From f39e1230c5a413343ce33c979fad7e6430d8a339 Mon Sep 17 00:00:00 2001 From: flashwave <me@flash.moe> Date: Sun, 9 Feb 2025 00:26:12 +0000 Subject: [PATCH] Moved passwords out of the users table. --- ..._moved_passwords_out_of_the_user_table.php | 33 ++++++++ public-legacy/auth/login.php | 23 ++++-- public-legacy/auth/password.php | 8 +- public-legacy/auth/register.php | 10 +-- public-legacy/manage/users/user.php | 8 +- public-legacy/settings/account.php | 12 +-- public-legacy/settings/data.php | 5 +- src/Users/UserInfo.php | 36 +++------ src/Users/UserPasswordInfo.php | 33 ++++++++ src/Users/UserPasswordsData.php | 80 +++++++++++++++++++ src/Users/UserTotpsData.php | 2 +- src/Users/UsersContext.php | 2 + src/Users/UsersData.php | 47 ++--------- 13 files changed, 202 insertions(+), 97 deletions(-) create mode 100644 database/2025_02_08_235046_moved_passwords_out_of_the_user_table.php create mode 100644 src/Users/UserPasswordInfo.php create mode 100644 src/Users/UserPasswordsData.php diff --git a/database/2025_02_08_235046_moved_passwords_out_of_the_user_table.php b/database/2025_02_08_235046_moved_passwords_out_of_the_user_table.php new file mode 100644 index 00000000..4e900324 --- /dev/null +++ b/database/2025_02_08_235046_moved_passwords_out_of_the_user_table.php @@ -0,0 +1,33 @@ +<?php +use Index\Db\DbConnection; +use Index\Db\Migration\DbMigration; + +final class MovedPasswordsOutOfTheUserTable_20250208_235046 implements DbMigration { + public function migrate(DbConnection $conn): void { + $conn->execute(<<<SQL + CREATE TABLE msz_users_passwords ( + user_id INT(10) UNSIGNED NOT NULL, + password_hash VARCHAR(255) NOT NULL COLLATE 'ascii_bin', + password_created TIMESTAMP NOT NULL DEFAULT current_timestamp(), + PRIMARY KEY (user_id), + CONSTRAINT users_passwords_users_foreign + FOREIGN KEY (user_id) + REFERENCES msz_users (user_id) + ON UPDATE CASCADE + ON DELETE CASCADE + ) COLLATE='utf8mb4_bin'; + SQL); + + $conn->execute(<<<SQL + INSERT msz_users_passwords + SELECT user_id, user_password, NOW() + FROM msz_users + WHERE user_password IS NOT NULL AND TRIM(user_password) <> '' + SQL); + + $conn->execute(<<<SQL + ALTER TABLE msz_users + DROP COLUMN user_password; + SQL); + } +} diff --git a/public-legacy/auth/login.php b/public-legacy/auth/login.php index 613b914d..6c0f4eca 100644 --- a/public-legacy/auth/login.php +++ b/public-legacy/auth/login.php @@ -98,19 +98,26 @@ while(!empty($_POST['login']) && is_array($_POST['login'])) { break; } - if(!$userInfo->hasPasswordHash) { - $notices[] = 'Your password has been invalidated, please reset it.'; - break; - } - - if($userInfo->deleted || !$userInfo->verifyPassword($_POST['login']['password'])) { + if($userInfo->deleted) { $msz->authCtx->loginAttempts->recordAttempt(false, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo); $notices[] = $loginFailedError; break; } - if($userInfo->passwordNeedsRehash) - $msz->usersCtx->users->updateUser($userInfo, password: $_POST['login']['password']); + $pwInfo = $msz->usersCtx->passwords->getUserPassword($userInfo); + if($pwInfo === null) { + $notices[] = 'Your password has been invalidated, please reset it.'; + break; + } + + if(!$pwInfo->verifyPassword($_POST['login']['password'])) { + $msz->authCtx->loginAttempts->recordAttempt(false, $ipAddress, $countryCode, $userAgent, $clientInfo, $userInfo); + $notices[] = $loginFailedError; + break; + } + + if($pwInfo->needsRehash) + $msz->usersCtx->passwords->updateUserPassword($userInfo, $_POST['login']['password']); if(!empty($loginPermCat) && $loginPermVal > 0 && !$msz->perms->checkPermissions($loginPermCat, $loginPermVal, $userInfo)) { $notices[] = "Login succeeded, but you're not allowed to browse the site right now."; diff --git a/public-legacy/auth/password.php b/public-legacy/auth/password.php index 2d4c55f1..2c3936ff 100644 --- a/public-legacy/auth/password.php +++ b/public-legacy/auth/password.php @@ -2,7 +2,7 @@ namespace Misuzu; use RuntimeException; -use Misuzu\Users\User; +use Misuzu\Users\{User,UserPasswordsData}; if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext)) die('Script must be called through the Misuzu route dispatcher.'); @@ -63,15 +63,15 @@ while($canResetPassword) { break; } - $passwordValidation = $msz->usersCtx->users->validatePassword($passwordNew); + $passwordValidation = UserPasswordsData::validateUserPassword($passwordNew); if($passwordValidation !== '') { - $notices[] = $msz->usersCtx->users->validatePasswordText($passwordValidation); + $notices[] = UserPasswordsData::validateUserPasswordText($passwordValidation); break; } // also disables two factor auth to prevent getting locked out of account entirely // this behaviour should really be replaced with recovery keys... - $msz->usersCtx->users->updateUser($userInfo, password: $passwordNew); + $msz->usersCtx->passwords->updateUserPassword($userInfo, $passwordNew); $msz->usersCtx->totps->deleteUserTotp($userInfo); $msz->createAuditLog('PASSWORD_RESET', [], $userInfo); diff --git a/public-legacy/auth/register.php b/public-legacy/auth/register.php index b273db39..0b58127c 100644 --- a/public-legacy/auth/register.php +++ b/public-legacy/auth/register.php @@ -2,7 +2,7 @@ namespace Misuzu; use RuntimeException; -use Misuzu\Users\User; +use Misuzu\Users\{User,UserPasswordsData}; if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext)) die('Script must be called through the Misuzu route dispatcher.'); @@ -61,11 +61,11 @@ while(!empty($register)) { $notices[] = $msz->usersCtx->users->validateEMailAddressText($emailValidation); if($register['password_confirm'] !== $register['password']) - $notices[] = 'The given passwords don\'t match.'; + $notices[] = "The given passwords don't match."; - $passwordValidation = $msz->usersCtx->users->validatePassword($register['password']); + $passwordValidation = UserPasswordsData::validateUserPassword($register['password']); if($passwordValidation !== '') - $notices[] = $msz->usersCtx->users->validatePasswordText($passwordValidation); + $notices[] = UserPasswordsData::validateUserPasswordText($passwordValidation); if(!empty($notices)) break; @@ -75,12 +75,12 @@ while(!empty($register)) { try { $userInfo = $msz->usersCtx->users->createUser( $register['username'], - $register['password'], $register['email'], $ipAddress, $countryCode, $defaultRoleInfo ); + $msz->usersCtx->passwords->updateUserPassword($userInfo, $register['password']); } catch(RuntimeException $ex) { $notices[] = 'Something went wrong while creating your account, please alert an administrator or a developer about this!'; break; diff --git a/public-legacy/manage/users/user.php b/public-legacy/manage/users/user.php index 4d13272d..5e837bb7 100644 --- a/public-legacy/manage/users/user.php +++ b/public-legacy/manage/users/user.php @@ -5,7 +5,7 @@ use RuntimeException; use Index\Colour\Colour; use Misuzu\Perm; use Misuzu\Auth\AuthTokenCookie; -use Misuzu\Users\User; +use Misuzu\Users\{User,UserPasswordsData}; if(!isset($msz) || !($msz instanceof \Misuzu\MisuzuContext)) die('Script must be called through the Misuzu route dispatcher.'); @@ -190,13 +190,13 @@ if(CSRF::validateRequest() && $canEdit) { if($passwordNewValue !== $passwordConfirmValue) $notices[] = 'Confirm password does not match.'; else { - $passwordValidation = $msz->usersCtx->users->validatePassword($passwordNewValue); + $passwordValidation = UserPasswordsData::validateUserPassword($passwordNewValue); if($passwordValidation !== '') - $notices[] = $msz->usersCtx->users->validatePasswordText($passwordValidation); + $notices[] = UserPasswordsData::validateUserPasswordText($passwordValidation); } if(empty($notices)) - $msz->usersCtx->users->updateUser(userInfo: $userInfo, password: $passwordNewValue); + $msz->usersCtx->passwords->updateUserPassword($userInfo, $passwordNewValue); } } diff --git a/public-legacy/settings/account.php b/public-legacy/settings/account.php index 77fab736..98a4e7d7 100644 --- a/public-legacy/settings/account.php +++ b/public-legacy/settings/account.php @@ -2,7 +2,7 @@ namespace Misuzu; use RuntimeException; -use Misuzu\Users\User; +use Misuzu\Users\{User,UserPasswordsData}; use chillerlan\QRCode\QRCode; use chillerlan\QRCode\QROptions; @@ -50,7 +50,7 @@ if(!$isRestricted && $isVerifiedRequest && !empty($_POST['role'])) { if($isVerifiedRequest && isset($_POST['tfa']['enable']) && $msz->usersCtx->totps->hasUserTotp($userInfo) !== (bool)$_POST['tfa']['enable']) { if((bool)$_POST['tfa']['enable']) { - $totpInfo = $msz->usersCtx->totps->createUserTotp($userInfo); + $totpInfo = $msz->usersCtx->totps->updateUserTotp($userInfo); $totpSecret = $totpInfo->encodedSecret; $totpIssuer = $msz->siteInfo->name; $totpQrcode = (new QRCode(new QROptions([ @@ -74,7 +74,7 @@ if($isVerifiedRequest && isset($_POST['tfa']['enable']) && $msz->usersCtx->totps } if($isVerifiedRequest && !empty($_POST['current_password'])) { - if(!$userInfo->verifyPassword($_POST['current_password'] ?? '')) { + if(!$msz->usersCtx->passwords->getUserPassword($userInfo)?->verifyPassword($_POST['current_password'] ?? '')) { $errors[] = 'Your password was incorrect.'; } else { // Changing e-mail @@ -100,12 +100,12 @@ if($isVerifiedRequest && !empty($_POST['current_password'])) { if(empty($_POST['password']['confirm']) || $_POST['password']['new'] !== $_POST['password']['confirm']) { $errors[] = 'The new passwords you entered did not match each other.'; } else { - $checkPassword = $msz->usersCtx->users->validatePassword($_POST['password']['new']); + $checkPassword = UserPasswordsData::validateUserPassword($_POST['password']['new']); if($checkPassword !== '') { - $errors[] = $msz->usersCtx->users->validatePasswordText($checkPassword); + $errors[] = UserPasswordsData::validateUserPasswordText($checkPassword); } else { - $msz->usersCtx->users->updateUser(userInfo: $userInfo, password: $_POST['password']['new']); + $msz->usersCtx->passwords->updateUserPassword($userInfo, $_POST['password']['new']); $msz->createAuditLog('PERSONAL_PASSWORD_CHANGE'); } } diff --git a/public-legacy/settings/data.php b/public-legacy/settings/data.php index 94bf64d5..50f7efc0 100644 --- a/public-legacy/settings/data.php +++ b/public-legacy/settings/data.php @@ -111,7 +111,7 @@ $userInfo = $msz->authInfo->userInfo; if(isset($_POST['action']) && is_string($_POST['action'])) { if(isset($_POST['password']) && is_string($_POST['password']) - && ($userInfo->verifyPassword($_POST['password'] ?? ''))) { + && ($msz->usersCtx->passwords->getUserPassword($userInfo)?->verifyPassword($_POST['password'] ?? ''))) { switch($_POST['action']) { case 'data': $msz->createAuditLog('PERSONAL_DATA_DOWNLOAD'); @@ -151,9 +151,10 @@ if(isset($_POST['action']) && is_string($_POST['action'])) { $tmpFiles[] = db_to_zip($archive, $userInfo, 'profile_backgrounds', ['user_id:s', 'bg_attach:s', 'bg_blend:i', 'bg_slide:i']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'profile_fields_values', ['field_id:s', 'user_id:s', 'format_id:s', 'field_value:s']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'sessions', ['session_id:s', 'user_id:s', 'session_key:n', 'session_remote_addr_first:a', 'session_remote_addr_last:a:n', 'session_user_agent:s', 'session_country:s', 'session_expires:t', 'session_expires_bump:b', 'session_created:t', 'session_active:t:n']); - $tmpFiles[] = db_to_zip($archive, $userInfo, 'users', ['user_id:s', 'user_name:s', 'user_password:n', 'user_email:s', 'user_remote_addr_first:a', 'user_remote_addr_last:a', 'user_super:b', 'user_country:s', 'user_colour:i:n', 'user_title:s:n', 'user_display_role_id:s:n', 'user_created:t', 'user_active:t:n', 'user_deleted:t:n']); + $tmpFiles[] = db_to_zip($archive, $userInfo, 'users', ['user_id:s', 'user_name:s', 'user_email:s', 'user_remote_addr_first:a', 'user_remote_addr_last:a', 'user_super:b', 'user_country:s', 'user_colour:i:n', 'user_title:s:n', 'user_display_role_id:s:n', 'user_created:t', 'user_active:t:n', 'user_deleted:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_bans', ['ban_id:s', 'user_id:s', 'mod_id:n', 'ban_severity:i', 'ban_reason_public:s', 'ban_reason_private:s', 'ban_created:t', 'ban_expires:t:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_birthdates', ['user_id:s', 'birth_year:i:n', 'birth_month:i', 'birth_day:i']); + $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_passwords', ['user_id:s', 'password_hash:n', 'password_created:t']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_password_resets', ['reset_id:s', 'user_id:s', 'reset_remote_addr:a', 'reset_requested:t', 'reset_code:n']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_roles', ['user_id:s', 'role_id:s']); $tmpFiles[] = db_to_zip($archive, $userInfo, 'users_totp', ['user_id:s', 'totp_secret:n', 'totp_created:t']); diff --git a/src/Users/UserInfo.php b/src/Users/UserInfo.php index 19fcfaff..d9769ae9 100644 --- a/src/Users/UserInfo.php +++ b/src/Users/UserInfo.php @@ -9,7 +9,6 @@ class UserInfo { public function __construct( public private(set) string $id, public private(set) string $name, - #[\SensitiveParameter] private ?string $passwordHash, #[\SensitiveParameter] public private(set) string $emailAddress, public private(set) string $registerRemoteAddress, public private(set) string $lastRemoteAddress, @@ -27,33 +26,20 @@ class UserInfo { return new UserInfo( id: $result->getString(0), name: $result->getString(1), - passwordHash: $result->getStringOrNull(2), - emailAddress: $result->getString(3), - registerRemoteAddress: $result->getString(4), - lastRemoteAddress: $result->getStringOrNull(5), - super: $result->getBoolean(6), - countryCode: $result->getString(7), - colourRaw: $result->getIntegerOrNull(8), - title: $result->getString(9), - displayRoleId: $result->getStringOrNull(10), - createdTime: $result->getInteger(11), - lastActiveTime: $result->getIntegerOrNull(12), - deletedTime: $result->getIntegerOrNull(13), + emailAddress: $result->getString(2), + registerRemoteAddress: $result->getString(3), + lastRemoteAddress: $result->getStringOrNull(4), + super: $result->getBoolean(5), + countryCode: $result->getString(6), + colourRaw: $result->getIntegerOrNull(7), + title: $result->getString(8), + displayRoleId: $result->getStringOrNull(9), + createdTime: $result->getInteger(10), + lastActiveTime: $result->getIntegerOrNull(11), + deletedTime: $result->getIntegerOrNull(12), ); } - public bool $hasPasswordHash { - get => $this->passwordHash !== null && $this->passwordHash !== ''; - } - - public bool $passwordNeedsRehash { - get => $this->hasPasswordHash && UsersData::passwordNeedsRehash($this->passwordHash); - } - - public function verifyPassword(string $password): bool { - return $this->hasPasswordHash && password_verify($password, $this->passwordHash); - } - public bool $hasColour { get => $this->colourRaw !== null && ($this->colourRaw & 0x40000000) === 0; } diff --git a/src/Users/UserPasswordInfo.php b/src/Users/UserPasswordInfo.php new file mode 100644 index 00000000..8af63326 --- /dev/null +++ b/src/Users/UserPasswordInfo.php @@ -0,0 +1,33 @@ +<?php +namespace Misuzu\Users; + +use Carbon\CarbonImmutable; +use Index\Db\DbResult; + +class UserPasswordInfo { + public function __construct( + public private(set) string $userId, + #[\SensitiveParameter] private string $hash, + public private(set) int $createdTime + ) {} + + public static function fromResult(DbResult $result): UserPasswordInfo { + return new UserPasswordInfo( + userId: $result->getString(0), + hash: $result->getString(1), + createdTime: $result->getInteger(2), + ); + } + + public bool $needsRehash { + get => UserPasswordsData::passwordNeedsRehash($this->hash); + } + + public CarbonImmutable $createdAt { + get => CarbonImmutable::createFromTimestampUTC($this->createdTime); + } + + public function verifyPassword(#[\SensitiveParameter] string $password): bool { + return password_verify($password, $this->hash); + } +} diff --git a/src/Users/UserPasswordsData.php b/src/Users/UserPasswordsData.php new file mode 100644 index 00000000..2eda9e73 --- /dev/null +++ b/src/Users/UserPasswordsData.php @@ -0,0 +1,80 @@ +<?php +namespace Misuzu\Users; + +use RuntimeException; +use Index\XString; +use Index\Db\{DbConnection,DbStatementCache}; + +class UserPasswordsData { + public const string PASSWORD_ALGO = PASSWORD_ARGON2ID; + public const array PASSWORD_OPTS = []; + public const int PASSWORD_UNIQUE = 6; + + private DbStatementCache $cache; + + public function __construct(DbConnection $dbConn) { + $this->cache = new DbStatementCache($dbConn); + } + + public static function passwordHash(#[\SensitiveParameter] string $password): string { + return password_hash($password, self::PASSWORD_ALGO, self::PASSWORD_OPTS); + } + + public static function passwordNeedsRehash(#[\SensitiveParameter] string $passwordHash): bool { + return password_needs_rehash($passwordHash, self::PASSWORD_ALGO, self::PASSWORD_OPTS); + } + + public function getUserPassword(UserInfo|string $userInfo): ?UserPasswordInfo { + $stmt = $this->cache->get(<<<SQL + SELECT user_id, password_hash, UNIX_TIMESTAMP(password_created) + FROM msz_users_passwords + WHERE user_id = ? + SQL); + $stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo); + $stmt->execute(); + + $result = $stmt->getResult(); + return $result->next() ? UserPasswordInfo::fromResult($result) : null; + } + + public function deleteUserPassword(UserInfo|string $userInfo): void { + $stmt = $this->cache->get(<<<SQL + DELETE FROM msz_users_passwords + WHERE user_id = ? + SQL); + $stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo); + $stmt->execute(); + } + + public function updateUserPassword(UserInfo|string $userInfo, #[\SensitiveParameter] string $password): UserPasswordInfo { + $stmt = $this->cache->get(<<<SQL + REPLACE INTO msz_users_passwords ( + user_id, password_hash + ) VALUES (?, ?) + SQL); + $stmt->nextParameter($userInfo instanceof UserInfo ? $userInfo->id : $userInfo); + $stmt->nextParameter(self::passwordHash($password)); + $stmt->execute(); + + $pwInfo = $this->getUserPassword($userInfo); + if($pwInfo === null) + throw new RuntimeException('failed to create password'); + + return $pwInfo; + } + + public static function validateUserPassword(string $password): string { + if(XString::countUnique($password) < self::PASSWORD_UNIQUE) + return 'weak'; + + return ''; + } + + public static function validateUserPasswordText(string $error): string { + return match($error) { + 'weak' => sprintf("Your password is too weak, it must contain at least %d unique characters.", self::PASSWORD_UNIQUE), + '' => 'Your password is strong enough, why are you seeing this?', + default => 'Your password is not acceptable.', + }; + } +} diff --git a/src/Users/UserTotpsData.php b/src/Users/UserTotpsData.php index 9d232e95..5e42c2f1 100644 --- a/src/Users/UserTotpsData.php +++ b/src/Users/UserTotpsData.php @@ -46,7 +46,7 @@ class UserTotpsData { $stmt->execute(); } - public function createUserTotp(UserInfo|string $userInfo): UserTotpInfo { + public function updateUserTotp(UserInfo|string $userInfo): UserTotpInfo { $stmt = $this->cache->get(<<<SQL REPLACE INTO msz_users_totp ( user_id, totp_secret diff --git a/src/Users/UsersContext.php b/src/Users/UsersContext.php index 69cbfc14..a0cb4071 100644 --- a/src/Users/UsersContext.php +++ b/src/Users/UsersContext.php @@ -10,6 +10,7 @@ class UsersContext { public private(set) BansData $bans; public private(set) WarningsData $warnings; public private(set) ModNotesData $modNotes; + public private(set) UserPasswordsData $passwords; public private(set) UserTotpsData $totps; public private(set) UserBirthdatesData $birthdates; @@ -31,6 +32,7 @@ class UsersContext { $this->bans = new BansData($dbConn); $this->warnings = new WarningsData($dbConn); $this->modNotes = new ModNotesData($dbConn); + $this->passwords = new UserPasswordsData($dbConn); $this->totps = new UserTotpsData($dbConn); $this->birthdates = new UserBirthdatesData($dbConn); } diff --git a/src/Users/UsersData.php b/src/Users/UsersData.php index 25196139..fc436743 100644 --- a/src/Users/UsersData.php +++ b/src/Users/UsersData.php @@ -16,20 +16,8 @@ class UsersData { $this->cache = new DbStatementCache($dbConn); } - public const NAME_MIN_LENGTH = 3; - public const NAME_MAX_LENGTH = 16; - - public const PASSWORD_ALGO = PASSWORD_ARGON2ID; - public const PASSWORD_OPTS = []; - public const PASSWORD_UNIQUE = 6; - - public static function passwordHash(string $password): string { - return password_hash($password, self::PASSWORD_ALGO, self::PASSWORD_OPTS); - } - - public static function passwordNeedsRehash(string $passwordHash): bool { - return password_needs_rehash($passwordHash, self::PASSWORD_ALGO, self::PASSWORD_OPTS); - } + public const int NAME_MIN_LENGTH = 3; + public const int NAME_MAX_LENGTH = 16; public function countUsers( RoleInfo|string|null $roleInfo = null, @@ -165,7 +153,7 @@ class UsersData { $args = 0; $query = <<<SQL - SELECT u.user_id, u.user_name, u.user_password, u.user_email, + SELECT u.user_id, u.user_name, u.user_email, INET6_NTOA(u.user_remote_addr_first), INET6_NTOA(u.user_remote_addr_last), u.user_super, u.user_country, u.user_colour, u.user_title, u.user_display_role_id, @@ -271,7 +259,7 @@ class UsersData { $args = 0; $query = <<<SQL - SELECT user_id, user_name, user_password, user_email, + SELECT user_id, user_name, user_email, INET6_NTOA(user_remote_addr_first), INET6_NTOA(user_remote_addr_last), user_super, user_country, user_colour, user_title, user_display_role_id, @@ -307,7 +295,6 @@ class UsersData { public function createUser( string $name, - string $password, string $email, string $remoteAddr, string $countryCode, @@ -318,16 +305,13 @@ class UsersData { elseif($displayRoleInfo === null) $displayRoleInfo = RolesData::DEFAULT_ROLE; - $password = self::passwordHash($password); - if(self::validateName($name, true) !== '') throw new InvalidArgumentException('$name is not a valid user name.'); if(self::validateEMailAddress($email, true) !== '') throw new InvalidArgumentException('$email is not a valid e-mail address.'); - $stmt = $this->cache->get('INSERT INTO msz_users (user_name, user_password, user_email, user_remote_addr_first, user_remote_addr_last, user_country, user_display_role_id) VALUES (?, ?, ?, INET6_ATON(?), INET6_ATON(?), ?, ?)'); + $stmt = $this->cache->get('INSERT INTO msz_users (user_name, user_email, user_remote_addr_first, user_remote_addr_last, user_country, user_display_role_id) VALUES (?, ?, INET6_ATON(?), INET6_ATON(?), ?, ?)'); $stmt->nextParameter($name); - $stmt->nextParameter($password); $stmt->nextParameter($email); $stmt->nextParameter($remoteAddr); $stmt->nextParameter($remoteAddr); @@ -342,7 +326,6 @@ class UsersData { UserInfo|string $userInfo, ?string $name = null, ?string $emailAddr = null, - ?string $password = null, ?string $countryCode = null, ?Colour $colour = null, RoleInfo|string|null $displayRoleInfo = null, @@ -372,11 +355,6 @@ class UsersData { $values[] = $emailAddr; } - if($password !== null) { - $fields[] = 'password = ?'; - $values[] = $password === '' ? null : self::passwordHash($password); - } - if($countryCode !== null) { $fields[] = 'user_country = ?'; $values[] = $countryCode; @@ -643,19 +621,4 @@ class UsersData { default => 'Your e-mail address is not correctly formatted.', }; } - - public static function validatePassword(string $password): string { - if(XString::countUnique($password) < self::PASSWORD_UNIQUE) - return 'weak'; - - return ''; - } - - public static function validatePasswordText(string $error): string { - return match($error) { - 'weak' => sprintf("Your password is too weak, it must contain at least %d unique characters.", self::PASSWORD_UNIQUE), - '' => 'Your password is strong enough, why are you seeing this?', - default => 'Your password is not acceptable.', - }; - } }