From: Bartosz Dziewoński Date: Mon, 25 Feb 2019 20:08:10 +0000 (+0100) Subject: Check normalization rules of usernames during signup X-Git-Tag: 1.34.0-rc.0~2603^2 X-Git-Url: http://git.heureux-cyclage.org/?a=commitdiff_plain;h=bc2a712ace1140cab3a4e000edd72ae0672cc904;p=lhc%2Fweb%2Fwiklou.git Check normalization rules of usernames during signup The username may need to be adjusted due to technical restrictions for page titles: the first letter is capitalized, underscores are changed to spaces, and so on. Some of these tweaks can be unwanted by some users: for example "Matma Rex" and "matmarex" are both acceptable usernames for me, but "Matmarex" is not. Display a warning if that happens (if the user has JavaScript enabled). No action is needed from the user, other than reading the message. Bug: T63416 Change-Id: I120f17ca3801879ad650e5a81e7a4c270540cd4f --- diff --git a/RELEASE-NOTES-1.33 b/RELEASE-NOTES-1.33 index 515407771f..c2bddd11f0 100644 --- a/RELEASE-NOTES-1.33 +++ b/RELEASE-NOTES-1.33 @@ -57,6 +57,8 @@ production. * Argon2 password hashing is now available, can be enabled via $wgPasswordDefault = 'argon2'. It's designed to resist timing attacks (requires PHP 7.2+) and GPU hacking (7.3+). +* Special:CreateAccount now warns the user if their chosen username has to be + normalized. === External library changes in 1.33 === diff --git a/languages/i18n/en.json b/languages/i18n/en.json index c371cc2e6c..4ad916b8f5 100644 --- a/languages/i18n/en.json +++ b/languages/i18n/en.json @@ -459,6 +459,7 @@ "badretype": "The passwords you entered do not match.", "usernameinprogress": "An account creation for this user name is already in progress.\nPlease wait.", "userexists": "Username entered already in use.\nPlease choose a different name.", + "createacct-normalization": "Your username will be adjusted to \"$2\" due to technical restrictions.", "loginerror": "Login error", "createacct-error": "Account creation error", "createaccounterror": "Could not create account: $1", diff --git a/languages/i18n/qqq.json b/languages/i18n/qqq.json index 686022069a..f1b78de51e 100644 --- a/languages/i18n/qqq.json +++ b/languages/i18n/qqq.json @@ -665,6 +665,7 @@ "badretype": "Used as error message when the new password and its retype do not match.", "usernameinprogress": "Used as error message in creating a user account.", "userexists": "Used as error message in creating a user account.", + "createacct-normalization": "Used as warning message on account creation when user name is adjusted silently due to technical restrictions (e.g. first letter capitalized, underscores converted to spaces).\nParameters:\n* $1 - the old username\n* $2 - the new username", "loginerror": "Used as title of error message.\n{{Identical|Login error}}", "createacct-error": "Used as heading for the error message.", "createaccounterror": "Parameters:\n* $1 - an error message", diff --git a/resources/Resources.php b/resources/Resources.php index 1edfdd3eb7..59fdd85b70 100644 --- a/resources/Resources.php +++ b/resources/Resources.php @@ -2353,6 +2353,7 @@ return [ 'createacct-emailrequired', 'noname', 'userexists', + 'createacct-normalization', ], 'dependencies' => [ 'mediawiki.api', diff --git a/resources/src/mediawiki.htmlform.checker.js b/resources/src/mediawiki.htmlform.checker.js index 78e9f5f6ac..ecaddd8041 100644 --- a/resources/src/mediawiki.htmlform.checker.js +++ b/resources/src/mediawiki.htmlform.checker.js @@ -73,7 +73,7 @@ if ( value === '' ) { this.currentValue = value; - this.setErrors( [] ); + this.setErrors( true, [] ); return; } @@ -91,14 +91,10 @@ that.currentValue = value; - if ( info.valid ) { - that.setErrors( [], forceReplacement ); - } else { - that.setErrors( info.messages, forceReplacement ); - } + that.setErrors( info.valid, info.messages, forceReplacement ); } ).fail( function () { that.currentValue = null; - that.setErrors( [] ); + that.setErrors( true, [] ); } ); return currentRequestInternal; @@ -106,6 +102,7 @@ /** * Display errors associated with the form element + * @param {boolean} valid Whether the input is still valid regardless of the messages * @param {Array} errors Error messages. Each error message will be appended to a * `` or `
  • `, as with jQuery.append(). * @param {boolean} [forceReplacement] Set true to force a visual replacement even @@ -113,7 +110,7 @@ * @return {mw.htmlform.Checker} * @chainable */ - mw.htmlform.Checker.prototype.setErrors = function ( errors, forceReplacement ) { + mw.htmlform.Checker.prototype.setErrors = function ( valid, errors, forceReplacement ) { var $oldErrorBox, tagName, showFunc, text, replace, $errorBox = this.$errorBox; @@ -165,14 +162,17 @@ // FIXME: Use CSS transition // eslint-disable-next-line no-jquery/no-slide $errorBox - .attr( 'class', 'error' ) + .attr( 'class', valid ? 'warning' : 'error' ) .empty() .append( errors.map( function ( e ) { return errors.length === 1 ? e : $( '
  • ' ).append( e ); } ) ) .slideDown(); }; - if ( $oldErrorBox !== $errorBox && $oldErrorBox.hasClass( 'error' ) ) { + if ( + $oldErrorBox !== $errorBox && + ( $oldErrorBox.hasClass( 'error' ) || $oldErrorBox.hasClass( 'warning' ) ) + ) { // eslint-disable-next-line no-jquery/no-slide $oldErrorBox.slideUp( showFunc ); } else { diff --git a/resources/src/mediawiki.special.userlogin.signup.js b/resources/src/mediawiki.special.userlogin.signup.js index 777f5e9dcf..fff2d4e61a 100644 --- a/resources/src/mediawiki.special.userlogin.signup.js +++ b/resources/src/mediawiki.special.userlogin.signup.js @@ -30,7 +30,7 @@ updateForCheckbox(); } ); - // Check if the username is invalid or already taken + // Check if the username is invalid or already taken; show username normalisation warning mw.hook( 'htmlform.enhance' ).add( function ( $root ) { var $usernameInput = $root.find( '#wpName2' ), $passwordInput = $root.find( '#wpPassword2' ), @@ -43,6 +43,10 @@ // We could just use .then() if we didn't have to pass on .abort()… var d, apiPromise; + // Leading/trailing/multiple whitespace characters are always stripped in usernames, + // this should not require a warning. We do warn about underscores. + username = username.replace( / +/g, ' ' ).trim(); + d = $.Deferred(); apiPromise = api.get( { action: 'query', @@ -68,6 +72,10 @@ return m.html; } ) : [] } ); + } else if ( userinfo.name !== username ) { + d.resolve( { valid: true, messages: [ + mw.message( 'createacct-normalization', username, userinfo.name ).parseDom() + ] } ); } else { d.resolve( { valid: true, messages: [] } ); }