From 237cc3bd0a89b73a43726c3aab8851daf8b35265 Mon Sep 17 00:00:00 2001 From: Brad Jorsch Date: Thu, 1 Dec 2016 17:29:29 -0500 Subject: [PATCH] API: Add action=validatepassword This will allow for checking passwords against the wiki's password policy from the account creation and password change forms. Bug: T111303 Change-Id: I0de281483bd83e47d80aa1ea37149d14f2ae5ebd --- RELEASE-NOTES-1.29 | 2 + autoload.php | 1 + docs/hooks.txt | 4 ++ includes/api/ApiMain.php | 1 + includes/api/ApiValidatePassword.php | 81 ++++++++++++++++++++++++++++ includes/api/i18n/en.json | 8 +++ includes/api/i18n/qqq.json | 7 +++ 7 files changed, 104 insertions(+) create mode 100644 includes/api/ApiValidatePassword.php diff --git a/RELEASE-NOTES-1.29 b/RELEASE-NOTES-1.29 index 3af1654c3f..10b152d2a3 100644 --- a/RELEASE-NOTES-1.29 +++ b/RELEASE-NOTES-1.29 @@ -75,6 +75,8 @@ production. 'stasherrors' rather than a 'stashfailed' text string. * action=watch reports 'errors' and 'warnings' instead of a single 'error', and no longer returns a 'message' on success. +* Added action=validatepassword to validate passwords for the account creation + and password change forms. === Action API internal changes in 1.29 === * New methods were added to ApiBase to handle errors and warnings using i18n diff --git a/autoload.php b/autoload.php index 941b3354e7..d85b6793c3 100644 --- a/autoload.php +++ b/autoload.php @@ -147,6 +147,7 @@ $wgAutoloadLocalClasses = [ 'ApiUpload' => __DIR__ . '/includes/api/ApiUpload.php', 'ApiUsageException' => __DIR__ . '/includes/api/ApiUsageException.php', 'ApiUserrights' => __DIR__ . '/includes/api/ApiUserrights.php', + 'ApiValidatePassword' => __DIR__ . '/includes/api/ApiValidatePassword.php', 'ApiWatch' => __DIR__ . '/includes/api/ApiWatch.php', 'ArchivedFile' => __DIR__ . '/includes/filerepo/file/ArchivedFile.php', 'ArrayDiffFormatter' => __DIR__ . '/includes/diff/ArrayDiffFormatter.php', diff --git a/docs/hooks.txt b/docs/hooks.txt index 1ecc1f82d8..862f9f0b4b 100644 --- a/docs/hooks.txt +++ b/docs/hooks.txt @@ -592,6 +592,10 @@ Use this hook to extend action=tokens with new token types. &$tokenTypes: supported token types in format 'type' => callback function used to retrieve this type of tokens. +'ApiValidatePassword': Called from ApiValidatePassword. +$module: ApiValidatePassword instance. +&$r: Result array. + 'Article::MissingArticleConditions': Before fetching deletion & move log entries to display a message of a non-existing page being deleted/moved, give extensions a chance to hide their (unrelated) log entries. diff --git a/includes/api/ApiMain.php b/includes/api/ApiMain.php index 54679a80a4..4220fb8d80 100644 --- a/includes/api/ApiMain.php +++ b/includes/api/ApiMain.php @@ -79,6 +79,7 @@ class ApiMain extends ApiBase { 'tokens' => 'ApiTokens', 'checktoken' => 'ApiCheckToken', 'cspreport' => 'ApiCSPReport', + 'validatepassword' => 'ApiValidatePassword', // Write modules 'purge' => 'ApiPurge', diff --git a/includes/api/ApiValidatePassword.php b/includes/api/ApiValidatePassword.php new file mode 100644 index 0000000000..6968523f28 --- /dev/null +++ b/includes/api/ApiValidatePassword.php @@ -0,0 +1,81 @@ +extractRequestParams(); + + // For sanity + $this->requirePostedParameters( [ 'password' ] ); + + if ( $params['user'] !== null ) { + $user = User::newFromName( $params['user'], 'creatable' ); + if ( !$user ) { + $encParamName = $this->encodeParamName( 'user' ); + $this->dieWithError( + [ 'apierror-baduser', $encParamName, wfEscapeWikiText( $params['user'] ) ], + "baduser_{$encParamName}" + ); + } + + if ( !$user->isAnon() || AuthManager::singleton()->userExists( $user->getName() ) ) { + $this->dieWithError( 'userexists' ); + } + + $user->setEmail( (string)$params['email'] ); + $user->setRealName( (string)$params['realname'] ); + } else { + $user = $this->getUser(); + } + + $validity = $user->checkPasswordValidity( $params['password'] ); + $r['validity'] = $validity->isGood() ? 'Good' : ( $validity->isOK() ? 'Change' : 'Invalid' ); + $messages = array_merge( + $this->getErrorFormatter()->arrayFromStatus( $validity, 'error' ), + $this->getErrorFormatter()->arrayFromStatus( $validity, 'warning' ) + ); + if ( $messages ) { + $r['validitymessages'] = $messages; + } + + Hooks::run( 'ApiValidatePassword', [ $this, &$r ] ); + + $this->getResult()->addValue( null, $this->getModuleName(), $r ); + } + + public function mustBePosted() { + return true; + } + + public function getAllowedParams() { + return [ + 'password' => [ + ApiBase::PARAM_TYPE => 'password', + ApiBase::PARAM_REQUIRED => true + ], + 'user' => [ + ApiBase::PARAM_TYPE => 'user', + ], + 'email' => null, + 'realname' => null, + ]; + } + + protected function getExamplesMessages() { + return [ + 'action=validatepassword&password=foobar' + => 'apihelp-validatepassword-example-1', + 'action=validatepassword&password=querty&user=Example' + => 'apihelp-validatepassword-example-2', + ]; + } + + public function getHelpUrls() { + return 'https://www.mediawiki.org/wiki/API:Validatepassword'; + } +} diff --git a/includes/api/i18n/en.json b/includes/api/i18n/en.json index d74889447d..f6eeffe880 100644 --- a/includes/api/i18n/en.json +++ b/includes/api/i18n/en.json @@ -1431,6 +1431,14 @@ "apihelp-userrights-example-user": "Add user FooBot to group bot, and remove from groups sysop and bureaucrat.", "apihelp-userrights-example-userid": "Add the user with ID 123 to group bot, and remove from groups sysop and bureaucrat.", + "apihelp-validatepassword-description": "Validate a password against the wiki's password policies.\n\nValidity is reported as Good if the password is acceptable, Change if the password may be used for login but must be changed, or Invalid if the password is not usable.", + "apihelp-validatepassword-param-password": "Password to validate.", + "apihelp-validatepassword-param-user": "User name, for use when testing account creation. The named user must not exist.", + "apihelp-validatepassword-param-email": "Email address, for use when testing account creation.", + "apihelp-validatepassword-param-realname": "Real name, for use when testing account creation.", + "apihelp-validatepassword-example-1": "Validate the password foobar for the current user.", + "apihelp-validatepassword-example-2": "Validate the password qwerty for creating user Example.", + "apihelp-watch-description": "Add or remove pages from the current user's watchlist.", "apihelp-watch-param-title": "The page to (un)watch. Use $1titles instead.", "apihelp-watch-param-unwatch": "If set the page will be unwatched rather than watched.", diff --git a/includes/api/i18n/qqq.json b/includes/api/i18n/qqq.json index 2bdc64a88c..1fbc3d0b65 100644 --- a/includes/api/i18n/qqq.json +++ b/includes/api/i18n/qqq.json @@ -1331,6 +1331,13 @@ "apihelp-userrights-param-reason": "{{doc-apihelp-param|userrights|reason}}", "apihelp-userrights-example-user": "{{doc-apihelp-example|userrights}}", "apihelp-userrights-example-userid": "{{doc-apihelp-example|userrights}}", + "apihelp-validatepassword-description": "{{doc-apihelp-description|validatepassword}}", + "apihelp-validatepassword-param-email": "{{doc-apihelp-param|validatepassword|email}}", + "apihelp-validatepassword-param-password": "{{doc-apihelp-param|validatepassword|password}}", + "apihelp-validatepassword-param-realname": "{{doc-apihelp-param|validatepassword|realname}}", + "apihelp-validatepassword-param-user": "{{doc-apihelp-param|validatepassword|user}}", + "apihelp-validatepassword-example-1": "{{doc-apihelp-example|validatepassword}}", + "apihelp-validatepassword-example-2": "{{doc-apihelp-example|validatepassword}}", "apihelp-watch-description": "{{doc-apihelp-description|watch}}", "apihelp-watch-param-title": "{{doc-apihelp-param|watch|title}}", "apihelp-watch-param-unwatch": "{{doc-apihelp-param|watch|unwatch}}", -- 2.20.1