Enforce $wgMinimalPasswordLength client-side
authorAryeh Gregor <simetrical@users.mediawiki.org>
Sun, 23 Aug 2009 03:33:11 +0000 (03:33 +0000)
committerAryeh Gregor <simetrical@users.mediawiki.org>
Sun, 23 Aug 2009 03:33:11 +0000 (03:33 +0000)
. . . except not really.  It works fine on Opera 9.6, except for the
slight detail that if you enter a password that's too short, Opera will
helpfully repeat your password back to you un-*ed when telling you it's
too short.  Same in Opera 10.00 Beta 3.  So the code is commented out,
and there are no functional changes.  We'll need UA sniffing when the
code is uncommented.  But I already wrote it, so may as well commit it
for future use.

This recycles the "passwordtooshort" message to provide the client-side
error message, using the title attribute on the input.  Since the title
attribute might be displayed when the user hasn't actually entered an
invalid password, I've reworded it to not imply the user actually
entered an incorrect password, so it just states the requirement.  (This
accords with the advice given in the HTML 5 spec.)  I didn't make up a
new message name for that, because it's not a big deal if translations
do imply that the password is wrong, since that should theoretically be
the most common case anyway.

includes/User.php
includes/specials/SpecialResetpass.php
includes/templates/Userlogin.php
languages/messages/MessagesEn.php

index 315efed..df95f3f 100644 (file)
@@ -3586,4 +3586,49 @@ class User {
                $dbw->commit();
        }
 
+       /**
+        * Provide an array of HTML 5 attributes to put on an input element
+        * intended for the user to enter a new password.  This may include
+        * required, title, and/or pattern, depending on $wgMinimalPasswordLength.
+        *
+        * Do *not* use this when asking the user to enter his current password!
+        * Regardless of configuration, users may have invalid passwords for whatever
+        * reason (e.g., they were set before requirements were tightened up).
+        * Only use it when asking for a new password, like on account creation or
+        * ResetPass.
+        *
+        * Obviously, you still need to do server-side checking.
+        *
+        * @return array Array of HTML attributes suitable for feeding to
+        *   Html::element(), directly or indirectly.  (Don't feed to Xml::*()!
+        *   That will potentially output invalid XHTML 1.0 Transitional, and will
+        *   get confused by the boolean attribute syntax used.)
+        */
+       public static function passwordChangeInputAttribs() {
+               global $wgMinimalPasswordLength;
+
+               if ( $wgMinimalPasswordLength == 0 ) {
+                       return array();
+               }
+
+               # Note that the pattern requirement will always be satisfied if the
+               # input is empty, so we need required in all cases.
+               $ret = array( 'required' );
+
+               # We can't actually do this right now, because Opera 9.6 will print out
+               # the entered password visibly in its error message!  When other
+               # browsers add support for this attribute, or Opera fixes its support,
+               # we can add support with a version check to avoid doing this on Opera
+               # versions where it will be a problem.  Reported to Opera as
+               # DSK-262266, but they don't have a public bug tracker for us to follow.
+               /*
+               if ( $wgMinimalPasswordLength > 1 ) {
+                       $ret['pattern'] = '.{' . intval( $wgMinimalPasswordLength ) . ',}';
+                       $ret['title'] = wfMsgExt( 'passwordtooshort', 'parsemag',
+                               $wgMinimalPasswordLength );
+               }
+               */
+
+               return $ret;
+       }
 }
index f585612..3e49354 100644 (file)
@@ -128,8 +128,6 @@ class SpecialResetpass extends SpecialPage {
        }
 
        function pretty( $fields ) {
-               global $wgMinimalPasswordLength;
-
                $out = '';
                foreach ( $fields as $list ) {
                        list( $name, $label, $type, $value ) = $list;
@@ -137,14 +135,9 @@ class SpecialResetpass extends SpecialPage {
                                $field = htmlspecialchars( $value );
                        } else {
                                $attribs = array( 'id' => $name );
-                               # The current password field is never required; it's possible
-                               # that existing users might have empty passwords on any wiki.
-                               # The two other password fields are required if
-                               # $wgMinimalPasswordLength > 0 (not allowed to set an empty
-                               # password).
-                               if ( ( $name == 'wpNewPassword' || $name == 'wpRetype' )
-                               && $wgMinimalPasswordLength > 0 ) {
-                                       $attribs[] = 'required';
+                               if ( $name == 'wpNewPassword' || $name == 'wpRetype' ) {
+                                       $attribs = array_merge( $attribs,
+                                               User::passwordChangeInputAttribs() );
                                }
                                if ( $name == 'wpPassword' ) {
                                        $attribs[] = 'autofocus';
index 41e1346..914e773 100644 (file)
@@ -133,8 +133,6 @@ class UsercreateTemplate extends QuickTemplate {
        }
        
        function execute() {
-               global $wgMinimalPasswordLength;
-
                if( $this->data['message'] ) {
 ?>
        <div class="<?php $this->text('messagetype') ?>box">
@@ -176,7 +174,7 @@ class UsercreateTemplate extends QuickTemplate {
                                'id' => 'wpPassword2',
                                'tabindex' => '2',
                                'size' => '20'
-                       ) + ( $wgMinimalPasswordLength > 0 ? array( 'required' ) : array() ) ); ?>
+                       ) + User::passwordChangeInputAttribs() ); ?>
                        </td>
                </tr>
        <?php if( $this->data['usedomain'] ) {
@@ -204,7 +202,7 @@ class UsercreateTemplate extends QuickTemplate {
                        'id' => 'wpRetype',
                        'tabindex' => '4',
                        'size' => '20'
-               ) + ( $wgMinimalPasswordLength > 0 ? array( 'required' ) : array() ) ); ?>
+               ) + User::passwordChangeInputAttribs() ); ?>
                        </td>
                </tr>
                <tr>
index f248806..b13d591 100644 (file)
@@ -1076,8 +1076,7 @@ Check your spelling.',
 Please try again.',
 'wrongpasswordempty'         => 'Password entered was blank.
 Please try again.',
-'passwordtooshort'           => 'Your password is too short.
-It must have at least {{PLURAL:$1|1 character|$1 characters}}.',
+'passwordtooshort'           => 'Passwords must be at least {{PLURAL:$1|1 character|$1 characters}}.',
 'password-name-match'        => 'Your password must be different from your username.',
 'mailmypassword'             => 'E-mail new password',
 'passwordremindertitle'      => 'New temporary password for {{SITENAME}}',