/**
  * Return an instance with a new, random password
  * @return TemporaryPasswordAuthenticationRequest
  */
 public static function newRandom()
 {
     $config = \ConfigFactory::getDefaultInstance()->makeConfig('main');
     // get the min password length
     $minLength = $config->get('MinimalPasswordLength');
     $policy = $config->get('PasswordPolicy');
     foreach ($policy['policies'] as $p) {
         if (isset($p['MinimalPasswordLength'])) {
             $minLength = max($minLength, $p['MinimalPasswordLength']);
         }
         if (isset($p['MinimalPasswordLengthToLogin'])) {
             $minLength = max($minLength, $p['MinimalPasswordLengthToLogin']);
         }
     }
     $password = \PasswordFactory::generateRandomPasswordString($minLength);
     return new self($password);
 }
Пример #2
0
 public function execute()
 {
     $userName = $this->getArg(0);
     if (preg_match('/^#\\d+$/', $userName)) {
         $user = User::newFromId(substr($userName, 1));
     } else {
         $user = User::newFromName($userName);
     }
     if (!$user || !$user->getId() || !$user->loadFromId()) {
         $this->error("Error: user '{$userName}' does not exist\n", 1);
     }
     $email = $this->getArg(1);
     if (!Sanitizer::validateEmail($email)) {
         $this->error("Error: email '{$email}' is not valid\n", 1);
     }
     // Code from https://wikitech.wikimedia.org/wiki/Password_reset
     $user->setEmail($email);
     $user->setEmailAuthenticationTimestamp(wfTimestampNow());
     $user->saveSettings();
     // Kick whomever is currently controlling the account off
     $user->setPassword(PasswordFactory::generateRandomPasswordString(128));
 }
 /**
  * Test the account creation API with a valid request. Also
  * make sure the new account can log in and is valid.
  *
  * This test does multiple API requests so it might end up being
  * a bit slow. Raise the default timeout.
  * @group medium
  */
 public function testValid()
 {
     global $wgServer;
     if (!isset($wgServer)) {
         $this->markTestIncomplete('This test needs $wgServer to be set in LocalSettings.php');
     }
     $password = PasswordFactory::generateRandomPasswordString();
     $ret = $this->doApiRequest(array('action' => 'createaccount', 'name' => 'Apitestnew', 'password' => $password, 'email' => '*****@*****.**', 'realname' => 'Test Name'));
     $result = $ret[0];
     $this->assertNotInternalType('bool', $result);
     $this->assertNotInternalType('null', $result['createaccount']);
     // Should first ask for token.
     $a = $result['createaccount'];
     $this->assertEquals('NeedToken', $a['result']);
     $token = $a['token'];
     // Finally create the account
     $ret = $this->doApiRequest(array('action' => 'createaccount', 'name' => 'Apitestnew', 'password' => $password, 'token' => $token, 'email' => '*****@*****.**', 'realname' => 'Test Name'), $ret[2]);
     $result = $ret[0];
     $this->assertNotInternalType('bool', $result);
     $this->assertEquals('Success', $result['createaccount']['result']);
     // Try logging in with the new user.
     $ret = $this->doApiRequest(array('action' => 'login', 'lgname' => 'Apitestnew', 'lgpassword' => $password));
     $result = $ret[0];
     $this->assertNotInternalType('bool', $result);
     $this->assertNotInternalType('null', $result['login']);
     $a = $result['login']['result'];
     $this->assertEquals('NeedToken', $a);
     $token = $result['login']['token'];
     $ret = $this->doApiRequest(array('action' => 'login', 'lgtoken' => $token, 'lgname' => 'Apitestnew', 'lgpassword' => $password), $ret[2]);
     $result = $ret[0];
     $this->assertNotInternalType('bool', $result);
     $a = $result['login']['result'];
     $this->assertEquals('Success', $a);
     // log out to destroy the session
     $ret = $this->doApiRequest(array('action' => 'logout'), $ret[2]);
     $this->assertEquals(array(), $ret[0]);
 }
