Fixed some stray version numbers (again!); added support for Diffie-Hellman logins in the normal login form (not AJAX) - even works in IE
authorDan
Tue, 18 Mar 2008 14:32:40 -0400
changeset 507 586fd7d3202d
parent 506 da0f2a76add5
child 508 459a447d7e79
Fixed some stray version numbers (again!); added support for Diffie-Hellman logins in the normal login form (not AJAX) - even works in IE
cron.php
includes/captcha.php
includes/captcha/engine_default.php
includes/captcha/engine_failsafe.php
includes/captcha/engine_potpourri.php
includes/clientside/jsres.php
includes/clientside/static/faders.js
includes/comment.php
includes/constants.php
includes/diffiehellman.php
includes/email.php
includes/functions.php
includes/http.php
includes/js-compressor.php
includes/lang.php
includes/math.php
includes/pageprocess.php
includes/paths.php
includes/plugins.php
includes/render.php
includes/search.php
includes/sessions.php
includes/stats.php
includes/tagcloud.php
includes/template.php
includes/wikiengine/Tables.php
plugins/SpecialUserFuncs.php
--- a/cron.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/cron.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/captcha.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/captcha.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
--- a/includes/captcha/engine_default.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/captcha/engine_default.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
--- a/includes/captcha/engine_failsafe.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/captcha/engine_failsafe.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
--- a/includes/captcha/engine_potpourri.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/captcha/engine_potpourri.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * captcha.php - visual confirmation system used during registration
  *
--- a/includes/clientside/jsres.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/clientside/jsres.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * jsres.php - the Enano client-side runtime, a.k.a. AJAX on steroids
  *
--- a/includes/clientside/static/faders.js	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/clientside/static/faders.js	Tue Mar 18 14:32:40 2008 -0400
@@ -487,3 +487,30 @@
     }
 }
 
+function whiteOutElement(el)
+{
+  var top = $(el).Top();
+  var left = $(el).Left();
+  var width = $(el).Width();
+  var height = $(el).Height();
+  
+  var blackout = document.createElement('div');
+  blackout.style.position = 'absolute';
+  blackout.style.top = top + 'px';
+  blackout.style.left = left + 'px';
+  blackout.style.width = width + 'px';
+  blackout.style.height = height + 'px';
+  
+  blackout.style.backgroundColor = '#FFFFFF';
+  domObjChangeOpac(60, blackout);
+  blackout.style.backgroundImage = 'url(' + scriptPath + '/includes/clientside/tinymce/themes/advanced/skins/default/img/progress.gif)';
+  blackout.style.backgroundPosition = 'center center';
+  blackout.style.backgroundRepeat = 'no-repeat';
+  blackout.style.zIndex = getHighestZ() + 2;
+  
+  var body = document.getElementsByTagName('body')[0];
+  body.appendChild(blackout);
+  
+  return blackout;
+}
+
--- a/includes/comment.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/comment.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/constants.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/constants.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * constants.php - important defines used Enano-wide
  *
@@ -104,10 +104,6 @@
 define('PROTECT_FULL', 1);
 define('PROTECT_SEMI', 2);
 
-// Special comments - plugin blocks
-define('PLUGIN_METABLOCK_LANGUAGE_START', '/**!language**');
-define('PLUGIN_METABLOCK_LANGUAGE_END', '**!*/');
-
 //
 // Enano versions progress
 //
--- a/includes/diffiehellman.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/diffiehellman.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * diffiehellman.php - Diffie Hellman key exchange and supporting functions
  *
@@ -17,7 +17,16 @@
  * The Diffie-Hellman key exchange protocol
  */
 
-$GLOBALS['_math'] = enanomath_create();
+global $dh_supported;
+$dh_supported = true;
+try
+{
+  $GLOBALS['_math'] = enanomath_create();
+}
+catch ( Exception $e )
+{
+  $dh_supported = false;
+}
 // Our prime number as a base for operations.
 $GLOBALS['dh_prime'] = '82818079787776757473727170696867666564636261605958575655545352515049484746454443424140393837363534333231302928272625242322212019181716151413121110987654321';
 
