Skizzerz has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/101813


Change subject: Major rewrite of SecurePasswords
......................................................................

Major rewrite of SecurePasswords

This is version 3.0beta1, the first of (many) betas before the final 3.0 
release.
Additional features will be added in subsequent betas. Please see the extension 
page
on www.mediawiki.org for more information and a roadmap.

Change-Id: I5103c081e2725242be99f42451a0bec890c15f9b
---
M .gitignore
M .gitreview
A ExtSecurePasswords.php
M SecurePasswords.php
A password_history.sql
D securepasswords.sql
A securepasswords_uninstall.sql
A user.patch.user_newpassword.sql
A user.patch.user_password.sql
9 files changed, 657 insertions(+), 374 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/SecurePasswords 
refs/changes/13/101813/1

diff --git a/.gitignore b/.gitignore
index 98b092a..6afb988 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,4 @@
-.svn
-*~
-*.kate-swp
-.*.swp
+.svn
+*~
+*.kate-swp
+.*.swp
diff --git a/.gitreview b/.gitreview
index ae1ac79..92a3648 100644
--- a/.gitreview
+++ b/.gitreview
@@ -1,6 +1,6 @@
-[gerrit]
-host=gerrit.wikimedia.org
-port=29418
-project=mediawiki/extensions/SecurePasswords.git
-defaultbranch=master
+[gerrit]
+host=gerrit.wikimedia.org
+port=29418
+project=mediawiki/extensions/SecurePasswords.git
+defaultbranch=master
 defaultrebase=0
