Merge pull request #6356 from MrPetovan/task/6355-add-password-rules

Add password rules
This commit is contained in:
Tobias Diekershoff 2019-01-10 10:37:32 +01:00 committed by GitHub
commit 6bc865ff4d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 1799 additions and 1723 deletions

View File

@ -17,6 +17,7 @@
"ext-curl": "*", "ext-curl": "*",
"ext-dom": "*", "ext-dom": "*",
"ext-json": "*", "ext-json": "*",
"ext-openssl": "*",
"ext-xml": "*", "ext-xml": "*",
"asika/simple-console": "^1.0", "asika/simple-console": "^1.0",
"divineomega/password_exposed": "^2.4", "divineomega/password_exposed": "^2.4",

View File

@ -391,35 +391,23 @@ function settings_post(App $a)
$newpass = $_POST['password']; $newpass = $_POST['password'];
$confirm = $_POST['confirm']; $confirm = $_POST['confirm'];
$err = false; try {
if ($newpass != $confirm) { if ($newpass != $confirm) {
notice(L10n::t('Passwords do not match. Password unchanged.') . EOL); throw new Exception(L10n::t('Passwords do not match.'));
$err = true;
}
if (empty($newpass) || empty($confirm)) {
notice(L10n::t('Empty passwords are not allowed. Password unchanged.') . EOL);
$err = true;
}
if (!Config::get('system', 'disable_password_exposed', false) && User::isPasswordExposed($newpass)) {
notice(L10n::t('The new password has been exposed in a public data dump, please choose another.') . EOL);
$err = true;
} }
// check if the old password was supplied correctly before changing it to the new value // check if the old password was supplied correctly before changing it to the new value
if (!User::authenticate(intval(local_user()), $_POST['opassword'])) { User::getIdFromPasswordAuthentication(local_user(), $_POST['opassword']);
notice(L10n::t('Wrong password.') . EOL);
$err = true; $result = User::updatePassword(local_user(), $newpass);
if (!DBA::isResult($result)) {
throw new Exception(L10n::t('Password update failed. Please try again.'));
} }
if (!$err) { info(L10n::t('Password changed.'));
$result = User::updatePassword(local_user(), $newpass); } catch (Exception $e) {
if (DBA::isResult($result)) { notice($e->getMessage());
info(L10n::t('Password changed.') . EOL); notice(L10n::t('Password unchanged.'));
} else {
notice(L10n::t('Password update failed. Please try again.') . EOL);
}
} }
} }
@ -1193,7 +1181,7 @@ function settings_content(App $a)
'$nickname_block' => $prof_addr, '$nickname_block' => $prof_addr,
'$h_pass' => L10n::t('Password Settings'), '$h_pass' => L10n::t('Password Settings'),
'$password1'=> ['password', L10n::t('New Password:'), '', ''], '$password1'=> ['password', L10n::t('New Password:'), '', L10n::t('Allowed characters are a-z, A-Z, 0-9 and special characters except white spaces, accentuated letters and colon (:).')],
'$password2'=> ['confirm', L10n::t('Confirm:'), '', L10n::t('Leave password fields blank unless changing')], '$password2'=> ['confirm', L10n::t('Confirm:'), '', L10n::t('Leave password fields blank unless changing')],
'$password3'=> ['opassword', L10n::t('Current Password:'), '', L10n::t('Your current password to confirm the changes')], '$password3'=> ['opassword', L10n::t('Current Password:'), '', L10n::t('Your current password to confirm the changes')],
'$password4'=> ['mpassword', L10n::t('Password:'), '', L10n::t('Your current password to confirm the changes')], '$password4'=> ['mpassword', L10n::t('Password:'), '', L10n::t('Your current password to confirm the changes')],

View File