--- a/includes/email.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/email.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/functions.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/functions.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/http.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/http.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * class_http.php - Pure PHP HTTP client library
  *
--- a/includes/js-compressor.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/js-compressor.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * Javascript compression library - used to compact the client-side Javascript code (all 72KB of it!) to save some bandwidth
  *
--- a/includes/lang.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/lang.php	Tue Mar 18 14:32:40 2008 -0400
@@ -364,23 +364,13 @@
     if ( $this->lang_id == 0 )
       $db->_die('lang.php - BUG: trying to perform import when $lang->lang_id == 0');
     
-    $contents = trim(@file_get_contents($file));
-    
-    if ( empty($contents) )
-      $db->_die('lang.php - can\'t load the contents of the language file');
-    
-    // If there isn't a specially formed comment block, bail out quietly.
-    if ( !strpos($contents, PLUGIN_METABLOCK_LANGUAGE_START) || !strpos($contents, PLUGIN_METABLOCK_LANGUAGE_END) )
-      return null;
+    $block = pluginLoader::parse_plugin_blocks($file, 'language');
+    if ( !is_array($block) )
+      return false;
+    if ( !isset($block[0]) )
+      return false;
     
-    // Get all data in the language block
-    $block_start = strpos($contents, PLUGIN_METABLOCK_LANGUAGE_START) + strlen(PLUGIN_METABLOCK_LANGUAGE_START);
-    $block_end = strpos($contents, PLUGIN_METABLOCK_LANGUAGE_END);
-    $block_len = $block_end - $block_start;
-    if ( $block_len < 1 )
-      $db->_die('lang.php - plugin file contains corrupt language data');
-    
-    $contents = substr($contents, $block_start, $block_len);
+    $contents =& $block[0]['value'];
     
     // Trim off all text before and after the starting and ending braces
     $contents = preg_replace('/^([^{]+)\{/', '{', $contents);
--- a/includes/math.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/math.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * diffiehellman.php - Diffie Hellman key exchange and supporting functions
  *
--- a/includes/pageprocess.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/pageprocess.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * pageprocess.php - intelligent retrieval of pages
  * Copyright (C) 2006-2007 Dan Fuhry
  *
--- a/includes/paths.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/paths.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /**
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * paths.php - The part of Enano that actually manages content. Everything related to page handling and namespaces is in here.
  *
--- a/includes/plugins.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/plugins.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
@@ -172,6 +172,77 @@
   {
     return isset( $this->loaded_plugins[$plugid] );
   }
+  
+  /**
+   * Parses all special comment blocks in a plugin and returns an array in the format:
+   <code>
+   array(
+       0 => array(
+           'block' => 'upgrade',
+           // parsed from the block's parameters section
+             'release_from' => '1.0b1',
+             'release_to' => '1.0b2',
+           'value' => 'foo'
+         ),
+       1 => array(
+           ...
+         )
+     );
+   </code>
+   * @param string Path to plugin file
+   * @param string Optional. The type of block to fetch. If this is specified, only the block type specified will be read, all others will be discarded.
+   * @return array
+   */
+  
+  public static function parse_plugin_blocks($file, $type = false)
+  {
+    if ( !file_exists($file) )
+    {
+      return array();
+    }
+    $blocks = array();
+    $contents = @file_get_contents($file);
+    if ( empty($contents) )
+    {
+      return array();
+    }
+    
+    $regexp = '#^/\*\*!([a-z0-9_]+)'  // block header and type
+            . '(([\s]+[a-z0-9_]+[\s]*=[\s]*".+?"[\s]*;)*)' // parameters
+            . '[\s]*\*\*' . "\n"      // spacing and header close
+            . '([\w\W]+?)' . "\n"     // value
+            . '\*\*!\*/'              // closing comment
+            . '#m';
+            
+    // Match out all blocks
+    
+    $results = preg_match_all($regexp, $contents, $blocks);
+    
+    $return = array();
+    foreach ( $blocks[0] as $i => $_ )
+    {
+      if ( is_string($type) && $blocks[1][$i] !== $type )
+        continue;
+      
+      $el = self::parse_vars($blocks[2][$i]);
+      $el['block'] = $blocks[1][$i];
+      $el['value'] = $blocks[4][$i];
+      $return[] = $el;
+    }
+    
+    return $return;
+  }
+  
+  private static function parse_vars($var_block)
+  {
+    preg_match_all('/[\s]+([a-z0-9_]+)[\s]*=[\s]*"(.+?)";/', $var_block, $matches);
+    $return = array();
+    foreach ( $matches[0] as $i => $_ )
+    {
+      $return[ $matches[1][$i] ] = $matches[2][$i];
+    }
+    return $return;
+  }
 }
 
 ?>
