X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;ds=sidebyside;f=src%2FModel%2FUser.php;h=39c544c3a8786f62053093ec1c4ff734d5eb4c4f;hb=9ea6d4b26d4375502c567276705dff2ff678122e;hp=c8409b58431d6106069281338332a73b4263b642;hpb=236616995b64728d2d5efc889e3f917e6b3c78f4;p=friendica.git diff --git a/src/Model/User.php b/src/Model/User.php index c8409b5843..39c544c3a8 100644 --- a/src/Model/User.php +++ b/src/Model/User.php @@ -5,10 +5,11 @@ */ namespace Friendica\Model; +use DivineOmega\PasswordExposed\PasswordStatus; use Friendica\Core\Addon; use Friendica\Core\Config; -use Friendica\Core\PConfig; use Friendica\Core\L10n; +use Friendica\Core\PConfig; use Friendica\Core\System; use Friendica\Core\Worker; use Friendica\Database\DBM; @@ -17,9 +18,12 @@ use Friendica\Model\Group; use Friendica\Model\Photo; use Friendica\Object\Image; use Friendica\Util\Crypto; +use Friendica\Util\DateTimeFormat; use Friendica\Util\Network; use dba; use Exception; +use LightOpenID; +use function password_exposed; require_once 'boot.php'; require_once 'include/dba.php'; @@ -92,64 +96,54 @@ class User /** - * @brief Authenticate a user with a clear text password - * - * User info can be any of the following: - * - User DB object - * - User Id - * - User email or username or nickname - * - User array with at least the uid and the hashed password + * Authenticate a user with a clear text password * + * @brief Authenticate a user with a clear text password * @param mixed $user_info * @param string $password - * @return boolean + * @return int|boolean + * @deprecated since version 3.6 + * @see User::getIdFromPasswordAuthentication() */ public static function authenticate($user_info, $password) { - if (is_object($user_info)) { - $user = (array) $user_info; - } elseif (is_int($user_info)) { - $user = dba::selectFirst('user', ['uid', 'password', 'legacy_password'], - [ - 'uid' => $user_info, - 'blocked' => 0, - 'account_expired' => 0, - 'account_removed' => 0, - 'verified' => 1 - ] - ); - } elseif (is_string($user_info)) { - $user = dba::fetch_first('SELECT `uid`, `password`, `legacy_password` - FROM `user` - WHERE (`email` = ? OR `username` = ? OR `nickname` = ?) - AND `blocked` = 0 - AND `account_expired` = 0 - AND `account_removed` = 0 - AND `verified` = 1 - LIMIT 1', - $user_info, - $user_info, - $user_info - ); - } else { - $user = $user_info; + try { + return self::getIdFromPasswordAuthentication($user_info, $password); + } catch (Exception $ex) { + return false; } + } - if (!DBM::is_result($user) - || !isset($user['uid']) - || !isset($user['password']) - || !isset($user['legacy_password']) - ) { - throw new Exception('Not enough information to authenticate'); - } + /** + * Returns the user id associated with a successful password authentication + * + * @brief Authenticate a user with a clear text password + * @param mixed $user_info + * @param string $password + * @return int User Id if authentication is successful + * @throws Exception + */ + public static function getIdFromPasswordAuthentication($user_info, $password) + { + $user = self::getAuthenticationInfo($user_info); - if ($user['legacy_password']) { + if (strpos($user['password'], '$') === false) { + //Legacy hash that has not been replaced by a new hash yet + if (self::hashPasswordLegacy($password) === $user['password']) { + self::updatePassword($user['uid'], $password); + + return $user['uid']; + } + } elseif (!empty($user['legacy_password'])) { + //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` if (password_verify(self::hashPasswordLegacy($password), $user['password'])) { self::updatePassword($user['uid'], $password); return $user['uid']; } } elseif (password_verify($password, $user['password'])) { + //New password hash if (password_needs_rehash($user['password'], PASSWORD_DEFAULT)) { self::updatePassword($user['uid'], $password); } @@ -157,7 +151,71 @@ class User return $user['uid']; } - return false; + throw new Exception(L10n::t('Login failed')); + } + + /** + * Returns authentication info from various parameters types + * + * User info can be any of the following: + * - User DB object + * - User Id + * - User email or username or nickname + * - User array with at least the uid and the hashed password + * + * @param mixed $user_info + * @return array + * @throws Exception + */ + private static function getAuthenticationInfo($user_info) + { + $user = null; + + if (is_object($user_info) || is_array($user_info)) { + if (is_object($user_info)) { + $user = (array) $user_info; + } else { + $user = $user_info; + } + + if (!isset($user['uid']) + || !isset($user['password']) + || !isset($user['legacy_password']) + ) { + throw new Exception(L10n::t('Not enough information to authenticate')); + } + } elseif (is_int($user_info) || is_string($user_info)) { + if (is_int($user_info)) { + $user = dba::selectFirst('user', ['uid', 'password', 'legacy_password'], + [ + 'uid' => $user_info, + 'blocked' => 0, + 'account_expired' => 0, + 'account_removed' => 0, + 'verified' => 1 + ] + ); + } else { + $user = dba::fetch_first('SELECT `uid`, `password`, `legacy_password` + FROM `user` + WHERE (`email` = ? OR `username` = ? OR `nickname` = ?) + AND `blocked` = 0 + AND `account_expired` = 0 + AND `account_removed` = 0 + AND `verified` = 1 + LIMIT 1', + $user_info, + $user_info, + $user_info + ); + } + + if (!DBM::is_result($user)) { + throw new Exception(L10n::t('User not found')); + } + } + + return $user; } /** @@ -170,6 +228,17 @@ class User return autoname(6) . mt_rand(100, 9999); } + /** + * Checks if the provided plaintext password has been exposed or not + * + * @param string $password + * @return bool + */ + public static function isPasswordExposed($password) + { + return password_exposed($password) === PasswordStatus::EXPOSED; + } + /** * Legacy hashing function, kept for password migration purposes * @@ -189,6 +258,10 @@ class User */ public static function hashPassword($password) { + if (!trim($password)) { + throw new Exception(L10n::t('Password can\'t be empty')); + } + return password_hash($password, PASSWORD_DEFAULT); } @@ -258,6 +331,7 @@ class User $confirm = x($data, 'confirm') ? trim($data['confirm']) : ''; $blocked = x($data, 'blocked') ? intval($data['blocked']) : 0; $verified = x($data, 'verified') ? intval($data['verified']) : 0; + $language = x($data, 'language') ? notags(trim($data['language'])) : 'en'; $publish = x($data, 'profile_publish_reg') && intval($data['profile_publish_reg']) ? 1 : 0; $netpublish = strlen(Config::get('system', 'directory')) ? $publish : 0; @@ -286,7 +360,7 @@ class User $_SESSION['register'] = 1; $_SESSION['openid'] = $openid_url; - $openid = new \LightOpenID; + $openid = new LightOpenID($a->get_hostname()); $openid->identity = $openid_url; $openid->returnUrl = System::baseUrl() . '/openid'; $openid->required = ['namePerson/friendly', 'contact/email', 'namePerson']; @@ -336,7 +410,7 @@ class User throw new Exception(L10n::t('Not a valid email address.')); } - if (dba::exists('user', ['email' => $email])) { + if (Config::get('system', 'block_extended_register', false) && dba::exists('user', ['email' => $email])) { throw new Exception(L10n::t('Cannot use that email.')); } @@ -393,8 +467,9 @@ class User 'sprvkey' => $sprvkey, 'verified' => $verified, 'blocked' => $blocked, + 'language' => $language, 'timezone' => 'UTC', - 'register_date' => datetime_convert(), + 'register_date' => DateTimeFormat::utcNow(), 'default-location' => '' ]); @@ -475,7 +550,7 @@ class User if ($Image->isValid()) { $Image->scaleToSquare(175); - $hash = photo_new_resource(); + $hash = Photo::newResource(); $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 4); @@ -555,11 +630,12 @@ class User ')); $body = deindent(L10n::t(' The login details are as follows: - Site Location: %3$s - Login Name: %1$s - Password: %5$s - You may change your password from your account Settings page after logging + Site Location: %3$s + Login Name: %1$s + Password: %5$s + + You may change your password from your account "Settings" page after logging in. Please take a few moments to review the other account settings on that page. @@ -568,7 +644,7 @@ class User ' . "\x28" . 'on the "Profiles" page' . "\x29" . ' so that other people can easily find you. We recommend setting your full name, adding a profile photo, - adding some profile keywords ' . "\x28" . 'very useful in making new friends' . "\x29" . ' - and + adding some profile "keywords" ' . "\x28" . 'very useful in making new friends' . "\x29" . ' - and perhaps what country you live in; if you do not wish to be more specific than that. @@ -576,6 +652,7 @@ class User If you are new and do not know anybody here, they may help you to make some new and interesting friends. + If you ever want to delete your account, you can do so at %3$s/removeme Thank you and welcome to %2$s.')); @@ -611,7 +688,7 @@ class User dba::insert('userd', ['username' => $user['nickname']]); // The user and related data will be deleted in "cron_expire_and_remove_users" (cronjobs.php) - dba::update('user', ['account_removed' => true, 'account_expires_on' => datetime_convert()], ['uid' => $uid]); + dba::update('user', ['account_removed' => true, 'account_expires_on' => DateTimeFormat::utcNow()], ['uid' => $uid]); Worker::add(PRIORITY_HIGH, "Notifier", "removeme", $uid); // Send an update to the directory