Got Enano to load even if there are no plugins; added caching for decrypted session keys to significantly improve performance (in theory at least)
authorDan
Sun, 27 Jan 2008 22:57:40 -0500
changeset 378 c1c7fa6b329f
parent 377 bb3e6c3bd4f4
child 379 82b991bee797
Got Enano to load even if there are no plugins; added caching for decrypted session keys to significantly improve performance (in theory at least)
ajax.php
includes/common.php
includes/functions.php
includes/plugins.php
includes/rijndael.php
includes/sessions.php
index.php
language/english/core.json
--- a/ajax.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/ajax.php	Sun Jan 27 22:57:40 2008 -0500
@@ -291,7 +291,7 @@
     case "deletepage":
       $reason = ( isset($_POST['reason']) ) ? $_POST['reason'] : false;
       if ( empty($reason) )
-        die('Please enter a reason for deleting this page.');
+        die($lang->get('page_err_need_reason'));
       echo PageUtils::deletepage($paths->page_id, $paths->namespace, $reason);
       break;
     case "delvote":
--- a/includes/common.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/includes/common.php	Sun Jan 27 22:57:40 2008 -0500
@@ -283,7 +283,8 @@
 // Load plugins from common because we can't give plugins full abilities in object context
 foreach ( $plugins->load_list as $f )
 {
-  include_once $f;
+  if ( file_exists($f) )
+    include_once $f;
 }
 
 profiler_log('Loaded plugins');
--- a/includes/functions.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/includes/functions.php	Sun Jan 27 22:57:40 2008 -0500
@@ -1910,7 +1910,6 @@
   }
 
   return $html;