Пример #4
0
 /**
  * Return a random password.
  *
  * @deprecated since 1.27, use PasswordFactory::generateRandomPasswordString()
  * @return string New random password
  */
 public static function randomPassword()
 {
     global $wgMinimalPasswordLength;
     return PasswordFactory::generateRandomPasswordString($wgMinimalPasswordLength);
 }
Пример #5
0
 private function save(array $data)
 {
     $bp = BotPassword::newUnsaved(['centralId' => $this->userId, 'appId' => $this->par, 'restrictions' => MWRestrictions::newFromJson($data['restrictions']), 'grants' => array_merge(MWGrants::getHiddenGrants(), preg_replace('/^grant-/', '', $data['grants']))]);
     if ($this->operation === 'insert' || !empty($data['resetPassword'])) {
         $this->password = PasswordFactory::generateRandomPasswordString(max(32, $this->getConfig()->get('MinimalPasswordLength')));
         $passwordFactory = new PasswordFactory();
         $passwordFactory->init(RequestContext::getMain()->getConfig());
         $password = $passwordFactory->newFromPlaintext($this->password);
     } else {
         $password = null;
     }
     if ($bp->save($this->operation, $password)) {
         return Status::newGood();
     } else {
         // Messages: botpasswords-insert-failed, botpasswords-update-failed
         return Status::newFatal("botpasswords-{$this->operation}-failed", $this->par);
     }
 }
Пример #6
0
 /**
  * Process the form.  At this point we know that the user passes all the criteria in
  * userCanExecute(), and if the data array contains 'Username', etc, then Username
  * resets are allowed.
  * @param array $data
  * @throws MWException
  * @throws ThrottledError|PermissionsError
  * @return bool|array
  */
 public function onSubmit(array $data)
 {
     global $wgAuth, $wgMinimalPasswordLength;
     if (isset($data['Domain'])) {
         if ($wgAuth->validDomain($data['Domain'])) {
             $wgAuth->setDomain($data['Domain']);
         } else {
             $wgAuth->setDomain('invaliddomain');
         }
     }
     if (isset($data['Capture']) && !$this->getUser()->isAllowed('passwordreset')) {
         // The user knows they don't have the passwordreset permission,
         // but they tried to spoof the form. That's naughty
         throw new PermissionsError('passwordreset');
     }
     /**
      * @var $firstUser User
      * @var $users User[]
      */
     if (isset($data['Username']) && $data['Username'] !== '') {
         $method = 'username';
         $users = [User::newFromName($data['Username'])];
     } elseif (isset($data['Email']) && $data['Email'] !== '' && Sanitizer::validateEmail($data['Email'])) {
         $method = 'email';
         $res = wfGetDB(DB_SLAVE)->select('user', User::selectFields(), ['user_email' => $data['Email']], __METHOD__);
         if ($res) {
             $users = [];
             foreach ($res as $row) {
                 $users[] = User::newFromRow($row);
             }
         } else {
             // Some sort of database error, probably unreachable
             throw new MWException('Unknown database error in ' . __METHOD__);
         }
     } else {
         // The user didn't supply any data
         return false;
     }
     // Check for hooks (captcha etc), and allow them to modify the users list
     $error = [];
     if (!Hooks::run('SpecialPasswordResetOnSubmit', [&$users, $data, &$error])) {
         return [$error];
     }
     $this->method = $method;
     if (count($users) == 0) {
         if ($method == 'email') {
             // Don't reveal whether or not an email address is in use
             return true;
         } else {
             return ['noname'];
         }
     }
     $firstUser = $users[0];
     if (!$firstUser instanceof User || !$firstUser->getId()) {
         // Don't parse username as wikitext (bug 65501)
         return [['nosuchuser', wfEscapeWikiText($data['Username'])]];
     }
     // Check against the rate limiter
     if ($this->getUser()->pingLimiter('mailpassword')) {
         throw new ThrottledError();
     }
     // Check against password throttle
     foreach ($users as $user) {
         if ($user->isPasswordReminderThrottled()) {
             # Round the time in hours to 3 d.p., in case someone is specifying
             # minutes or seconds.
             return [['throttled-mailpassword', round($this->getConfig()->get('PasswordReminderResendTime'), 3)]];
         }
     }
     // All the users will have the same email address
     if ($firstUser->getEmail() == '') {
         // This won't be reachable from the email route, so safe to expose the username
         return [['noemail', wfEscapeWikiText($firstUser->getName())]];
     }
     // We need to have a valid IP address for the hook, but per bug 18347, we should
     // send the user's name if they're logged in.
     $ip = $this->getRequest()->getIP();
     if (!$ip) {
         return ['badipaddress'];
     }
     $caller = $this->getUser();
     Hooks::run('User::mailPasswordInternal', [&$caller, &$ip, &$firstUser]);
     $username = $caller->getName();
     $msg = IP::isValid($username) ? 'passwordreset-emailtext-ip' : 'passwordreset-emailtext-user';
     // Send in the user's language; which should hopefully be the same
     $userLanguage = $firstUser->getOption('language');
     $passwords = [];
     foreach ($users as $user) {
         $password = PasswordFactory::generateRandomPasswordString($wgMinimalPasswordLength);
         $user->setNewpassword($password);
         $user->saveSettings();
         $passwords[] = $this->msg('passwordreset-emailelement', $user->getName(), $password)->inLanguage($userLanguage)->text();
         // We'll escape the whole thing later
     }
     $passwordBlock = implode("\n\n", $passwords);
     $this->email = $this->msg($msg)->inLanguage($userLanguage);
     $this->email->params($username, $passwordBlock, count($passwords), '<' . Title::newMainPage()->getCanonicalURL() . '>', round($this->getConfig()->get('NewPasswordExpiry') / 86400));
     $title = $this->msg('passwordreset-emailtitle')->inLanguage($userLanguage);
     $this->result = $firstUser->sendMail($title->text(), $this->email->text());
     if (isset($data['Capture']) && $data['Capture']) {
         // Save the user, will be used if an error occurs when sending the email
         $this->firstUser = $firstUser;
     } else {
         // Blank the email if the user is not supposed to see it
         $this->email = null;
     }
     if ($this->result->isGood()) {
         return true;
     } elseif (isset($data['Capture']) && $data['Capture']) {
         // The email didn't send, but maybe they knew that and that's why they captured it
         return true;
     } else {
         // @todo FIXME: The email wasn't sent, but we have already set
         // the password throttle timestamp, so they won't be able to try
         // again until it expires...  :(
         return [['mailerror', $this->result->getMessage()]];
     }
 }