--- a/includes/render.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/render.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * render.php - handles fetching pages and parsing them into HTML
  *
--- a/includes/search.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/search.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * search.php - algorithm used to search pages
  *
--- a/includes/sessions.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/sessions.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * sessions.php - everything related to security and user management
  *
@@ -864,20 +864,22 @@
       $duration  = ( $_ = getConfig('lockout_duration') ) ? intval($_) : 15;
       // convert to minutes
       $duration  = $duration * 60;
+      $policy = ( $x = getConfig('lockout_policy') && in_array(getConfig('lockout_policy'), array('lockout', 'disable', 'captcha')) ) ? getConfig('lockout_policy') : 'lockout';
       
-      // get the lockout status
       $timestamp_cutoff = time() - $duration;
       $ipaddr = $db->escape($_SERVER['REMOTE_ADDR']);
       $q = $this->sql('SELECT timestamp FROM '.table_prefix.'lockout WHERE timestamp > ' . $timestamp_cutoff . ' AND ipaddr = \'' . $ipaddr . '\' ORDER BY timestamp DESC;');
       $fails = $db->numrows();
       
-      $policy = ( $x = getConfig('lockout_policy') && in_array(getConfig('lockout_policy'), array('lockout', 'disable', 'captcha')) ) ? getConfig('lockout_policy') : 'lockout';
       $captcha_good = false;
       if ( $policy == 'captcha' && $captcha_hash && $captcha_code )
       {
         // policy is captcha -- check if it's correct, and if so, bypass lockout check
         $real_code = $this->get_captcha($captcha_hash);
-        $captcha_good = ( strtolower($real_code) === strtolower($captcha_code) );
+        if ( strtolower($real_code) === strtolower($captcha_code) )
+        {
+          $captcha_good = true;
+        }
       }
       if ( $policy != 'disable' && !$captcha_good )
       {
@@ -2926,38 +2928,86 @@
    * @param string The name of the field that contains the encryption key
    * @param string The name of the field that will contain the encrypted password
    * @param string The name of the field that handles MD5 challenge data
+   * @param string The name of the field that tells if the server supports DiffieHellman
+   * @param string The name of the field with the DiffieHellman public key
+   * @param string The name of the field that the client should populate with its public key
    * @return string
    */
    
-  function aes_javascript($form_name, $pw_field, $use_crypt, $crypt_key, $crypt_data, $challenge)
+  function aes_javascript($form_name, $pw_field, $use_crypt, $crypt_key, $crypt_data, $challenge, $dh_supported = false, $dh_pubkey = false, $dh_client_pubkey = false)
   {
     $code = '
       <script type="text/javascript">
-        disableJSONExts();
-          str = \'\';
-          for(i=0;i<keySizeInBits/4;i++) str+=\'0\';
-          var key = hexToByteArray(str);
-          var pt = hexToByteArray(str);
-          var ct = rijndaelEncrypt(pt, key, \'ECB\');
-          var ct = byteArrayToHex(ct);
-          switch(keySizeInBits)
-          {
-            case 128:
-              v = \'66e94bd4ef8a2c3b884cfa59ca342b2e\';
-              break;
-            case 192:
-              v = \'aae06992acbf52a3e8f4a96ec9300bd7aae06992acbf52a3e8f4a96ec9300bd7\';
-              break;
-            case 256:
-              v = \'dc95c078a2408989ad48a21492842087dc95c078a2408989ad48a21492842087\';
-              break;
-          }
-          var testpassed = ' . ( ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0') ? 'false; // CRYPTO-AUTH DISABLED ON USER REQUEST // ' : '' ) . '( ct == v && md5_vm_test() );
-          var frm = document.forms.'.$form_name.';
+          
           function runEncryption()
           {
+            var testpassed = ' . ( ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0') ? 'false; // CRYPTO-AUTH DISABLED ON USER REQUEST // ' : '' ) . '( aes_self_test() && md5_vm_test() );
             var frm = document.forms.'.$form_name.';
