# HG changeset patch # User Dan # Date 1201492660 18000 # Node ID c1c7fa6b329fa00d04db7eb66cdd003fb46501df # Parent bb3e6c3bd4f46a7a837fca56af3fd5bb07af776c Got Enano to load even if there are no plugins; added caching for decrypted session keys to significantly improve performance (in theory at least) diff -r bb3e6c3bd4f4 -r c1c7fa6b329f ajax.php --- 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": diff -r bb3e6c3bd4f4 -r c1c7fa6b329f includes/common.php --- 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'); diff -r bb3e6c3bd4f4 -r c1c7fa6b329f includes/functions.php --- 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; - } /** diff -r bb3e6c3bd4f4 -r c1c7fa6b329f includes/plugins.php --- 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); diff -r bb3e6c3bd4f4 -r c1c7fa6b329f includes/rijndael.php --- 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).'
'; @@ -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 '
'.print_r($dypt, true).'
'; @@ -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 - * 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, " diff -r bb3e6c3bd4f4 -r c1c7fa6b329f includes/sessions.php --- 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) { diff -r bb3e6c3bd4f4 -r c1c7fa6b329f index.php --- 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 diff -r bb3e6c3bd4f4 -r c1c7fa6b329f language/english/core.json --- 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: '

You are about to destroy this page.

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.

Are you absolutely sure that you want to continue?
You will not be asked again.

', + delete_err_need_reason: 'Please enter a reason for deleting this page.', delete_btn_submit: 'Delete this page', delete_lbl_reason: 'Reason for deleting:',