X-Git-Url: http://git.cyclocoop.org/?a=blobdiff_plain;f=includes%2Fpassword%2FPassword.php;h=f167f958e6deed914d9ca829d101936416d4ed58;hb=2a571b49bb73998a2f83a1cba9d6596e875f9afc;hp=4e395b5182f7ef28fded98ace47bbdf00857ddd8;hpb=222727927abfe04a3116e4f7671e7628b14fe661;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/password/Password.php b/includes/password/Password.php index 4e395b5182..f167f958e6 100644 --- a/includes/password/Password.php +++ b/includes/password/Password.php @@ -20,6 +20,8 @@ * @file */ +use Wikimedia\Assert\Assert; + /** * Represents a password hash for use in authentication * @@ -81,6 +83,11 @@ abstract class Password { */ protected $config; + /** + * Hash must fit in user_password, which is a tinyblob + */ + const MAX_HASH_SIZE = 255; + /** * Construct the Password object using a string hash * @@ -133,8 +140,7 @@ abstract class Password { * * @return bool True if needs update, false otherwise */ - public function needsUpdate() { - } + abstract public function needsUpdate(); /** * Compare one Password object to this object @@ -143,21 +149,38 @@ abstract class Password { * Password::toString() for each object. This can be overridden to do * custom comparison, but it is not recommended unless necessary. * + * @deprecated since 1.33, use verify() + * * @param Password|string $other The other password * @return bool True if equal, false otherwise */ public function equals( $other ) { - if ( !$other instanceof self ) { - // No need to use the factory because we're definitely making - // an object of the same type. - $obj = clone $this; - $obj->crypt( $other ); - $other = $obj; + if ( is_string( $other ) ) { + return $this->verify( $other ); } return hash_equals( $this->toString(), $other->toString() ); } + /** + * Checks whether the given password matches the hash stored in this object. + * + * @param string $password Password to check + * @return bool + */ + public function verify( $password ) { + Assert::parameter( is_string( $password ), + '$password', 'must be string, actual: ' . gettype( $password ) + ); + + // No need to use the factory because we're definitely making + // an object of the same type. + $obj = clone $this; + $obj->crypt( $password ); + + return hash_equals( $this->toString(), $obj->toString() ); + } + /** * Convert this hash to a string that can be stored in the database * @@ -168,9 +191,28 @@ abstract class Password { * are considered equivalent. * * @return string + * @throws PasswordError if password cannot be serialized to fit a tinyblob. */ public function toString() { - return ':' . $this->config['type'] . ':' . $this->hash; + $result = ':' . $this->config['type'] . ':' . $this->hash; + $this->assertIsSafeSize( $result ); + return $result; + } + + /** + * Assert that hash will fit in a tinyblob field. + * + * This prevents MW from inserting it into the DB + * and having MySQL silently truncating it, locking + * the user out of their account. + * + * @param string $hash The hash in question. + * @throws PasswordError If hash does not fit in DB. + */ + final protected function assertIsSafeSize( $hash ) { + if ( strlen( $hash ) > self::MAX_HASH_SIZE ) { + throw new PasswordError( "Password hash is too big" ); + } } /**