\ No newline at end of file
diff --git a/ExtSecurePasswords.php b/ExtSecurePasswords.php
new file mode 100644
index 0000000..eea6f70
--- /dev/null
+++ b/ExtSecurePasswords.php
@@ -0,0 +1,499 @@
+<?php
+/**
+ * ExtSecurePasswords class
+ * Supports SecurePasswords version 3, as well as backwards compatibility with 
versions 1 and 2
+ * See http://www.mediawiki.org/wiki/Extension:SecurePasswords for details
+ * Code is released under the GNU GPL version 2 or (at your discretion) any 
later version
+ */
+if ( !defined( 'MEDIAWIKI' ) ) {
+       echo "Not an entry point!\n";
+       die( 1 );
+}
+
+class ExtSecurePasswords {
+       public static function LoadExtensionSchemaUpdates( DatabaseUpdater 
$updater ) {
+               $dir = dirname( __FILE__ );
+               $updater->addExtensionUpdate( array( 'modifyField', 'user', 
'user_password', $dir . '/user.patch.user_password.sql', true ) );
+               $updater->addExtensionUpdate( array( 'modifyField', 'user', 
'user_newpassword', $dir . '/user.patch.user_newpassword.sql', true ) );
+               $updater->addExtensionTable( 'password_history', $dir . 
'/password_history.sql', true );
+               $updater->addExtensionTable( 'securepasswords_uninstall', $dir 
. '/securepasswords_uninstall.sql', true );
+               return true;
+       }
+
+       public static function UserCryptPassword( $password, &$salt, 
$wgPasswordSalt, &$hash ) {
+               global $wgSecurePasswordsRounds, $wgSecurePasswordsAutoRounds, 
$wgSecurePasswordsAutoRoundsThreshold;
+               global $wgSecurePasswordsEncryptPasswords, 
$wgSecurePasswordsSecretKey, $wgSecurePasswordsUninstall;
+               global $wgSecurePasswordsTrialMode, $wgUser;
+
+               static $recursionGuard = false;
+
+               if ( $wgSecurePasswordsUninstall || $recursionGuard ) {
+                       // do not generate new SecurePasswords hashes if we are 
uninstalling
+                       // or if we're re-entering this function due to calling 
User::crypt()
+                       return true;
+               }
+
+               $salt = substr( str_replace( '+', '.', base64_encode( 
MWCryptRand::generate( 16, true ) ) ), 0, 22 );
+               $hash = 'S3:';
+               $rounds = $wgSecurePasswordsRounds;
+               $user = RequestContext::getMain()->getUser();
+
+               if ( $wgSecurePasswordsAutoRounds ) {
+                       while ( true ) {
+                               $str = '$2y$' . $rounds . '$' . $salt;
+                               $start = microtime( true );
+                               crypt( 'benchmarkingpassword', $str );
+                               $end = microtime( true );
+
+                               if ( $end - $start >= 
$wgSecurePasswordsAutoRoundsThreshold || $rounds == 31 ) {
+                                       break;
+                               }
+
+                               $rounds++;
+                       }
+               }
+
+               $saltstr = '$2y$' . $rounds . '$' . $salt;
+               $hashstr = substr( crypt( $password, $saltstr ), strlen( '$2y$' 
. $rounds . '$' ) );
+
+               // generate hash options
+               $hashstr = 'G' . time() . ':R' . $rounds . ':H' . $hashstr;
+
+               if ( $wgSecurePasswordsEncryptPasswords ) {
+                       $iv = MWCryptRand::generate( 16, true );
+                       $hash .= 'E' . base64_encode( $iv ) . ':' . 
self::encrypt( $hashstr, $wgSecurePasswordsSecretKey, $iv );
+               } else {
+                       $hash .= $hashstr;
+               }
+
+               if ( $wgSecurePasswordsTrialMode ) {
+                       // stash away the default mediawiki hash for easier 
uninstallation
+                       $recursionGuard = true;
+                       // User::crypt() calls the UserCryptPassword hook, 
hence recursion guards
+                       $defaultHash = User::crypt( $password );
+                       $recursionGuard = false;
+
+                       $dbw = wfGetDB( DB_MASTER );
+                       $exists = $dbw->selectField( 
'securepasswords_uninstall', '1', array( 'su_user' => $wgUser->getId() ), 
'ExtSecurePasswords::UserCryptPassword' );
+                       if ( $exists ) {
+                               $dbw->update( 'securepasswords_uninstall', 
array( 'su_password' => $defaultHash ), array( 'su_user' => $wgUser->getId() ), 
'ExtSecurePasswords::UserCryptPassword' );
+                       } else {
+                               $dbw->insert( 'securepasswords_uninstall', 
array( 'su_user' => $wgUser->getId(), 'su_password' => $defaultHash ), 
'ExtSecurePasswords::UserCryptPassword' );
+                       }
+               }
+
+               // use our hash instead of mediawiki default
+               return false;
+       }
+
+       public static function UserComparePasswords( $hash, $password, $userId, 
&$result ) {
+               $bits = explode( ':', $hash, 2 );
+
+               switch ( $bits[0] ) {
+                       // the self::compareX functions modify $result 
accordingly
+                       case 'SP': // SecurePasswords v1
+                               self::compare1( $hash, $password, $userId, 
$result );
+                               break;
+                       case 'S2': // SecurePasswords v2
+                               self::compare2( $hash, $password, $userId, 
$result );
+                               break;
+                       case 'S3': // SecurePasswords v3
+                               self::compare3( $hash, $password, $userId, 
$result );
+                               break;
+                       default: // something else, pass off to MW to handle
+                               return true;
+               }
+
+               return false;
+       }
+
+       public static function isValidPassword( $password, &$result, $user ) {
+               global $wgValidPasswords, $wgSecurePasswordsSpecialChars, 
$wgSecurePasswordsAdditionalDictionary, $wgSecurePasswordsUninstall;
+               global $wgLang, $wgContLang;
+
+               if ( $wgSecurePasswordsUninstall ) {
+                       return true; // do not generate new SecurePasswords 
hashes if we are uninstalling
+               }
+
+               // if the password matches the user's current password, then 
don't check for validity
+               // this way users with passwords that don't fit the criteria 
can still log in :)
+               if ( ( $id = $user->getId() ) !== 0 ) {
+                       $dbr = wfGetDB( DB_SLAVE );
+                       $hash = $dbr->selectField( 'user', 'user_password', 
'user_id=' . $id );
+                       if ( User::comparePasswords( $hash, $password, $id ) ) {
+                               $result = true;
+                               return false;
+                       }
+               }
+
+               $ok = true;
+
+               $lang = $wgContLang->getPreferredVariant( false );
+               // check password length
+               if ( strlen( $password ) < $wgValidPasswords['minlength'] ) {
+                       $ok = false;
+               }
+
+               // check for a lowercase letter, if needed
+               if ( $wgValidPasswords['lowercase'] && !preg_match( '/[a-z]/', 
$password ) ) {
+                       $ok = false;
+               }
+
+               // check for an uppercase letter, if needed
+               if ( $wgValidPasswords['uppercase'] && !preg_match( '/[A-Z]/', 
$password ) ) {
+                       $ok = false;
+               }
+
+               // check for a digit, if needed
+               if ( $wgValidPasswords['digit'] && !preg_match( '/[0-9]/', 
$password ) ) {
+                       $ok = false;
+               }
+
+               // check for a special character, if needed
+               if ( $wgValidPasswords['special'] && !preg_match( '/[' . 
$wgSecurePasswordsSpecialChars . ']/', $password ) ) {
+                       $ok = false;
+               }
+
+               // check for the username, if needed
+               if ( $wgValidPasswords['usercheck'] && $wgContLang->lc( 
$password ) == $wgContLang->lc( $user->getName() ) ) {
+                       $ok = false;
+               }
+
+               // check for words, if needed. If the password is already bad, 
skip this since it could take up time
+               if ( $ok && $wgValidPasswords['wordcheck'] ) {
+                       if ( function_exists( 'pspell_check' ) ) {
+                               $config = pspell_config_create( $lang );
+                               pspell_config_runtogether( $config, true );
+                               if ( $wgSecurePasswordsAdditionalDictionary ) {
+                                       pspell_config_personal( $config, 
$wgSecurePasswordsAdditionalDictionary );
+                               }
+                               $link = pspell_new_config( $config );
+
+                               if ( $link ) {
+                                       if ( pspell_check( $link, $password ) ) 
{
+                                               $ok = false;
+                                       }
+                               }
+
+                               if ( $ok && $lang != 'en' ) {
+                                       $config = pspell_config_create( 'en' );
+                                       pspell_config_runtogether( $config, 
true );
+                                       $link = pspell_new_config( $config );
+
+                                       if ( $link ) {
+                                               if ( pspell_check( $link, 
$password ) ) {
+                                                       $ok = false;
+                                               }
+                                       }
+                               }
+                       } elseif ( function_exists( 'enchant_dict_check' ) ) {
+                               $broker = enchant_broker_init();
+                               $dict = enchant_broker_request_dict( $broker, 
$lang );
+                               if ( $dict ) {
+                                       if ( enchant_dict_check( $dict, 
$password ) ) {
+                                               $ok = false;
+                                       }
+                               }
+
+                               if ( $ok && $lang != 'en' ) {
+                                       $dict = enchant_broker_request_dict( 
$broker, 'en' );
+                                       if ( $dict ) {
+                                               if ( enchant_dict_check( $dict, 
$password ) ) {
+                                                       $ok = false;
+                                               }
+                                       }
+                               }
+
+                               if ( $ok && 
$wgSecurePasswordsAdditionalDictionary ) {
+                                       $dict = 
enchant_broker_request_pwl_dict( $broker, 
$wgSecurePasswordsAdditionalDictionary );
+                                       if ( $dict ) {
+                                               if ( enchant_dict_check( $dict, 
$password ) ) {
+                                                       $ok = false;
+                                               }
+                                       }
+                               }
+
+                               enchant_broker_free( $broker );
+                       }
+               }
+
+               if ( !$ok ) {
+                       $conds = array( wfMsgExt( 'securepasswords-minlength', 
array( 'parsemag' ), $wgValidPasswords['minlength'] ) );
+                       if ( $wgValidPasswords['lowercase'] ) {
+                               $conds[] = wfMsg( 'securepasswords-lowercase' );
+                       }
+                       if ( $wgValidPasswords['uppercase'] ) {
+                               $conds[] = wfMsg( 'securepasswords-uppercase' );
+                       }
+                       if ( $wgValidPasswords['digit'] ) {
+                               $conds[] = wfMsg( 'securepasswords-digit' );
+                       }
+                       if ( $wgValidPasswords['special'] ) {
+                               $conds[] = wfMsg( 'securepasswords-special', 
str_replace( '\\', '', $wgSecurePasswordsSpecialChars ) );
+                       }
+                       if ( $wgValidPasswords['usercheck'] ) {
+                               $conds[] = wfMsgExt( 
'securepasswords-username', array( 'parsemag' ), $wgUser->getName() );
+                       }
+                       if ( $wgValidPasswords['wordcheck'] ) {
+                               $conds[] = wfMsg( 'securepasswords-word' );
+                       }
+                       $result = array( 'securepasswords-valid', 
$wgLang->listToText( $conds ) );
+                       return false;
+               }
+
+               $result = true;
+               return false;
+       }
+
+       /**
+        * Get password strength
+        */
+       private static function getPasswordStrength( $password ) {
+               global $wgSecurePasswordsStrengthTuning;
+               // TODO: implement
+       }
+
+       /**
+        * Encrypts a string with a given key and iv via mcrypt
+        * Returns base64-encoded result
+        */
+       private static function encrypt( $str, $key, $iv ) {
+               $m = mcrypt_module_open( 'rijndael-128', '', 'cbc', '' );
+               if ( $m === false ) {
+                       // maybe localize this, but it shouldn't ever happen in 
theory anyway...
+                       throw new MWException( 'mcrypt_module_open returned 
false' );
+               }
+               $key = hash( 'sha256', $key, true );
+               $blocksize = mcrypt_enc_get_block_size( $m );
+               mcrypt_generic_init( $m, $key, $iv );
+               $encrypted = base64_encode( mcrypt_generic( $m, self::pad( 
$str, $blocksize ) ) );
+               mcrypt_generic_deinit( $m );
+               mcrypt_module_close( $m );
+
+               return $encrypted;
+       }
+
+       private static function decrypt( $str, $key, $iv ) {
+               $m = mcrypt_module_open( 'rijndael-128', '', 'cbc', '' );
+               if ( $m === false ) {
+                       throw new MWException( 'mcrypt_module_open returned 
false' );
+               }
+               $key = hash( 'sha256', $key, true );
+               mcrypt_generic_init( $m, $key, $iv );
+               $decrypted = self::unpad( mdecrypt_generic( $m, base64_decode( 
$str ) ) );
+               mcrypt_generic_deinit( $m );
+               mcrypt_module_close( $m );
+
+               return $decrypted;
+       }
+
+       /**
+        * Helper functions because mcrypt is stupid and does null padding by 
default
+        * which is not binary safe in the slightest in order to unpad
+        * Using PKCS#7 instead
+        */
+       private static function pad( $str, $blocksize ) {
+               $pad = $blocksize - ( strlen( $str ) % $blocksize );
+               $str .= str_repeat( chr( $pad ), $pad );
+               return $str;
+       }
+
+       private static function unpad( $str ) {
+               return substr( $str, 0, strlen( $str ) - ord( substr( $str, -1 
) ) );
+       }
+
+       /**
+        * Compare password using version 3 of SecurePasswords
+        */
+       private static function compare3( $hash, $password, $userId, &$result ) 
{
+               global $wgSecurePasswordsSecretKey;
+
+               $bits = explode( ':', $hash );
+               $options = array();
+               $encrypted = false;
+               $iv = false;
+               $rounds = false;
+               $hash = false;
+               $result = false;
+
+               foreach ( $bits as $bit ) {
+                       if ( $bit == 'SP3' || strlen( $bit ) < 2 ) {
+                               continue;
+                       }
+                       $type = substr( $bit, 0, 1 );
+                       $rest = substr( $bit, 1 );
+                       switch ( $type ) {
+                               case 'G': // $rest is unix timestamp of when 
hash was generated
+                                       // TODO: password expiry stuff here
+                                       break;
+                               case 'R': // $rest is number of rounds to use
+                                       $rounds = $rest;
+                                       break;
+                               case 'H': // $rest is the actual hash
+                                       $hash = $rest;
+                                       break;
+                               case 'E': // $rest is the iv and the next bit 
is the encrypted value
+                                       $encrypted = true;
+                                       $iv = $rest;
+                                       break;
+                               default: // encrypted stuff after encountering 
E, or just invalid
+                                       if ( $encrypted ) {
+                                               $encrypted = false;
+                                               $d = explode( ':', 
self::decrypt( $bit, $wgSecurePasswordsSecretKey, $iv ) );
+                                               foreach ( $d as $p ) {
+                                                       $bits[] = $p;
+                                               }
+                                       }
+                                       break;
+                       }
+               }
+
+               if ( $rounds && $hash ) {
+                       $hashstr = '$2y$' . $rounds . '$' . $hash;
+                       $result = ( crypt( $password, $hashstr ) == $hashstr );
+               }
+
+               return false;
+       }
+
+       /**
+        * Compare password using version 2 of SecurePasswords
+        */
+       private static function compare2( $hash, $password, $userId, &$result) {
+               global $wgSecurePasswordsSecretKeys;
+               $bits = explode( ':', $hash, 4 );
+
+               $type1 = substr( $bits[1], 0, 1 );
+               $type2 = substr( $bits[1], 1, 1 );
+               $salt = $bits[2];
+               $hash1 = $bits[3];
+
+               $a = self::hashOrder( $userId );
+               $algos = array(
+                       $a[0] => 'sha512',
+                       $a[1] => 'ripemd160',
+                       $a[2] => 'ripemd320',
+                       $a[3] => 'whirlpool',
+                       $a[4] => 'gost',
+                       $a[5] => 'tiger192,4',
+                       $a[6] => 'haval256,5',
+                       $a[7] => 'sha256',
+                       $a[8] => 'sha384',
+                       $a[9] => 'ripemd128',
+                       $a[10] => 'ripemd256',
+               );
+               $pw = hash_hmac( $algos[$type2], $salt . '-' . hash_hmac( 
$algos[$type1], $password, $wgSecurePasswordsSecretKeys[0] ), 
$wgSecurePasswordsSecretKeys[1] );
+               $h1 = gzuncompress( base64_decode( $hash1 ) );
+               $ksize = mcrypt_get_key_size( MCRYPT_RIJNDAEL_256, 
MCRYPT_MODE_CBC );
+               $key = substr( $wgSecurePasswordsSecretKeys[2], 0, $ksize - 1 );
+               $bits = explode( '|', $h1 );
+               $iv = base64_decode( $bits[1] );
+               $h2 = base64_decode( $bits[0] );
+               $hf = mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $key, $h2, 
MCRYPT_MODE_CBC, $iv );
+
+               $result = ( $pw === $hf );
+               return false;
+       }
+
+       /**
+        * Compare password using version 1 of SecurePasswords
+        */
+       private static function compare1( $hash, $password, $userId, &$result ) 
{
+               $bits = explode( ':', $hash, 4 );
+
+               $type1 = substr( $bits[1], 0, 1 );
+               $type2 = substr( $bits[1], 1, 1 );
+               $salt = $bits[2];
+               $hash1 = $bits[3];
+
+               $m = function_exists( 'mcrypt_encrypt' );
+               $g = function_exists( 'gzcompress' );
+
+               $algos = array(
+                       'A' => 'md5',
+                       'B' => 'sha1',
+                       'C' => 'sha512',
+                       'D' => 'ripemd160',
+                       'E' => 'ripemd320',
+                       'F' => 'whirlpool',
+                       'G' => 'tiger192,4',
+                       'H' => 'snefru',
+                       'I' => 'gost',
+                       'J' => 'haval256,5',
+               );
+
+               $pw1 = hash( $algos[$type1], $password );
+               $pwf = hash( $algos[$type2], $salt . '-' . $pw1 );
+
+               if ( $g ) {
+                       $h1 = gzuncompress( base64_decode( $hash1 ) );
+               } else {
+                       $h1 = base64_decode( $hash1 );
+               }
+
+               if ( $m ) {
+                       global $wgSecretKey;
+                       $ksize = mcrypt_get_key_size( MCRYPT_RIJNDAEL_256, 
MCRYPT_MODE_CBC );
+                       $key = substr( $wgSecretKey, 0, $ksize - 1 );
+                       $bits = explode( '|', $h1 );
+                       $iv = base64_decode( $bits[1] );
+                       $h2 = base64_decode( $bits[0] );
+                       $hf = mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $key, $h2, 
MCRYPT_MODE_CBC, $iv );
+               } else {
+                       $hf = $h1;
+               }
+
+               $result = ($hf === $pwf);
+
+               return false;
+       }
+
+       /**
+        * Legacy function used in version 2 of SecurePasswords
+        */
+       private static function hashOrder( $userid ) {
+               if ( $userid > 999999 ) {
+                       $userid = substr( $userid, 0, 6 );
+               }
+               $o = floor( ( ( $userid * 3 ) + 513829 ) / 5 ) + 925487; #just 
two random prime numbers with no significance attached
+               $s = str_split( $o );
+               $r = array();
+               $f = false;
+               $n = 64;
+               //in case it is impossible to get all values 65-90 from the 
above values, we break after 1000 iterations
+               for($i = 0; $i < 1000; $i++) {
+                       $n += $s[0];
+                       if ( $n < 65 ) $n = 65;
+                       elseif ( $n > 90 ) $n = 65 + $s[0];
+                       if ( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
+                       $n -= $s[1];
+                       if ( $n < 65 ) $n = 65;
+                       elseif ( $n > 90 ) $n = 90 - $s[0];
+                       if ( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
+                       $n += 2 * $s[2];
+                       if ( $n < 65 ) $n = 65;
+                       elseif ( $n > 90 ) $n = 65 + $s[0];
+                       if ( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
+                       $n -= 2 * $s[3];
+                       if ( $n < 65 ) $n = 65;
+                       elseif ( $n > 90 ) $n = 90 - $s[0];
+                       if ( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
+                       $n += 3 * $s[4];
+                       if ( $n < 65 ) $n = 65;
+                       elseif ( $n > 90 ) $n = 65 + $s[0];
+                       if ( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
+                       $n -= 3 * $s[5];
+                       if ( $n < 65 ) $n = 65;
+                       elseif ( $n > 90 ) $n = 90 - $s[0];
+                       if ( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
+                       if ( count( $r ) == 26 ) {
+                               $f = true;
+                               break;
+                       }
+               }
+               if ( !$f ) {
+                       return array( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 
'I', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 
'Z' );
+               }
+               return $r;
+       }
+}
\ No newline at end of file
diff --git a/SecurePasswords.php b/SecurePasswords.php
index 2798eb6..5e058d3 100755
--- a/SecurePasswords.php
+++ b/SecurePasswords.php
@@ -1,360 +1,127 @@
-<?php
-
-/**
- * SecurePasswords extension by Ryan Schmidt (Skizzerz)
- * See http://www.mediawiki.org/wiki/Extension:SecurePasswords for details
- * Code is released under the Public Domain -- just please give credit where 
credit is due :)
- */
-
-if( !defined( 'MEDIAWIKI' ) ) {
-       echo "Not an entry point!\n";
-       die( 1 );
-}
-
-$wgValidPasswords = array(
-       'minlength' => $wgMinimalPasswordLength, #Minimum password length, 
should be at least 8 for decent security
-       'lowercase' => true, #Should we require at least one lowercase letter?
-       'uppercase' => true, #Should we require at least one uppercase letter?
-       'digit'     => true, #Should we require at least one digit?
-       'special'   => false, #Should we require at least one special character 
(punctuation, etc.)?
-       'usercheck' => true, #Should we disallow passwords that are the same as 
the username?
-       'wordcheck' => function_exists( 'pspell_check' ), #Should we check the 
password against a dictionary to make sure that it is not a word?
-);
-$wgSecurePasswordsSpecialChars = '.|\/!@#$%^&*\(\)-_=+\[\]{}`~,<>?\'";: '; # 
Character class of special characters for a regex
-$wgSecurePasswordsSecretKeys = array(false, false, false); #MUST be customized 
in LocalSettings.php!
-
-$wgExtensionCredits['other'][] = array(
-       'path'           => __FILE__,
-       'name'           => 'SecurePasswords',
-       'author'         => 'Ryan Schmidt',
-       'url'            => 
'https://www.mediawiki.org/wiki/Extension:SecurePasswords',
-       'version'        => '2.0',
-       'descriptionmsg' => 'securepasswords-desc',
-);
-
-$wgExtensionMessagesFiles['SecurePasswords'] = dirname( __FILE__ ) . 
'/SecurePasswords.i18n.php';
-
-$wgHooks['UserCryptPassword'][] = 'efSecurePasswordsCrypt'; //used to encrypt 
passwords
-$wgHooks['UserComparePasswords'][] = 'efSecurePasswordsCompare'; //used to 
compare a password with an encrypted password
-$wgHooks['isValidPassword'][] = 'efSecurePasswordsValidate'; //used to enforce 
password strength
-
-//new method
-function efSecurePasswordsCrypt( &$password, &$salt, &$wgPasswordSalt, &$hash 
) {
-       global $wgSecurePasswordsSecretKeys, $wgUser;
-       if($wgSecurePasswordsSecretKeys == array(false, false, false)) {
-               die('You need to customize $wgSecurePasswordsSecretKeys in your 
LocalSettings.php file.
-               See http://www.mediawiki.org/wiki/Extension:SecurePasswords for 
more information');
-       }
-       $hash = 'S2:';
-       
-       if( $salt === false ) {
-               $salt = substr( wfGenerateToken(), 0, 8 );
-       }
-       $a = efSecurePasswordsHashOrder( $wgUser->getId() ); 
-       
-       $hash_algos = hash_algos();
-       $algos = array();
-       //only use algorithms deemed "secure"
-       foreach( $hash_algos as $algo ) {
-               switch( $algo ) {
-                       case 'sha512':
-                               $algos[] = array( $a[0], 'sha512' );
-                               break;
-                       case 'ripemd160':
-                               $algos[] = array( $a[1], 'ripemd160' );
-                               break;
-                       case 'ripemd320':
-                               $algos[] = array( $a[2], 'ripemd320' );
-                               break;
-                       case 'whirlpool':
-                               $algos[] = array( $a[3], 'whirlpool' );
-                               break;
-                       case 'gost':
-                               $algos[] = array( $a[4], 'gost' );
-                               break;
-                       case 'tiger192,4':
-                               $algos[] = array( $a[5], 'tiger192,4' );
-                               break;
-                       case 'haval256,5':
-                               $algos[] = array( $a[6], 'haval256,5' );
-                               break;
-                       case 'sha256':
-                               $algos[] = array( $a[7], 'sha256' );
-                               break;
-                       case 'sha384':
-                               $algos[] = array( $a[8], 'sha384' );
-                               break;
-                       case 'ripemd128':
-                               $algos[] = array( $a[9], 'ripemd128' );
-                               break;
-                       case 'ripemd256':
-                               $algos[] = array( $a[10], 'ripemd256' );
-                               break;
-               }
-       }
-       
-       $r1 = rand( 0, count( $algos ) - 1 );
-       $r2 = rand( 0, count( $algos ) - 1 );
-       $type = $algos[$r1][0] . $algos[$r2][0];
-       $pw1 = hash_hmac( $algos[$r2][1], $salt . '-' . hash_hmac( 
$algos[$r1][1], $password, $wgSecurePasswordsSecretKeys[0] ), 
$wgSecurePasswordsSecretKeys[1] );
-       $size = mcrypt_get_iv_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC );
-       $ksize = mcrypt_get_key_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC );
-       $iv = mcrypt_create_iv( $size, MCRYPT_RAND );
-       $key = substr( $wgSecurePasswordsSecretKeys[2], 0, $ksize - 1 );
-       $pw2 = mcrypt_encrypt( MCRYPT_RIJNDAEL_256, $key, $pw1, 
MCRYPT_MODE_CBC, $iv );
-       $pwf = base64_encode( gzcompress( base64_encode( $pw2 ) . '|' . 
base64_encode( $iv ) ) );
-       $hash .= $type . ':' . $salt . ':' . $pwf;
-       
-       // sometimes the mcrypt is invalid, so we need to do a quick check to 
make sure that comparing will work in the future
-       // otherwise the password won't work... and that would suck
-       $hash = efSecurePasswordsRecursiveCheck( $hash, $password, $salt );
-       
-       return false;
-}
-
-function efSecurePasswordsCompare( &$hash, &$password, &$userId, &$result ) {
-       global $wgSecurePasswordsSecretKeys;
-       $bits = explode( ':', $hash, 4 );
-       if( $bits[0] == 'SP' && count( $bits ) == 4 ) {
-               //old check
-               return efSecurePasswordsOldCompare( $hash, $password, $userId, 
$result );
-       } elseif( $bits[0] != 'S2' || count( $bits ) != 4 ) {
-               //must be a default hash or something, let mw handle it
-               return true;
-       }
-       
-       $type1 = substr( $bits[1], 0, 1 );
-       $type2 = substr( $bits[1], 1, 1 );
-       $salt = $bits[2];
-       $hash1 = $bits[3];
-       
-       $a = efSecurePasswordsHashOrder( $userId );
-       $algos = array(
-               $a[0] => 'sha512',
-               $a[1] => 'ripemd160',
-               $a[2] => 'ripemd320',
-               $a[3] => 'whirlpool',
-               $a[4] => 'gost',
-               $a[5] => 'tiger192,4',
-               $a[6] => 'haval256,5',
-               $a[7] => 'sha256',
-               $a[8] => 'sha384',
-               $a[9] => 'ripemd128',
-               $a[10] => 'ripemd256',
-       );
-       $pw = hash_hmac( $algos[$type2], $salt . '-' . hash_hmac( 
$algos[$type1], $password, $wgSecurePasswordsSecretKeys[0] ), 
$wgSecurePasswordsSecretKeys[1] );
-       $h1 = gzuncompress( base64_decode( $hash1 ) );
-       $ksize = mcrypt_get_key_size( MCRYPT_RIJNDAEL_256, MCRYPT_MODE_CBC );
-       $key = substr( $wgSecurePasswordsSecretKeys[2], 0, $ksize - 1 );
-       $bits = explode( '|', $h1 );
-       $iv = base64_decode( $bits[1] );
-       $h2 = base64_decode( $bits[0] );
-       $hf = mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $key, $h2, MCRYPT_MODE_CBC, 
$iv );
-       
-       $result = ( $pw === $hf );
-       return false;
-}
-
-//does an old compare used in version 1.x of SecurePasswords
-function efSecurePasswordsOldCompare( &$hash, &$password, &$userId, &$result ) 
{
-       $bits = explode( ':', $hash, 4 );
-       
-       if( $bits[0] != 'SP' || count( $bits ) != 4 ) {
-               return true;
-       }
-       
-       $type1 = substr( $bits[1], 0, 1 );
-       $type2 = substr( $bits[1], 1, 1 );
-       $salt = $bits[2];
-       $hash1 = $bits[3];
-       
-       $m = function_exists( 'mcrypt_encrypt' );
-       $g = function_exists( 'gzcompress' );
-       
-       $algos = array(
-               'A' => 'md5',
-               'B' => 'sha1',
-               'C' => 'sha512',
-               'D' => 'ripemd160',
-               'E' => 'ripemd320',
-               'F' => 'whirlpool',
-               'G' => 'tiger192,4',
-               'H' => 'snefru',
-               'I' => 'gost',
-               'J' => 'haval256,5',
-       );
-       
-       $pw1 = hash( $algos[$type1], $password );
-       $pwf = hash( $algos[$type2], $salt . '-' . $pw1 );
-       
-       if( $g ) {
-               $h1 = gzuncompress( base64_decode( $hash1 ) );
-       } else {
-               $h1 = base64_decode( $hash1 );
-       }
-       
-       if( $m ) {
-               global $wgSecretKey;
-               $ksize = mcrypt_get_key_size( MCRYPT_RIJNDAEL_256, 
MCRYPT_MODE_CBC );
-               $key = substr( $wgSecretKey, 0, $ksize - 1 );
-               $bits = explode( '|', $h1 );
-               $iv = base64_decode( $bits[1] );
-               $h2 = base64_decode( $bits[0] );
-               $hf = mcrypt_decrypt( MCRYPT_RIJNDAEL_256, $key, $h2, 
MCRYPT_MODE_CBC, $iv );
-       } else {
-               $hf = $h1;
-       }
-       
-       $result = ($hf === $pwf);
-       
-       return false;
-}
-
-function efSecurePasswordsRecursiveCheck( $hash, $password, $salt ) {
-       $result = false;
-       $x = 1; // unused, but necessary since everything is by reference
-       efSecurePasswordsCompare( $hash, $password, $x, $result );
-       if(!$result) {
-               efSecurePasswordsCrypt( $password, $salt, $x, $hash );
-               return efSecurePasswordsRecursiveCheck( $hash, $password, $salt 
);
-       }
-       return $hash;
-}
-
-function efSecurePasswordsValidate( $password, &$result, $user ) {
-       // if the password matches the user's current password, then don't 
check for validity
-       // this way users with passwords that don't fit the criteria can still 
log in :)
-       if( ( $id = $user->getId() ) !== 0 ) {
-               $dbr = wfGetDB( DB_SLAVE );
-               $hash = $dbr->selectField( 'user', 'user_password', 'user_id=' 
. $id );
-               if( User::comparePasswords( $hash, $password, $id ) ) {
-                       $result = true;
-                       return false;
-               }
-       }
-
-       $ok = true;
-
-       global $wgValidPasswords, $wgContLang, $wgSecurePasswordsSpecialChars, 
$wgLang, $wgUser;
-       $lang = $wgContLang->getPreferredVariant( false );
-       // check password length
-       if( strlen( $password ) < $wgValidPasswords['minlength'] ) {
-               $ok = false;
-       }
-       
-       // check for a lowercase letter, if needed
-       if( $wgValidPasswords['lowercase'] && !preg_match( '/[a-z]/', $password 
) ) {
-               $ok = false;
-       }
-       
-       // check for an uppercase letter, if needed
-       if( $wgValidPasswords['uppercase'] && !preg_match( '/[A-Z]/', $password 
) ) {
-               $ok = false;
-       }
-       
-       // check for a digit, if needed
-       if( $wgValidPasswords['digit'] && !preg_match( '/[0-9]/', $password ) ) 
{
-               $ok = false;
-       }
-       
-       // check for a special character, if needed
-       if( $wgValidPasswords['special'] && !preg_match( '/[' . 
$wgSecurePasswordsSpecialChars . ']/', $password ) ) {
-               $ok = false;
-       }
-       
-       // check for the username, if needed
-       if( $wgValidPasswords['usercheck'] && $wgContLang->lc( $password ) == 
$wgContLang->lc( $user->getName() ) ) {
-               $ok = false;
-       }
-       
-       // check for words, if needed
-       if( $wgValidPasswords['wordcheck'] && function_exists( 'pspell_check' ) 
) {
-               $link = pspell_new( $lang, '', '', ( PSPELL_FAST | 
PSPELL_RUN_TOGETHER ) );
-               if( $link ) {
-                       if( pspell_check( $link, $password ) ) {
-                               $ok = false;
-                       }
-               }
-               if( $lang != 'en' ) {
-                       $link = pspell_new( 'en', '', '', ( PSPELL_FAST | 
PSPELL_RUN_TOGETHER ) );
-                       if( $link ) {
-                               if( pspell_check( $link, $password ) ) {
-                                       $ok = false;
-                               }
-                       }
-               }
-       }
-
-       if ( !$ok ) {
-               $conds = array( wfMsgExt( 'securepasswords-minlength', array( 
'parsemag' ), $wgValidPasswords['minlength'] ) );
-               if( $wgValidPasswords['lowercase'] ) {
-                       $conds[] = wfMsg( 'securepasswords-lowercase' );
-               }
-               if( $wgValidPasswords['uppercase'] ) {
-                       $conds[] = wfMsg( 'securepasswords-uppercase' );
-               }
-               if( $wgValidPasswords['digit'] ) {
-                       $conds[] = wfMsg( 'securepasswords-digit' );
-               }
-               if( $wgValidPasswords['special'] ) {
-                       $conds[] = wfMsg( 'securepasswords-special', 
str_replace( '\\', '', $wgSecurePasswordsSpecialChars ) );
-               }
-               if( $wgValidPasswords['usercheck'] ) {
-                       $conds[] = wfMsgExt( 'securepasswords-username', array( 
'parsemag' ), $wgUser->getName() );
-               }
-               if( $wgValidPasswords['wordcheck'] ) {
-                       $conds[] = wfMsg( 'securepasswords-word' );
-               }
-               $result = array( 'securepasswords-valid', $wgLang->listToText( 
$conds ) );
-               return false;
-       }
-
-       $result = true;
-       return false;
-}
-
-function efSecurePasswordsHashOrder( $userid ) {
-       if( $userid > 999999 ) {
-               $userid = substr( $userid, 0, 6 );
-       }
-       $o = floor( ( ( $userid * 3 ) + 513829 ) / 5 ) + 925487; #just two 
random prime numbers with no significance attached
-       $s = str_split( $o );
-       $r = array();
-       $f = false;
-       $n = 64;
-       //in case it is impossible to get all values 65-90 from the above 
values, we break after 1000 iterations
-       for($i = 0; $i < 1000; $i++) {
-               $n += $s[0];
-               if( $n < 65 ) $n = 65;
-               elseif( $n > 90 ) $n = 65 + $s[0];
-               if( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
-               $n -= $s[1];
-               if( $n < 65 ) $n = 65;
-               elseif( $n > 90 ) $n = 90 - $s[0];
-               if( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
-               $n += 2 * $s[2];
-               if( $n < 65 ) $n = 65;
-               elseif( $n > 90 ) $n = 65 + $s[0];
-               if( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
-               $n -= 2 * $s[3];
-               if( $n < 65 ) $n = 65;
-               elseif( $n > 90 ) $n = 90 - $s[0];
-               if( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
-               $n += 3 * $s[4];
-               if( $n < 65 ) $n = 65;
-               elseif( $n > 90 ) $n = 65 + $s[0];
-               if( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
-               $n -= 3 * $s[5];
-               if( $n < 65 ) $n = 65;
-               elseif( $n > 90 ) $n = 90 - $s[0];
-               if( !in_array( chr( $n ), $r ) ) $r[] = chr( $n );
-               if( count( $r ) == 26 ) {
-                       $f = true;
-                       break;
-               }
-       }
-       if( !$f ) {
-               return array( 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'K', 
'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z' );
-       }
-       return $r;
+<?php
+/**
+ * SecurePasswords extension by Ryan Schmidt (Skizzerz)
+ * See http://www.mediawiki.org/wiki/Extension:SecurePasswords for details
+ * Code is released under the GNU GPL version 2 or (at your discretion) any 
later version
+ */
+if ( !defined( 'MEDIAWIKI' ) ) {
+       echo "Not an entry point!\n";
+       die( 1 );
+}
+
+// Please see extension documentation for more detailed descriptions on all of 
these parameters
+$wgValidPasswords = array(
+       'minlength' => $wgMinimalPasswordLength, #Minimum password length, 
should be at least 8 for decent security
+       'lowercase' => 1, #How many lowercase letters to require
+       'uppercase' => 1, #How many uppercase letters to require
+       'digit'     => 1, #How many digits to require
+       'special'   => 0, #How many special characters to require
+       'previous'  => 0, #Number of previous passwords to retain (forcing 
users to not pick the same password they previously used)
+       'strength'  => 0, #Minimum password strength needed (0 - 100)
+       'usercheck' => true, #Should we disallow passwords that are the same as 
the username?
+       'wordcheck' => false, #Should we check the password against a 
dictionary to make sure that it is not a word? (force-disabled if server does 
not support it)
+);
+$wgSecurePasswordsSpecialChars = '.|\/!@#$%^&*\(\)\-_=+\[\]{}`~,<>?\'";: '; 
#Character class of special characters for a regex
+$wgSecurePasswordsRounds = 10; #Number of rounds for the bcrypt algorithm, 
power of 2. Valid values are 1-31. 10 = 2^10 = 1024 rounds (see documentation 
page for more information)
+$wgSecurePasswordsAutoRounds = false; #Dynamically determines the optimal 
number of rounds, will slow down requests that involve hash generation (see 
documentation page for more information)
+$wgSecurePasswordsAutoRoundsThreshold = 0.5; #How much time a hash needs to 
take (in seconds) before the round size gets chosen via autorounds (default 0.5 
seconds)
+$wgSecurePasswordsExpiry = 0; #Number of days it takes a password to expire. 0 
means passwords never expire. This can also be configured per-group (see 
documentation page for more information)
+$wgSecurePasswordsEncryptPasswords = false; #Whether to encrypt passwords *IN 
ADDITION* to hashing them in the database (true, requires mcrypt and zlib), or 
only hash the passwords (false, default)
+$wgSecurePasswordsSecretKey = false; #MUST be customized in LocalSettings.php 
if you are encrypting passwords! (or preferrably a file not accessible on the 
web with appropriate permissions set)
+$wgSecurePasswordsMigrateOnLogin = false; #Whether to migrate a user to the 
SecurePasswords hash format on login (true) or only when they change their 
password (false, default)
+$wgSecurePasswordsStrengthTuning = array(); #Allows for tuning the default 
password strength checker, see documentation page for more information
+$wgSecurePasswordsAdditionalDictionary = false; #Allows for specifying an 
additional dictionary file that will be checked against if wordcheck is true 
(see documentation page for more information)
+
+// Configuration variables related to trialling / uninstallation -- don't set 
these except in very specific circumstances
+$wgSecurePasswordsTrialMode = false; #Specifies that default MediaWiki hashes 
are stored in an archive table for easy uninstallation. Only set this to true 
if you are trialling SecurePasswords and may wish to uninstall it soon
+$wgSecurePasswordsUninstall = false; #Specifies that you are attempting to 
uninstall SecurePasswords. Any logins of SecurePasswords hashes will be 
migrated back to MediaWiki format, and all features of the extension are 
disabled
+
+// Old configuration options, no longer used in current versions, but retained 
for backwards compat (namely, migrating from old versions to the current 
version)
+// If these are customized in LocalSettings.php, it is assumed you previously 
had an older version installed and some additional server checks are made
+$wgSecurePasswordsSecretKeys = array(false, false, false);
+$wgSecurePasswordSpecialChars = false; #Typo in older versions, if this is 
defined we replace the above char class with this
+
+$wgExtensionCredits['other'][] = array(
+       'path'           => __FILE__,
+       'name'           => 'SecurePasswords',
+       'author'         => 'Ryan Schmidt',
+       'url'            => 
'https://www.mediawiki.org/wiki/Extension:SecurePasswords',
+       'version'        => '3.0beta1',
+       'descriptionmsg' => 'securepasswords-desc',
+);
+
+$wgExtensionMessagesFiles['SecurePasswords'] = dirname( __FILE__ ) . 
'/SecurePasswords.i18n.php';
+$wgAutoloadClasses['ExtSecurePasswords'] = dirname( __FILE__ ) . 
'/ExtSecurePasswords.php';
+$wgHooks['UserCryptPassword'][] = 'ExtSecurePasswords::UserCryptPasswords'; 
//used to encrypt passwords
+$wgHooks['UserComparePasswords'][] = 
'ExtSecurePasswords::UserComparePasswords'; //used to compare a password with 
an encrypted password
+$wgHooks['isValidPassword'][] = 'ExtSecurePasswords::isValidPassword'; //used 
to enforce password strength
+$wgHooks['LoadExtensionSchemaUpdates'][] = 
'ExtSecurePasswords::LoadExtensionSchemaUpdates'; // performs necessary schema 
changes
+$wgExtensionFunctions[] = 'efSecurePasswordsCheckSetup';
+
+//check server requirements and also that parameters are correctly set
+//Mandatory: PHP 5.3.7+
+//Optional: mcrypt, zlib, pspell or enchant
+function efSecurePasswordsCheckSetup() {
+       global $wgValidPasswords, $wgSecurePasswordsSecretKeys, 
$wgSecurePasswordsSecretKey, $wgSecurePasswordSpecialChars, 
$wgSecurePasswordsSpecialChars;
+       global $wgSecurePasswordsRounds, $wgSecurePasswordsExpiry, 
$wgSecurePasswordsEncryptPasswords, $wgSecurePasswordsMigrateOnLogin;
+       global $wgSecurePasswordsAutoRounds, 
$wgSecurePasswordsAutoRoundsThreshold, $wgSecurePasswordsAdditionalDictionary;
+       $errors = array();
+
+       if ( version_compare( PHP_VERSION, '5.3.7' ) < 0 ) {
+               // We MIGHT be able to use i18n here since it is called in 
$wgExtensionFunctions, but not sure...
+               $errors[] = 'The SecurePasswords extension requires PHP version 
5.3.7 or greater';
+       }
+
+       if ( $wgSecurePasswordsEncryptPasswords ) {
+               if( !function_exists( 'mcrypt_module_open' ) ) {
+                       $errors[] = 'The mcrypt PHP extension is required 
because you are encrypting password hashes';
+               }
+
+               if ( !in_array( 'rijndael-128', mcrypt_list_modules() ) ) {
+                       $errors[] = 'Your installation of mcrypt does not 
support AES encryption (Rijndael-128)';
+               }
+
+               if ( $wgSecurePasswordsSecretKey == false ) {
+                       $errors[] = '$wgSecurePasswordsSecretKey must be set 
becase you are encrypting password hashes';
+               }
+       }
+
+       if ( $wgSecurePasswordsSecretKeys != array(false, false, false) ) {
+               if ( !function_exists( 'mcrypt_encrypt' ) ) {
+                       $errors[] = 'The mcrypt PHP extension is required 
because you are migrating from an older version of SecurePasswords';
+               }
+
+               if ( !function_exists( 'gzcompress' ) ) {
+                       $errors[] = 'The zlib PHP extension is required because 
you are migrating from an older version of SecurePasswords';
+               }
+       }
+
+       $wgSecurePasswordsRounds = intval( $wgSecurePasswordsRounds );
+       if ( $wgSecurePasswordsRounds < 1 || $wgSecurePasswordsRounds > 31 ) {
+               $errors[] = '$wgSecurePasswordsRounds must be an integer 
between 1 and 31, inclusive';
+       }
+
+       $wgSecurePasswordsAutoRoundsThreshold = floatval( 
$wgSecurePasswordsAutoRoundsThreshold );
+       if ( $wgSecurePasswordsAutoRoundsThreshold <= 0 ) {
+               $errors[] = '$wgSecurePasswordsAutoRoundsThreshold must be a 
decimal greater than 0';
+       }
+
+       if ( $wgValidPasswords['wordcheck'] && !( function_exists( 
'pspell_check' ) || function_exists( 'enchant_dict_check' ) ) ) {
+               $errors[] = 'Either the pspell or enchant PHP extension is 
required because you are checking if passwords are dictionary words';
+
+               if ( $wgSecurePasswordsAdditionalDictionary !== false && 
!is_readable( $wgSecurePasswordsAdditionalDictionary ) ) {
+                       $errors[] = 'You have specified an additional 
dictionary for word checking but it does not exist or it is not readable by the 
webserver';
+               }
+       }
+
+       if ( count( $errors ) > 0 ) {
+               throw new MWException( implode( "\n", $errors ) );
+       }
+
+       // If we get here, we're good, do other init things
+
+       // typo fix
+       if ( $wgSecurePasswordSpecialChars !== false ) {
+               $wgSecurePasswordsSpecialChars = $wgSecurePasswordSpecialChars;
+       }
 }
diff --git a/password_history.sql b/password_history.sql
new file mode 100644
index 0000000..00ae320
--- /dev/null
+++ b/password_history.sql
@@ -0,0 +1,8 @@
+CREATE TABLE IF NOT EXISTS /*_*/password_history (
+       ph_user integer unsigned NOT NULL, -- FK to user id
+       ph_password mediumblob NOT NULL, -- password hash
+       ph_timestamp varbinary(14) NOT NULL DEFAULT '',
+       PRIMARY KEY (ph_user, ph_timestamp)
+) /*$wgDBTableOptions*/;
+
+CREATE INDEX /*i*/age ON /*_*/password_history (ph_timestamp);
\ No newline at end of file
diff --git a/securepasswords.sql b/securepasswords.sql
deleted file mode 100644
index e19e518..0000000
--- a/securepasswords.sql
+++ /dev/null
@@ -1,6 +0,0 @@
---- Modify the user table for the SecurePasswords extension
---- tinyblob doesn't cut it anymore for the password hashing used by this 
extension
---- so this will change it to mediumblob
-
-ALTER TABLE /*$wgDBprefix*/user MODIFY user_password MEDIUMBLOB NOT NULL;
-ALTER TABLE /*$wgDBprefix*/user MODIFY user_newpassword MEDIUMBLOB NOT NULL;
\ No newline at end of file
diff --git a/securepasswords_uninstall.sql b/securepasswords_uninstall.sql
new file mode 100644
index 0000000..fcbe00f
--- /dev/null
+++ b/securepasswords_uninstall.sql
@@ -0,0 +1,5 @@
+-- This table only gets populated if $wgSecurePasswordsTrialMode is true
+CREATE TABLE IF NOT EXISTS /*_*/securepasswords_uninstall (
+       su_user integer unsigned NOT NULL PRIMARY KEY,
+       su_password tinyblob NOT NULL
+) /*$wgDBTableOptions*/;
\ No newline at end of file
diff --git a/user.patch.user_newpassword.sql b/user.patch.user_newpassword.sql
new file mode 100644
index 0000000..1573527
--- /dev/null
+++ b/user.patch.user_newpassword.sql
@@ -0,0 +1,5 @@
+--- Modify the user table for the SecurePasswords extension
+--- tinyblob doesn't cut it anymore for the password hashing used by this 
extension
+--- so this will change it to mediumblob
+
+ALTER TABLE /*_*/user MODIFY user_newpassword MEDIUMBLOB NOT NULL;
\ No newline at end of file
diff --git a/user.patch.user_password.sql b/user.patch.user_password.sql
new file mode 100644
index 0000000..c8e861e
--- /dev/null
+++ b/user.patch.user_password.sql
@@ -0,0 +1,5 @@
+--- Modify the user table for the SecurePasswords extension
+--- tinyblob doesn't cut it anymore for the password hashing used by this 
extension
+--- so this will change it to mediumblob
+
+ALTER TABLE /*_*/user MODIFY user_password MEDIUMBLOB NOT NULL;
\ No newline at end of file

-- 
To view, visit https://gerrit.wikimedia.org/r/101813
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I5103c081e2725242be99f42451a0bec890c15f9b
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/SecurePasswords
Gerrit-Branch: master
Gerrit-Owner: Skizzerz <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to