Пример #7
0
 /**
  * @param User $u
  * @param bool $throttle
  * @param string $emailTitle Message name of email title
  * @param string $emailText Message name of email text
  * @return Status
  */
 function mailPasswordInternal($u, $throttle = true, $emailTitle = 'passwordremindertitle', $emailText = 'passwordremindertext')
 {
     global $wgNewPasswordExpiry, $wgMinimalPasswordLength;
     if ($u->getEmail() == '') {
         return Status::newFatal('noemail', $u->getName());
     }
     $ip = $this->getRequest()->getIP();
     if (!$ip) {
         return Status::newFatal('badipaddress');
     }
     $currentUser = $this->getUser();
     Hooks::run('User::mailPasswordInternal', [&$currentUser, &$ip, &$u]);
     $np = PasswordFactory::generateRandomPasswordString($wgMinimalPasswordLength);
     $u->setNewpassword($np, $throttle);
     $u->saveSettings();
     $userLanguage = $u->getOption('language');
     $mainPage = Title::newMainPage();
     $mainPageUrl = $mainPage->getCanonicalURL();
     $m = $this->msg($emailText, $ip, $u->getName(), $np, '<' . $mainPageUrl . '>', round($wgNewPasswordExpiry / 86400))->inLanguage($userLanguage)->text();
     $result = $u->sendMail($this->msg($emailTitle)->inLanguage($userLanguage)->text(), $m);
     return $result;
 }
Пример #8
0
 /**
  * Returns a (raw, unhashed) random password string.
  * @param Config $config
  * @return string
  */
 public static function generatePassword($config)
 {
     return PasswordFactory::generateRandomPasswordString(max(32, $config->get('MinimalPasswordLength')));
 }