-
 }
 
 /**
--- a/includes/plugins.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/includes/plugins.php	Sun Jan 27 22:57:40 2008 -0500
@@ -39,7 +39,9 @@
             {
               $this->load_list[] = $dir . $file;
               $plugid = substr($file, 0, strlen($file)-4);
-              $f = file_get_contents($dir . $file);
+              $f = @file_get_contents($dir . $file);
+              if ( empty($f) )
+                continue;
               $f = explode("\n", $f);
               $f = array_slice($f, 2, 7);
               $f[0] = substr($f[0], 13);
--- a/includes/rijndael.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/includes/rijndael.php	Sun Jan 27 22:57:40 2008 -0500
@@ -128,7 +128,7 @@
   
   public static function singleton($key_size, $block_size)
   {
-    global $_aes_objcache;
+    static $_aes_objcache;
     if ( isset($_aes_objcache["$key_size,$block_size"]) )
     {
       return $_aes_objcache["$key_size,$block_size"];
@@ -779,7 +779,9 @@
     {
       $key = $this->prepare_string($key);
       $text = $this->prepare_string($text);
+      profiler_log('AES: Started encryption of a string');
       $cryptext = $this->rijndaelEncrypt($text, $key, 'ECB');
+      profiler_log('AES: Finished encryption of a string');
       if(!is_array($cryptext))
       {
         echo 'Warning: encryption failed for string: '.print_r($text,true).'<br />';
@@ -814,14 +816,7 @@
   {
     if ( $text == '' )
       return '';
-    $text_orig = $text;
-    if ( isset($this->decrypt_cache[$key]) && is_array($this->decrypt_cache[$key]) )
-    {
-      if ( isset($this->decrypt_cache[$key][$text]) )
-      {
-        return $this->decrypt_cache[$key][$text];
-      }
-    }
+    
     switch($input_encoding)
     {
       case ENC_BINARY:
@@ -834,9 +829,24 @@
         $text = base64_decode($text);
         break;
     }
-    //$mod = strlen($text) % $this->blockSizeInBits;
-    //if($mod != 96)
-      //die('modulus check failed: '.$mod);
+    
+    // Run memory-cache check
+    if ( isset($this->decrypt_cache[$key]) && is_array($this->decrypt_cache[$key]) )
+    {
+      if ( isset($this->decrypt_cache[$key][$text]) )
+      {
+        return $this->decrypt_cache[$key][$text];
+      }
+    }
+    
+    // Run disk-cache check
+    $hash = sha1($text . '::' . $key);
+    if ( $dypt = aes_decrypt_cache_fetch($hash) )
+      return $dypt;
+    
+    $text_bin = $text;
+    $key_bin = $key;
+    
     if ( $this->mcrypt )
     {
       $iv_size = mcrypt_get_iv_size($this->mcrypt, MCRYPT_MODE_ECB);
@@ -848,7 +858,9 @@
       $etext = $this->prepare_string($text);
       $ekey  = $this->prepare_string($key);
       $mod = count($etext) % $this->blockSizeInBits;
+      profiler_log('AES: Started decryption of a string');
       $dypt = $this->rijndaelDecrypt($etext, $ekey, 'ECB');
+      profiler_log('AES: Finished decryption of a string');
       if(!$dypt)
       {
         echo '<pre>'.print_r($dypt, true).'</pre>';
@@ -856,10 +868,12 @@
       }
       $dypt = $this->byteArrayToString($dypt);
     }
-    if ( !isset($this->decrypt_cache[$key]) )
-      $this->decrypt_cache[$key] = array();
+    if ( !isset($this->decrypt_cache[$key_bin]) )
+      $this->decrypt_cache[$key_bin] = array();
     
-    $this->decrypt_cache[$key][$text_orig] = $dypt;
+    $this->decrypt_cache[$key_bin][$text_bin] = $dypt;
+    
+    aes_decrypt_cache_store($text_bin, $dypt, $key_bin);
     
     return $dypt;
   }
@@ -977,118 +991,96 @@
   }
 }
 
-/**
- * XXTEA encryption arithmetic library.
- *
- * Copyright (C) 2006 Ma Bingyao <andot@ujn.edu.cn>
- * Version:      1.5
- * LastModified: Dec 5, 2006
- * This library is free.  You can redistribute it and/or modify it.
- * 
- * From dandaman32: I am treating this code as GPL, as implied by the license statement above.
- */
-class TEACrypt extends AESCrypt {
-  function long2str($v, $w) {
-      $len = count($v);
-      $n = ($len - 1) << 2;
-      if ($w) {
-          $m = $v[$len - 1];
-          if (($m < $n - 3) || ($m > $n)) return false;
-          $n = $m;
-      }
-      $s = array();
-      for ($i = 0; $i < $len; $i++) {
-          $s[$i] = pack("V", $v[$i]);
-      }
-      if ($w) {
-          return substr(join('', $s), 0, $n);
-      }
-      else {
-          return join('', $s);
-      }
+function aes_decrypt_cache_store($encrypted, $decrypted, $key)
+{
+  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
+  // only cache if $decrypted is long enough to actually warrant caching
+  if ( strlen($decrypted) < 32 )
+  {
+    profiler_log("AES: Skipped caching a string (probably a password, we dunno) because it's too short");
+    return false;
   }
-   
-  function str2long($s, $w) {
-      $v = unpack("V*", $s. str_repeat("\0", (4 - strlen($s) % 4) & 3));
-      $v = array_values($v);
-      if ($w) {
-          $v[count($v)] = strlen($s);
-      }
-      return $v;
-  }
-   
-  function int32($n) {
-      while ($n >= 2147483648) $n -= 4294967296;
-      while ($n <= -2147483649) $n += 4294967296;
-      return (int)$n;
-  }
-   
-  function encrypt($str, $key, $return_encoding = ENC_HEX) {
-      if ($str == "")
+  if ( file_exists($cache_file) )
+  {
+    require_once($cache_file);
+    global $aes_decrypt_cache;
+    $cachekey = sha1($encrypted . '::' . $key);
+    $aes_decrypt_cache[$cachekey] = $decrypted;
+    
+    if ( count($aes_decrypt_cache) > 5000 )
+    {
+      // we've got a lot of strings in the cache, clear out a few
+      $keys = array_keys($aes_decrypt_cache);
+      for ( $i = 0; $i < 2500; $i++ )
       {
-          return "";
+        unset($aes_decrypt_cache[$keys[$i]]);
+        unset($aes_decrypt_cache[$keys[$i]]);
       }
-      $v = $this->str2long($str, true);
-      $k = $this->str2long($key, false);
-      if (count($k) < 4) {
-          for ($i = count($k); $i < 4; $i++) {
-              $k[$i] = 0;
-          }
-      }
-      $n = count($v) - 1;
-   
-      $z = $v[$n];
-      $y = $v[0];
-      $delta = 0x9E3779B9;
-      $q = floor(6 + 52 / ($n + 1));
-      $sum = 0;
-      while (0 < $q--) {
-          $sum = $this->int32($sum + $delta);
-          $e = $sum >> 2 & 3;
-          for ($p = 0; $p < $n; $p++) {
-              $y = $v[$p + 1];
-              $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
-              $z = $v[$p] = $this->int32($v[$p] + $mx);
-          }
-          $y = $v[0];
-          $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
-          $z = $v[$n] = $this->int32($v[$n] + $mx);
-      }
-      return $this->long2str($v, false);
+    }
+  }
+  else
+  {
+    $aes_decrypt_cache = array(
+      sha1($encrypted . '::' . $key) => $decrypted
+    );
   }
-   
-  function decrypt($str, $key, $encoding = ENC_HEX) {
-      if ($str == "") {
-          return "";
-      }
-      $v = $this->str2long($str, false);
-      $k = $this->str2long($key, false);
-      if (count($k) < 4) {
-          for ($i = count($k); $i < 4; $i++) {
-              $k[$i] = 0;
-          }
-      }
-      $n = count($v) - 1;
-   
-      $z = $v[$n];
-      $y = $v[0];
-      $delta = 0x9E3779B9;
-      $q = floor(6 + 52 / ($n + 1));
-      $sum = $this->int32($q * $delta);
-      while ($sum != 0) {
-          $e = $sum >> 2 & 3;
-          for ($p = $n; $p > 0; $p--) {
-              $z = $v[$p - 1];
-              $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
-              $y = $v[$p] = $this->int32($v[$p] - $mx);
-          }
-          $z = $v[$n];
-          $mx = $this->int32((($z >> 5 & 0x07ffffff) ^ $y << 2) + (($y >> 3 & 0x1fffffff) ^ $z << 4)) ^ $this->int32(($sum ^ $y) + ($k[$p & 3 ^ $e] ^ $z));
-          $y = $v[0] = $this->int32($v[0] - $mx);
-          $sum = $this->int32($sum - $delta);
-      }
-      return $this->long2str($v, true);
+  // call var_export and collect contents
+  ob_start();
+  var_export($aes_decrypt_cache);
+  $dec_cache_string = ob_get_contents();
+  ob_end_clean();
+  $f = @fopen($cache_file, 'w');
+  if ( !$f )
+    return false;
+  fwrite($f, "<?php
+\$GLOBALS['aes_decrypt_cache'] = $dec_cache_string;
+");
+  fclose($f);
+  return true;
+}
+
+function aes_decrypt_cache_fetch($hash)
+{
+  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
+  if ( !file_exists($cache_file) )
+    return false;
+  
+  require_once($cache_file);
+  global $aes_decrypt_cache;
+  if ( isset($aes_decrypt_cache[$hash]) )
+  {
+    profiler_log("AES: Loaded cached decrypted string, hash is $hash");
+    return $aes_decrypt_cache[$hash];
   }
+  
+  return false;
+}
+
+function aes_decrypt_cache_destroy($hash)
+{
+  $cache_file = ENANO_ROOT . '/cache/aes_decrypt.php';
+  if ( !file_exists($cache_file) )
+    return false;
+  
+  require_once($cache_file);
+  global $aes_decrypt_cache;
+  
+  if ( isset($aes_decrypt_cache[$hash]) )
+    unset($aes_decrypt_cache[$hash]);
+  
+  // call var_export and collect contents
+  ob_start();
+  var_export($aes_decrypt_cache);
+  $dec_cache_string = ob_get_contents();
+  ob_end_clean();
+  $f = @fopen($cache_file, 'w');
+  if ( !$f )
+    return false;
+  fwrite($f, "<?php
+\$GLOBALS['aes_decrypt_cache'] = $dec_cache_string;
+");
+  fclose($f);
+  return true;
 }
 
 ?>
--- a/includes/sessions.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/includes/sessions.php	Sun Jan 27 22:57:40 2008 -0500
@@ -13,9 +13,6 @@
  * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for details.
  */
  
-// Prepare a string for insertion into a MySQL database
-function filter($str) { global $db; return $db->escape($str); }
-
 /**
  * Anything and everything related to security and user management. This includes AES encryption, which is illegal in some countries.
  * Documenting the API was not easy - I hope you folks enjoy it.
@@ -1183,7 +1180,8 @@
   function validate_session($key)
   {
     global $db, $session, $paths, $template, $plugins; // Common objects
-    $aes = new AESCrypt(AES_BITS, AES_BLOCKSIZE, true);
+    profiler_log("SessionManager: checking session: " . sha1($key));
+    $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
     $decrypted_key = $aes->decrypt($key, $this->private_key, ENC_HEX);
     
     if ( !$decrypted_key )
@@ -1284,6 +1282,9 @@
     // Leave the rest to PHP's automatic garbage collector ;-)
     
     $row['password'] = md5($real_pass);
+    
+    profiler_log("SessionManager: finished session check");
+    
     return $row;
   }
   
@@ -1360,10 +1361,14 @@
     if($level > USER_LEVEL_CHPREF)
     {
       $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
-      if(!$this->user_logged_in || $this->auth_level < USER_LEVEL_MOD)
+      if(!$this->user_logged_in || $this->auth_level < ( USER_LEVEL_MEMBER + 1))
       {
         return 'success';
       }
+      // See if we can get rid of the cached decrypted session key
+      $key_bin = $aes->hextostring(strrev($this->sid_super));
+      $key_hash = sha1($key_bin . '::' . $this->private_key);
+      aes_decrypt_cache_destroy($key_hash);
       // Destroy elevated privileges
       $keyhash = md5(strrev($this->sid_super));
       $this->sql('DELETE FROM '.table_prefix.'session_keys WHERE session_key=\''.$keyhash.'\' AND user_id=\'' . $this->user_id . '\';');
@@ -1374,6 +1379,11 @@
     {
       if($this->user_logged_in)
       {
+        $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
+        // See if we can get rid of the cached decrypted session key
+        $key_bin = $aes->hextostring($this->sid);
+        $key_hash = sha1($key_bin . '::' . $this->private_key);
+        aes_decrypt_cache_destroy($key_hash);
         // Completely destroy our session
         if($this->auth_level > USER_LEVEL_CHPREF)
         {
--- a/index.php	Sat Jan 26 15:42:32 2008 -0500
+++ b/index.php	Sun Jan 27 22:57:40 2008 -0500
@@ -19,7 +19,7 @@
   define('ENANO_INTERFACE_INDEX', '');
   
   // For the mighty and brave.
-  // define('ENANO_DEBUG', '');
+  define('ENANO_DEBUG', '');
  
   // Set up gzip encoding before any output is sent
   
--- a/language/english/core.json	Sat Jan 26 15:42:32 2008 -0500
+++ b/language/english/core.json	Sun Jan 27 22:57:40 2008 -0500
@@ -76,6 +76,7 @@
       delvote_reset_btn_submit: 'Reset votes',
       
       delete_warning_stern: '<h3>You are about to <span style="color: red;">destroy</span> this page.</h3><p>While the deletion of the page itself is completely reversible, it is impossible to recover any comments or category information on this page. If this is a file page, the file along with all older revisions of it will be permanently deleted. Also, any custom information that this page is tagged with, such as a custom name, protection status, or additional settings such as whether to allow comments, will be permanently lost.</p><p>Are you <u>absolutely sure</u> that you want to continue?<br />You will not be asked again.</p>',
+      delete_err_need_reason: 'Please enter a reason for deleting this page.',
       delete_btn_submit: 'Delete this page',
       delete_lbl_reason: 'Reason for deleting:',