@ -2,7 +2,6 @@
namespace Friendica\Core\Console; namespace Friendica\Core\Console;
use Friendica\Core\Config;
use Friendica\Core\L10n; use Friendica\Core\L10n;
use Friendica\Database\DBA; use Friendica\Database\DBA;
use Friendica\Model\User; use Friendica\Model\User;
@ -74,19 +73,17 @@ HELP;
$password = \Seld\CliPrompt\CliPrompt::hiddenPrompt(true); $password = \Seld\CliPrompt\CliPrompt::hiddenPrompt(true);
} }
if (!$password) { try {
throw new RuntimeException(L10n::t('Password can\'t be empty')); $result = User::updatePassword($user['uid'], $password);
}
if (!Config::get('system', 'disable_password_exposed', false) && User::isPasswordExposed($password)) { if (!DBA::isResult($result)) {
throw new RuntimeException(L10n::t('The new password has been exposed in a public data dump, please choose another.')); throw new \Exception(L10n::t('Password update failed. Please try again.'));
}
if (!User::updatePassword($user['uid'], $password)) {
throw new RuntimeException(L10n::t('Password update failed. Please try again.'));
} }
$this->out(L10n::t('Password changed.')); $this->out(L10n::t('Password changed.'));
} catch (\Exception $e) {
throw new RuntimeException($e->getMessage(), $e->getCode(), $e);
}
return 0; return 0;
} }

View File

@ -192,7 +192,7 @@ class User
if (strpos($user['password'], '$') === false) { if (strpos($user['password'], '$') === false) {
//Legacy hash that has not been replaced by a new hash yet //Legacy hash that has not been replaced by a new hash yet
if (self::hashPasswordLegacy($password) === $user['password']) { if (self::hashPasswordLegacy($password) === $user['password']) {
self::updatePassword($user['uid'], $password); self::updatePasswordHashed($user['uid'], self::hashPassword($password));
return $user['uid']; return $user['uid'];
} }
@ -200,14 +200,14 @@ class User
//Legacy hash that has been double-hashed and not replaced by a new hash yet //Legacy hash that has been double-hashed and not replaced by a new hash yet
//Warning: `legacy_password` is not necessary in sync with the content of `password` //Warning: `legacy_password` is not necessary in sync with the content of `password`
if (password_verify(self::hashPasswordLegacy($password), $user['password'])) { if (password_verify(self::hashPasswordLegacy($password), $user['password'])) {
self::updatePassword($user['uid'], $password); self::updatePasswordHashed($user['uid'], self::hashPassword($password));
return $user['uid']; return $user['uid'];
} }
} elseif (password_verify($password, $user['password'])) { } elseif (password_verify($password, $user['password'])) {
//New password hash //New password hash
if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) { if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) {
self::updatePassword($user['uid'], $password); self::updatePasswordHashed($user['uid'], self::hashPassword($password));
} }
return $user['uid']; return $user['uid'];
@ -280,7 +280,7 @@ class User
*/ */
public static function generateNewPassword() public static function generateNewPassword()
{ {
return Strings::getRandomName(6) . mt_rand(100, 9999); return ucfirst(Strings::getRandomName(8)) . mt_rand(1000, 9999);
} }
/** /**
@ -317,6 +317,7 @@ class User
* *
* @param string $password * @param string $password
* @return string * @return string
* @throws Exception
*/ */
public static function hashPassword($password) public static function hashPassword($password)
{ {
@ -333,9 +334,26 @@ class User
* @param int $uid * @param int $uid
* @param string $password * @param string $password
* @return bool * @return bool
* @throws Exception
*/ */
public static function updatePassword($uid, $password) public static function updatePassword($uid, $password)
{ {
$password = trim($password);
if (empty($password)) {
throw new Exception(L10n::t('Empty passwords are not allowed.'));
}
if (!Config::get('system', 'disable_password_exposed', false) && self::isPasswordExposed($password)) {
throw new Exception(L10n::t('The new password has been exposed in a public data dump, please choose another.'));
}
$allowed_characters = '!"#$%&\'()*+,-./;<=>?@[\]^_`{|}~';
if (!preg_match('/^[a-z0-9' . preg_quote($allowed_characters, '/') . ']+$/i', $password)) {
throw new Exception(L10n::t('The password can\'t contain accentuated letters, white spaces or colons (:)'));
}
return self::updatePasswordHashed($uid, self::hashPassword($password)); return self::updatePasswordHashed($uid, self::hashPassword($password));
} }
@ -401,8 +419,10 @@ class User
* - Create profile image * - Create profile image
* *
* @param array $data * @param array $data
* @return string * @return array
* @throw Exception * @throws \ErrorException
* @throws \Friendica\Network\HTTPException\InternalServerErrorException
* @throws Exception
*/ */
public static function create(array $data) public static function create(array $data)
{ {

File diff suppressed because it is too large Load Diff