-            if(testpassed)
+            var use_diffiehellman = false;' . "\n";
+    if ( $dh_supported && $dh_pubkey )
+    {
+      $code .= <<<EOF
+            if ( frm.$dh_supported.value == 'true' )
+              use_diffiehellman = true;
+EOF;
+    }
+    $code .= '
+    
+            if ( frm[\'' . $dh_supported . '\'] )
+            {
+              frm[\'' . $dh_supported . '\'].value = ( use_diffiehellman ) ? "true" : "false";
+            }
+            
+            if ( testpassed && use_diffiehellman )
+            {
+              // try to blank out the table to prevent double submits and what have you
+              var el = frm.' . $pw_field . ';
+              while ( el.tagName != "BODY" && el.tagName != "TABLE" )
+              {
+                el = el.parentNode;
+              }
+              if ( el.tagName == "TABLE" )
+              {
+                whiteOutElement(el);
+              }
+              
+              frm.'.$use_crypt.'.value = \'yes_dh\';
+              
+              // Perform Diffie Hellman stuff
+              // console.info("DiffieHellman: started keygen process");
+              var dh_priv = dh_gen_private();
+              var dh_pub = dh_gen_public(dh_priv);
+              var secret = dh_gen_shared_secret(dh_priv, frm.' . $dh_pubkey . '.value);
+              // console.info("DiffieHellman: finished keygen process");
+              
+              // secret_hash is used to verify that the server guesses the correct secret
+              var secret_hash = hex_sha1(secret);
+              
+              // give the server our values
+              frm.' . $crypt_key . '.value = secret_hash;
+              frm.' . $dh_client_pubkey . '.value = dh_pub;
+              
+              // console.info("DiffieHellman: set public values");
+              
+              // crypt_key is the actual AES key
+              var crypt_key = (hex_sha256(secret)).substr(0, (keySizeInBits / 4));
+              
+              // Perform encryption
+              crypt_key = hexToByteArray(crypt_key);
+              var pass = frm.'.$pw_field.'.value;
+              pass = stringToByteArray(pass);
+              var cryptstring = rijndaelEncrypt(pass, crypt_key, \'ECB\');
+              if(!cryptstring)
+              {
+                return false;
+              }
+              cryptstring = byteArrayToHex(cryptstring);
+              // console.info("DiffieHellman: finished AES");
+              frm.'.$crypt_data.'.value = cryptstring;
+              frm.'.$pw_field.'.value = \'\';
+              // console.info("DiffieHellman: ready to submit");
+            }
+            else if ( testpassed && !use_diffiehellman )
             {
               frm.'.$use_crypt.'.value = \'yes\';
               var cryptkey = frm.'.$crypt_key.'.value;
--- a/includes/stats.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/stats.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  * stats.php - handles statistics for pages (disablable in the admin CP)
  *
--- a/includes/tagcloud.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/tagcloud.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/template.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/template.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/includes/wikiengine/Tables.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/includes/wikiengine/Tables.php	Tue Mar 18 14:32:40 2008 -0400
@@ -2,7 +2,7 @@
 
 /*
  * Enano - an open-source CMS capable of wiki functions, Drupal-like sidebar blocks, and everything in between
- * Version 1.1.2 (Caoineag alpha 2)
+ * Version 1.1.3 (Caoineag alpha 3)
  * Copyright (C) 2006-2007 Dan Fuhry
  *
  * This program is Free Software; you can redistribute and/or modify it under the terms of the GNU General Public License
--- a/plugins/SpecialUserFuncs.php	Mon Mar 17 09:47:19 2008 -0400
+++ b/plugins/SpecialUserFuncs.php	Tue Mar 18 14:32:40 2008 -0400
@@ -169,6 +169,7 @@
     }
     
     // 1.1.3: generate diffie hellman key
+    require_once( ENANO_ROOT . '/includes/diffiehellman.php' );
     global $dh_supported, $_math;
     
     $response['dh_supported'] = $dh_supported;
@@ -206,7 +207,7 @@
   if ( $level <= USER_LEVEL_MEMBER && $session->user_logged_in )
     $paths->main_page();
   $template->header();
-  echo '<form action="'.makeUrl($paths->nslist['Special'].'Login').'" method="post" name="loginform" onsubmit="runEncryption();">';
+  echo '<form action="'.makeUrl($paths->nslist['Special'].'Login').'" method="post" name="loginform" onsubmit="try{runEncryption();}catch(e){};">';
   $header = ( $level > USER_LEVEL_MEMBER ) ? $lang->get('user_login_message_short_elev') : $lang->get('user_login_message_short');
   if ( isset($_POST['login']) )
   {
@@ -226,11 +227,11 @@
         $errstring = $lang->get('user_err_invalid_credentials');
         if ( $__login_status['lockout_policy'] == 'lockout' )
         {
-          $errstring .= $lang->get('err_invalid_credentials_lockout', array('lockout_fails' => $__login_status['lockout_fails']));
+          $errstring .= $lang->get('err_invalid_credentials_lockout', array('fails' => $__login_status['lockout_fails']));
         }
         else if ( $__login_status['lockout_policy'] == 'captcha' )
         {
-          $errstring .= $lang->get('user_err_invalid_credentials_lockout_captcha', array('lockout_fails' => $__login_status['lockout_fails']));
+          $errstring .= $lang->get('user_err_invalid_credentials_lockout_captcha', array('fails' => $__login_status['lockout_fails']));
         }
         break;
       case 'backend_fail':
@@ -248,7 +249,7 @@
         
         $s = ( $time_rem == 1 ) ? '' : $lang->get('meta_plural');
         
-        $captcha_string = ( $__login_status['lockout_policy'] == 'captcha' ) ? $lang->get('err_locked_out_captcha_blurb') : '';
+        $captcha_string = ( $__login_status['lockout_policy'] == 'captcha' ) ? $lang->get('user_err_locked_out_captcha_blurb') : '';
         $errstring = $lang->get('user_err_locked_out', array('plural' => $s, 'captcha_blurb' => $captcha_string, 'time_rem' => $time_rem));
         
         break;
@@ -330,26 +331,35 @@
            <?php
          }
          ?>
-         <tr>
-           <td class="row3" colspan="3">
-             <?php
-             if ( $level <= USER_LEVEL_MEMBER && ( !isset($_GET['use_crypt']) || ( isset($_GET['use_crypt']) && $_GET['use_crypt']!='0' ) ) )
-             {
-               $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
-               $nocrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=0", true);
-               echo '<p><b>' . $lang->get('user_login_nocrypt_title') . '</b> ' . $lang->get('user_login_nocrypt_body', array('nocrypt_link' => $nocrypt_link)) . '</p>';
-               echo '<p>' . $lang->get('user_login_nocrypt_countrylist') . '</p>';
-             }
-             else if ( $level <= USER_LEVEL_MEMBER && ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0' ) )
-             {
-               $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
-               $usecrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=1", true);
-               echo '<p><b>' . $lang->get('user_login_usecrypt_title') . '</b> ' . $lang->get('user_login_usecrypt_body', array('usecrypt_link' => $usecrypt_link)) . '</p>';
-               echo '<p>' . $lang->get('user_login_usecrypt_countrylist') . '</p>';
-             }
-             ?>
-           </td>
-         </tr>
+         <?php
+         if ( $level <= USER_LEVEL_MEMBER && ( !isset($_GET['use_crypt']) || ( isset($_GET['use_crypt']) && $_GET['use_crypt']!='0' ) ) )
+         {
+           echo '<tr>
+             <td class="row3" colspan="3">';
+             
+           $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
+           $nocrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=0", true);
+           echo '<p><b>' . $lang->get('user_login_nocrypt_title') . '</b> ' . $lang->get('user_login_nocrypt_body', array('nocrypt_link' => $nocrypt_link)) . '</p>';
+           echo '<p>' . $lang->get('user_login_nocrypt_countrylist') . '</p>';
+           
+           echo '  </td>
+           </tr>';
+         }
+         else if ( $level <= USER_LEVEL_MEMBER && ( isset($_GET['use_crypt']) && $_GET['use_crypt']=='0' ) )
+         {
+           echo '<tr>
+             <td class="row3" colspan="3">';
+             
+           $returnpage_link = ( $return = $paths->getAllParams() ) ? '/' . $return : '';
+           $usecrypt_link = makeUrlNS('Special', "Login$returnpage_link", "level=$level&use_crypt=1", true);
+           echo '<p><b>' . $lang->get('user_login_usecrypt_title') . '</b> ' . $lang->get('user_login_usecrypt_body', array('usecrypt_link' => $usecrypt_link)) . '</p>';
+           echo '<p>' . $lang->get('user_login_usecrypt_countrylist') . '</p>';
+           
+           echo '  </td>
+           </tr>';
+         }
+         ?>
+         
          <tr>
            <th colspan="3" style="text-align: center" class="subhead"><input type="submit" name="login" value="Log in" tabindex="<?php echo ( $level <= USER_LEVEL_MEMBER ) ? '3' : '2'; ?>" /></th>
          </tr>
@@ -369,9 +379,35 @@
         document.forms.loginform.pass.focus();
       </script>
       <?php endif; ?>
+      <?php
+      // 1.1.4
+      
+      require_once( ENANO_ROOT . '/includes/diffiehellman.php' );
+      
+      global $dh_supported, $_math;
+      if ( $dh_supported )
+      {
+        $dh_key_priv = dh_gen_private();
+        $dh_key_pub = dh_gen_public($dh_key_priv);
+        $dh_key_priv = $_math->str($dh_key_priv);
+        $dh_key_pub = $_math->str($dh_key_pub);
+        // store the keys in the DB
+        $q = $db->sql_query('INSERT INTO ' . table_prefix . "diffiehellman( public_key, private_key ) VALUES ( '$dh_key_pub', '$dh_key_priv' );");
+        if ( !$q )
+          $db->_die();
+        
+        echo "<input type=\"hidden\" name=\"dh_supported\" value=\"true\" />
+              <input type=\"hidden\" name=\"dh_public_key\" value=\"$dh_key_pub\" />
+              <input type=\"hidden\" name=\"dh_client_public_key\" value=\"\" />";
+      }
+      else
+      {
+        echo "<input type=\"hidden\" name=\"dh_supported\" value=\"false\" />";
+      }
+      ?>
     </form>
     <?php
-      echo $session->aes_javascript('loginform', 'pass', 'use_crypt', 'crypt_key', 'crypt_data', 'challenge_data');
+      echo $session->aes_javascript('loginform', 'pass', 'use_crypt', 'crypt_key', 'crypt_data', 'challenge_data', 'dh_supported', 'dh_public_key', 'dh_client_public_key');
     ?>
   <?php
   $template->footer();
@@ -407,103 +443,74 @@
   }
   if ( isset($_GET['act']) && $_GET['act'] == 'ajaxlogin' )
   {
-    $plugins->attachHook('login_password_reset', 'SpecialLogin_SendResponse_PasswordReset($row[\'user_id\'], $row[\'temp_password\']);');
-    $data = enano_json_decode($_POST['params']);
-    $captcha_hash = ( isset($data['captcha_hash']) ) ? $data['captcha_hash'] : false;
-    $captcha_code = ( isset($data['captcha_code']) ) ? $data['captcha_code'] : false;
-    $level = ( isset($data['level']) ) ? intval($data['level']) : USER_LEVEL_MEMBER;
-    
-    // 1.1.3: Diffie Hellman
-    global $dh_supported;
-    global $_math;
-    if ( $data['diffiehellman'] && isset($data['publickey_client']) && isset($data['publickey_server']) && isset($data['crypt_key_check']) )
+    die('This version of the Enano LoginAPI is deprecated. Please use the action.json method instead.');
+    $db->close();
+    exit;
+  }
+  if(isset($_POST['login']))
+  {
+    $captcha_hash = ( isset($_POST['captcha_hash']) ) ? $_POST['captcha_hash'] : false;
+    $captcha_code = ( isset($_POST['captcha_code']) ) ? $_POST['captcha_code'] : false;
+    if ( $_POST['use_crypt'] == 'yes' )
     {
+      $result = $session->login_with_crypto($_POST['username'], $_POST['crypt_data'], $_POST['crypt_key'], $_POST['challenge_data'], intval($_POST['auth_level']), $captcha_hash, $captcha_code);
+    }
+    else if ( $_POST['use_crypt'] == 'yes_dh' )
+    {
+      // retrieve and decrypt the password using DiffieHellman
+      
+      require_once( ENANO_ROOT . '/includes/diffiehellman.php' );
+      global $dh_supported, $_math;
+      
       if ( !$dh_supported )
       {
-        die('Special:Login: Illegal request for Diffie Hellman exchange');
+        die_semicritical('DiffieHellman error', 'Server does not support DiffieHellman, denying logon request');
       }
-      // retrieve our public key
-      if ( !preg_match('/^[0-9]+$/', $data['publickey_server']) )
+      
+      // Fetch private key
+      $dh_public = $_POST['dh_public_key'];
+      if ( !preg_match('/^[0-9]+$/', $dh_public) )
       {
-        die('Special:Login: Illegal request for Diffie Hellman exchange');
+        die_semicritical('DiffieHellman error', 'Public key not integer: ' . $dh_public);
       }
-      $pubkey_server =& $data['publickey_server'];
-      
-      // retrieve our private key
-      $q = $db->sql_query('SELECT private_key, key_id FROM ' . table_prefix . "diffiehellman WHERE public_key = '$pubkey_server';");
+      $q = $db->sql_query('SELECT private_key, key_id FROM ' . table_prefix . "diffiehellman WHERE public_key = '$dh_public';");
       if ( !$q )
         $db->die_json();
       
       if ( $db->numrows() < 1 )
       {
-        die('Special:Login: Couldn\'t lookup Diffie Hellman key: ' . $pubkey_server);
+        die_semicritical('DiffieHellman error', 'ERR_DH_KEY_NOT_FOUND');
       }
-      list($privkey_server, $key_id) = $db->fetchrow_num();
+      
+      list($dh_private, $dh_key_id) = $db->fetchrow_num();
       $db->free_result();
       
-      // get shared secret
-      $dh_secret = dh_gen_shared_secret($privkey_server, $data['publickey_client']);
+      // We have the private key, now delete the key pair, we no longer need it
+      $q = $db->sql_query('DELETE FROM ' . table_prefix . "diffiehellman WHERE key_id = $dh_key_id;");
+      if ( !$q )
+        $db->die_json();
+      
+      // Generate the shared secret
+      $dh_secret = dh_gen_shared_secret($dh_private, $_POST['dh_client_public_key']);
       $dh_secret = $_math->str($dh_secret);
-      $secret_check = sha1($dh_secret);
-      if ( $secret_check !== $data['crypt_key_check'] )
+      
+      // Did we get all our math right?
+      $dh_secret_check = sha1($dh_secret);
+      $dh_hash = $_POST['crypt_key'];
+      if ( $dh_secret_check !== $dh_hash )
       {
-        die(enano_json_encode(array(
-            'mode' => 'error',
-            'error' => 'Diffie Hellman redundancy check failed, couldn\'t rebuild the AES key.',
-            'debug' => array(
-              'server private key' => $privkey_server,
-              'client public key' => $data['publickey_client'],
-              'expected sha1' => $data['crypt_key_check'],
-              'actual sha1' => $secret_check
-              )
-          )));
+        die_semicritical('DiffieHellman error', 'ERR_DH_HASH_NO_MATCH');
       }
-      // we have the secret, now get the sha256 hash
-      $crypt_key = substr(sha256($dh_secret), 0, ( AES_BITS / 4 ));
-    }
-    else if ( !$data['diffiehellman'] && isset($data['crypt_key']) && isset($data['crypt_data']) )
-    {
-      $crypt_key = $data['crypt_key'];
-    }
-    else
-    {
-      die('Special:Login: Illegal request');
-    }
-    
-    $result = $session->login_with_crypto($data['username'], $data['crypt_data'], $crypt_key, $data['challenge'], $level, $captcha_hash, $captcha_code, !$dh_supported);
-    
-    if ( $result['success'] )
-    {
-      $response = Array(
-          'result' => 'success',
-          'key' => $session->sid_super // ( ( $session->sid_super ) ? $session->sid_super : $session->sid )
-        );
-    }
-    else
-    {
-      $captcha = '';
-      if ( $result['error'] == 'locked_out' && $result['lockout_policy'] == 'captcha' )
-      {
-        $session->kill_captcha();
-        $captcha = $session->make_captcha();
-      }
-      $response = Array(
-          'result' => 'error',
-          'data' => $result,
-          'captcha' => $captcha
-        );
-    }
-    $response = enano_json_encode($response);
-    echo $response;
-    $db->close();
-    exit;
-  }
-  if(isset($_POST['login'])) {
-    $captcha_hash = ( isset($_POST['captcha_hash']) ) ? $_POST['captcha_hash'] : false;
-    $captcha_code = ( isset($_POST['captcha_code']) ) ? $_POST['captcha_code'] : false;
-    if($_POST['use_crypt'] == 'yes')
-    {
-      $result = $session->login_with_crypto($_POST['username'], $_POST['crypt_data'], $_POST['crypt_key'], $_POST['challenge_data'], intval($_POST['auth_level']), $captcha_hash, $captcha_code);
+      
+      // All good! Generate the AES key
+      $aes_key = substr(sha256($dh_secret), 0, ( AES_BITS / 4 ));
+      
+      // decrypt user info
+      $aes_key = hexdecode($aes_key);
+      $aes = AESCrypt::singleton(AES_BITS, AES_BLOCKSIZE);
+      $password = $aes->decrypt($_POST['crypt_data'], $aes_key, ENC_HEX);
+      
+      $result = $session->login_without_crypto($_POST['username'], $password, false, intval($_POST['auth_level']), $captcha_hash, $captcha_code);
     }
     else
     {