Project structure cleanup.

This commit is contained in:
Pachira 2023-10-20 22:11:43 +00:00
parent 7e0218cf6b
commit 7d5f4a90e9
24 changed files with 199 additions and 367 deletions

View file

@ -1,7 +1,82 @@
<?php
namespace Hanyuu\Auth;
use InvalidArgumentException;
use RuntimeException;
use Index\XString;
use Index\Data\IDbConnection;
use Index\Data\IDbResult;
use Hanyuu\StatementCache;
use Hanyuu\Users\UserInfo;
abstract class Auth {}
class Auth {
private const LOGINS_TABLE = 'hau_auth_logins';
private const LOGINS_FIELDS = [
'auth_login_id', 'user_id', 'auth_login_ip', 'auth_login_country',
'auth_login_factors_required', 'auth_login_factors_done',
'UNIX_TIMESTAMP(auth_login_started)', 'UNIX_TIMESTAMP(auth_login_valid)', 'UNIX_TIMESTAMP(auth_login_completed)',
];
private StatementCache $stmts;
public function __construct(
private IDbConnection $conn
) {
$this->stmts = new StatementCache($conn);
}
public function createLoginSession(
UserInfo $userInfo,
string $remoteAddr,
string $countryCode,
int $factors
): string {
$loginId = XString::random(48);
$stmt = $this->stmts->getStatement('create login', function() {
return 'INSERT INTO ' . self::LOGINS_TABLE
. ' (auth_login_id, user_id, auth_login_ip, auth_login_country, auth_login_factors_required)'
. ' VALUES (?, ?, INET6_ATON(?), ?, ?)';
});
$stmt->addParameter(1, $loginId);
$stmt->addParameter(2, $userInfo->getId());
$stmt->addParameter(3, $remoteAddr);
$stmt->addParameter(4, $countryCode);
$stmt->addParameter(5, $factors);
$stmt->execute();
return $loginId;
}
public function destroyLoginSession(AuthLoginInfo $loginInfo): void {
$stmt = $this->stmts->getStatement('destroy login', fn() => ('DELETE FROM ' . self::LOGINS_TABLE . ' WHERE auth_login_id = ?'));
$stmt->addParameter(1, $loginInfo->getId());
$stmt->execute();
}
private function fetchLoginSingle(IDbResult $result, string $exceptionText): UserInfo {
if(!$result->next())
throw new AuthLoginNotFoundException($exceptionText);
return new UserInfo($result);
}
public function getLoginSessionById(string $loginId): ?AuthLoginInfo {
$stmt = $this->stmts->getStatement('get login by id', fn() => ('SELECT ' . implode(',', self::LOGINS_FIELDS) . ' FROM ' . self::LOGINS_TABLE . ' WHERE auth_login_id = ?'));
$stmt->addParameter(1, $loginId);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
return null;
return new AuthLoginInfo($result);
}
public function incrementLoginSessionDone(AuthLoginInfo $login): void {
$stmt = $this->stmts->getStatement('increment login done', fn() => ('UPDATE ' . self::LOGINS_TABLE . ' SET auth_login_factors_done = auth_login_factors_done + 1 WHERE auth_login_id = ?'));
$stmt->addParameter(1, $login->getId());
$stmt->execute();
}
}

View file

@ -1,12 +1,11 @@
<?php
namespace Hanyuu\Auth\Db;
namespace Hanyuu\Auth;
use Index\DateTime;
use Index\Data\IDbResult;
use Index\Net\IPAddress;
use Hanyuu\Auth\IAuthLogin;
class DbAuthLogin implements IAuthLogin {
class AuthLoginInfo {
private string $id;
private string $userId;
private IPAddress $remoteAddr;

View file

@ -1,24 +1,23 @@
<?php
namespace Hanyuu\Auth;
use RuntimeException;
use Index\Routing\IRouter;
use Syokuhou\IConfig;
use Hanyuu\HanyuuContext;
use Hanyuu\Auth\Auth;
use Hanyuu\Auth\IAuthLogin;
use Hanyuu\Users\IUserInfo;
use Hanyuu\Users\IUsers;
use Hanyuu\Users\UserNotFoundException;
use Hanyuu\Auth\AuthLoginInfo;
use Hanyuu\Users\Users;
// VERY IMPORTANT TODO: CSRF AND RATE LIMITING
class AuthRoutes {
private HanyuuContext $context;
private IUsers $users;
private Users $users;
private IConfig $config;
private Auth $auth;
private ?IAuthLogin $loginSession;
private ?AuthLoginInfo $loginSession;
public function __construct(
IRouter $router,
@ -108,9 +107,9 @@ class AuthRoutes {
][$errorId] ?? '';
return $this->context->renderTemplate('auth/login', [
'userName' => $userName,
'errorId' => $errorId,
'errorText' => $errorText,
'user_name' => $userName,
'error_name' => $errorId,
'error_text' => $errorText,
]);
}
@ -133,7 +132,7 @@ class AuthRoutes {
try {
$userInfo = $this->users->getUserInfoByName($userName);
} catch(UserNotFoundException $ex) {
} catch(RuntimeException $ex) {
$response->redirect('/login?error=user_not_found&username=' . rawurlencode($userName));
return;
}
@ -183,10 +182,10 @@ class AuthRoutes {
}
return $this->context->renderTemplate('auth/login-tfa', [
'userInfo' => $userInfo,
'authMethods' => $authMethods,
'authMethodNames' => $authMethodNames,
'loginSession' => $this->loginSession,
'user_info' => $userInfo,
'auth_methods' => $authMethods,
'auth_method_names' => $authMethodNames,
'login_session' => $this->loginSession,
]);
}
@ -218,8 +217,8 @@ class AuthRoutes {
][$errorId] ?? '';
return $this->context->renderTemplate('auth/login-totp', [
'userInfo' => $userInfo,
'loginSession' => $this->loginSession,
'user_info' => $userInfo,
'login_session' => $this->loginSession,
]);
}

View file

@ -1,86 +0,0 @@
<?php
namespace Hanyuu\Auth\Db;
use Index\XString;
use Index\Data\IDbConnection;
use Index\Data\IDbResult;
use Index\Data\DbType;
use Hanyuu\StatementCache;
use Hanyuu\Auth\IAuthLogin;
use Hanyuu\Auth\IAuthMethod;
use Hanyuu\Auth\Auth;
use Hanyuu\Users\IUserInfo;
class DbAuth extends Auth {
private const LOGINS_TABLE = 'hau_auth_logins';
private const LOGINS_FIELDS = [
'auth_login_id', 'user_id', 'auth_login_ip', 'auth_login_country',
'auth_login_factors_required', 'auth_login_factors_done',
'UNIX_TIMESTAMP(auth_login_started)', 'UNIX_TIMESTAMP(auth_login_valid)', 'UNIX_TIMESTAMP(auth_login_completed)',
];
private StatementCache $stmts;
public function __construct(
private IDbConnection $conn
) {
$this->stmts = new StatementCache($conn);
}
public function createLoginSession(
IUserInfo $userInfo,
string $remoteAddr,
string $countryCode,
int $factors
): string {
$loginId = XString::random(48);
$stmt = $this->stmts->getStatement('create login', function() {
return 'INSERT INTO ' . self::LOGINS_TABLE
. ' (auth_login_id, user_id, auth_login_ip, auth_login_country, auth_login_factors_required)'
. ' VALUES (?, ?, INET6_ATON(?), ?, ?)';
});
$stmt->addParameter(1, $loginId, DbType::STRING);
$stmt->addParameter(2, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(3, $remoteAddr, DbType::STRING);
$stmt->addParameter(4, $countryCode, DbType::STRING);
$stmt->addParameter(5, $factors, DbType::INTEGER);
$stmt->execute();
return $loginId;
}
public function destroyLoginSession(IAuthLogin $loginInfo): void {
$stmt = $this->stmts->getStatement('destroy login', fn() => ('DELETE FROM ' . self::LOGINS_TABLE . ' WHERE auth_login_id = ?'));
$stmt->addParameter(1, $loginInfo->getId(), DbType::STRING);
$stmt->execute();
}
private function fetchLoginSingle(IDbResult $result, string $exceptionText): IUserInfo {
if(!$result->next())
throw new AuthLoginNotFoundException($exceptionText);
return new DbUserInfo($result);
}
public function getLoginSessionById(string $loginId): ?IAuthLogin {
$stmt = $this->stmts->getStatement('get login by id', fn() => ('SELECT ' . implode(',', self::LOGINS_FIELDS) . ' FROM ' . self::LOGINS_TABLE . ' WHERE auth_login_id = ?'));
$stmt->addParameter(1, $loginId, DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
return null;
return new DbAuthLogin($result);
}
public function incrementLoginSessionDone(IAuthLogin $login): void {
$stmt = $this->stmts->getStatement('increment login done', fn() => ('UPDATE ' . self::LOGINS_TABLE . ' SET auth_login_factors_done = auth_login_factors_done + 1 WHERE auth_login_id = ?'));
$stmt->addParameter(1, $login->getId(), DbType::STRING);
$stmt->execute();
}
}

View file

@ -1,19 +0,0 @@
<?php
namespace Hanyuu\Auth;
use Index\DateTime;
use Index\Net\IPAddress;
interface IAuthLogin {
public function getId(): string;
public function getUserId(): string;
public function getRemoteAddress(): IPAddress;
public function getCountryCode(): string;
public function getFactorsRequired(): int;
public function getFactorsDone(): int;
public function getStartedTime(): DateTime;
public function isValid(): bool;
public function getValidTime(): DateTime;
public function hasCompleted(): bool;
public function getCompletedTime(): DateTime;
}

View file

@ -13,14 +13,12 @@ use Sasae\SasaeEnvironment;
use Syokuhou\IConfig;
use Hanyuu\Auth\Auth;
use Hanyuu\Auth\AuthRoutes;
use Hanyuu\Auth\Db\DbAuth;
use Hanyuu\Users\IUsers;
use Hanyuu\Users\Db\DbUsers;
use Hanyuu\Users\Users;
class HanyuuContext {
private IConfig $config;
private IDbConnection $dbConn;
private IUsers $users;
private Users $users;
private Auth $auth;
private ?SasaeEnvironment $templating = null;
private SiteInfo $siteInfo;
@ -28,12 +26,12 @@ class HanyuuContext {
public function __construct(IConfig $config, IDbConnection $dbConn) {
$this->config = $config;
$this->dbConn = $dbConn;
$this->users = new DbUsers($dbConn);
$this->users = new Users($dbConn);
$this->siteInfo = new SiteInfo($config->scopeTo('site'));
}
public function getUsers(): IUsers {
public function getUsers(): Users {
return $this->users;
}
@ -78,7 +76,7 @@ class HanyuuContext {
}
public function setUpAuth(): void {
$this->auth = new DbAuth($this->dbConn);
$this->auth = new Auth($this->dbConn);
}
public function getAuth(): Auth {

View file

@ -1,6 +0,0 @@
<?php
namespace Hanyuu\OTP;
interface IOTPGenerator {
public function generate(): string;
}

View file

@ -1,74 +0,0 @@
<?php
namespace Hanyuu\OTP;
use InvalidArgumentException;
use Index\Serialisation\Serialiser;
class TOTPGenerator implements IOTPGenerator {
private const DIGITS = 6;
private const INTERVAL = 30;
private const HASH_ALGO = 'sha1';
public function __construct(
private string $secretKey,
private int $digits = self::DIGITS,
private int $interval = self::INTERVAL,
private string $hashAlgo = self::HASH_ALGO
) {
if(empty($this->secretKey))
throw new InvalidArgumentException('$secretKey may not be empty');
if($this->digits < 1)
throw new InvalidArgumentException('$digits must be a positive integer');
if($this->interval < 1)
throw new InvalidArgumentException('$interval must be a positive integer');
if(!in_array($this->hashAlgo, hash_hmac_algos(), true))
throw new InvalidArgumentException('$hashAlgo must be a hashing algorithm suitable for hmac');
}
public function getDigits(): int {
return $this->digits;
}
public function getInterval(): int {
return $this->interval;
}
public function getHashAlgo(): string {
return $this->hashAlgo;
}
public function getTimeCode(int $offset = 0, int $timeStamp = -1): int {
if($timeStamp < 0)
$timeStamp = time();
// use -1 and 1 to get the previous and next token for user convenience
if($offset !== 0)
$timeStamp += $this->interval * $offset;
return (int)(($timeStamp * 1000) / ($this->interval * 1000));
}
public function generate(int $offset = 0, int $timeStamp = -1): string {
$timeCode = pack('J', $this->getTimeCode($offset, $timeStamp));
$secretKey = Serialiser::base32()->deserialise($this->secretKey);
$hash = hash_hmac($this->hashAlgo, $timeCode, $secretKey, true);
$offset = ord($hash[strlen($hash) - 1]) & 0x0F;
$bin = (ord($hash[$offset]) & 0x7F) << 24;
$bin |= (ord($hash[$offset + 1]) & 0xFF) << 16;
$bin |= (ord($hash[$offset + 2]) & 0xFF) << 8;
$bin |= ord($hash[$offset + 3]) & 0xFF;
$otp = (string)($bin % pow(10, $this->digits));
return str_pad($otp, $this->digits, '0', STR_PAD_LEFT);
}
public static function generateKey(int $bytes = 16): string {
if($length < 1)
throw new InvalidArgumentException('$bytes must be a positive integer');
return Serialiser::base32()->serialise(random_bytes($bytes));
}
}

52
src/TOTPGenerator.php Normal file
View file

@ -0,0 +1,52 @@
<?php
namespace Hanyuu;
use InvalidArgumentException;
use Index\Serialisation\Base32;
class TOTPGenerator {
public const DIGITS = 6;
public const INTERVAL = 30000;
public function __construct(private string $secretKey) {}
public static function generateKey(): string {
return Base32::encode(random_bytes(16));
}
public static function timecode(?int $timestamp = null): int {
$timestamp ??= time();
return (int)(($timestamp * 1000) / self::INTERVAL);
}
public function generate(?int $timecode = null): string {
$timecode ??= self::timecode();
$hash = hash_hmac('sha1', pack('J', $timecode), Base32::decode($this->secretKey), true);
$offset = ord($hash[strlen($hash) - 1]) & 0x0F;
$bin = 0;
$bin |= (ord($hash[$offset]) & 0x7F) << 24;
$bin |= (ord($hash[$offset + 1]) & 0xFF) << 16;
$bin |= (ord($hash[$offset + 2]) & 0xFF) << 8;
$bin |= (ord($hash[$offset + 3]) & 0xFF);
$otp = $bin % pow(10, self::DIGITS);
return str_pad((string)$otp, self::DIGITS, '0', STR_PAD_LEFT);
}
public function generateRange(int $range = 1, ?int $timecode = null): array {
if($range < 1)
throw new InvalidArgumentException('$range must be greater than 0.');
$timecode ??= self::timecode();
$tokens = [$this->generate($timecode)];
for($i = 1; $i <= $range; ++$i)
$tokens[] = $this->generate($timecode - $i);
for($i = 1; $i <= $range; ++$i)
$tokens[] = $this->generate($timecode + $i);
return $tokens;
}
}

View file

@ -1,10 +0,0 @@
<?php
namespace Hanyuu\Users;
use Index\DateTime;
interface IUserAuthInfo {
public function getUserId(): string;
public function getType(): string;
public function getEnabledTime(): DateTime;
}

View file

@ -1,12 +0,0 @@
<?php
namespace Hanyuu\Users;
use Index\DateTime;
interface IUserBackupInfo {
public function getUserId(): string;
public function getCode(): string;
public function getCreatedTime(): DateTime;
public function isUsed(): bool;
public function getUsedTime(): DateTime;
}

View file

@ -1,13 +0,0 @@
<?php
namespace Hanyuu\Users;
use Index\DateTime;
interface IUserEMailInfo {
public function getUserId(): string;
public function getAddress(): string;
public function getCreatedTime(): DateTime;
public function isVerified(): bool;
public function getVerifiedTime(): DateTime;
public function isRecovery(): bool;
}

View file

@ -1,19 +0,0 @@
<?php
namespace Hanyuu\Users;
use Index\DateTime;
use Index\TimeZoneInfo;
use Index\Colour\Colour;
interface IUserInfo {
public function getId(): string;
public function getName(): string;
public function getCountryCode(): string;
public function getColour(): Colour;
public function isSuper(): bool;
public function getTimeZone(): TimeZoneInfo;
public function getCreatedTime(): DateTime;
public function getUpdatedTime(): DateTime;
public function isDeleted(): bool;
public function getDeletedTime(): DateTime;
}

View file

@ -1,12 +0,0 @@
<?php
namespace Hanyuu\Users;
use Index\DateTime;
interface IUserPasswordInfo {
public function getUserId(): string;
public function getHash(): string;
public function getChangedTime(): DateTime;
public function verifyPassword(string $password): bool;
public function needsRehash(string|int|null $algo, array $options = []): bool;
}

View file

@ -1,13 +0,0 @@
<?php
namespace Hanyuu\Users;
use Index\DateTime;
use Hanyuu\OTP\TOTPGenerator;
interface IUserTOTPInfo {
public function getUserId(): string;
public function getSecretKey(): string;
public function getChangedTime(): DateTime;
public function createGenerator(): TOTPGenerator;
public function generateValidCodes(int $offset = 0, int $timeStamp = -1): array;
}

View file

@ -1,6 +0,0 @@
<?php
namespace Hanyuu\Users;
interface IUsers {
//
}

View file

@ -1,11 +1,10 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use Index\DateTime;
use Index\Data\IDbResult;
use Hanyuu\Users\IUserAuthInfo;
class DbUserAuthInfo implements IUserAuthInfo {
class UserAuthInfo {
private string $userId;
private string $type;
private DateTime $enabled;

View file

@ -1,11 +1,10 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use Index\DateTime;
use Index\Data\IDbResult;
use Hanyuu\Users\IUserBackupInfo;
class DbUserBackupInfo implements IUserBackupInfo {
class UserBackupInfo {
private string $userId;
private string $code;
private DateTime $created;

View file

@ -1,11 +1,10 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use Index\DateTime;
use Index\Data\IDbResult;
use Hanyuu\Users\IUserEMailInfo;
class DbUserEMailInfo implements IUserEMailInfo {
class UserEMailInfo {
private string $userId;
private string $address;
private DateTime $created;

View file

@ -1,14 +1,13 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use Index\DateTime;
use Index\TimeZoneInfo;
use Index\Colour\Colour;
use Index\Colour\ColourRGB;
use Index\Data\IDbResult;
use Hanyuu\Users\IUserInfo;
class DbUserInfo implements IUserInfo {
class UserInfo {
private string $id;
private string $name;
private string $country;

View file

@ -1,6 +0,0 @@
<?php
namespace Hanyuu\Users;
use RuntimeException;
class UserNotFoundException extends RuntimeException {}

View file

@ -1,11 +1,10 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use Index\DateTime;
use Index\Data\IDbResult;
use Hanyuu\Users\IUserPasswordInfo;
class DbUserPasswordInfo implements IUserPasswordInfo {
class UserPasswordInfo {
private string $userId;
private string $hash;
private DateTime $changed;

View file

@ -1,12 +1,11 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use Index\DateTime;
use Index\Data\IDbResult;
use Hanyuu\OTP\TOTPGenerator;
use Hanyuu\Users\IUserTOTPInfo;
use Hanyuu\TOTPGenerator;
class DbUserTOTPInfo implements IUserTOTPInfo {
class UserTOTPInfo {
private string $userId;
private string $secretKey;
private DateTime $changed;
@ -33,13 +32,7 @@ class DbUserTOTPInfo implements IUserTOTPInfo {
return new TOTPGenerator($this->secretKey);
}
public function generateValidCodes(int $offset = 0, int $timeStamp = -1): array {
$generator = $this->createGenerator();
return [
$generator->generate(-1 + $offset, $timeStamp),
$generator->generate($offset, $timeStamp),
$generator->generate(1 + $offset, $timeStamp),
];
public function generateValidCodes(int $range = 1, ?int $timecode = null): array {
return $this->createGenerator()->generateRange($range, $timecode);
}
}

View file

@ -1,21 +1,18 @@
<?php
namespace Hanyuu\Users\Db;
namespace Hanyuu\Users;
use RuntimeException;
use Index\Data\IDbConnection;
use Index\Data\IDbStatement;
use Index\Data\IDbResult;
use Index\Data\DbType;
use Hanyuu\StatementCache;
use Hanyuu\Auth\IAuthMethod;
use Hanyuu\Auth\Auth;
use Hanyuu\Users\IUsers;
use Hanyuu\Users\IUserInfo;
use Hanyuu\Users\IUserPasswordInfo;
use Hanyuu\Users\IUserTOTPInfo;
use Hanyuu\Users\UserNotFoundException;
use Hanyuu\Users\UserInfo;
use Hanyuu\Users\UserPasswordInfo;
use Hanyuu\Users\UserTOTPInfo;
class DbUsers implements IUsers {
class Users {
private const USERS_TABLE = 'hau_users';
private const TFA_TABLE = 'hau_users_tfa';
private const BACKUP_TABLE = 'hau_users_backup';
@ -51,57 +48,57 @@ class DbUsers implements IUsers {
$this->stmts = new StatementCache($conn);
}
private function fetchUserInfoSingle(IDbResult $result, string $exceptionText): IUserInfo {
private function fetchUserInfoSingle(IDbResult $result, string $exceptionText): UserInfo {
if(!$result->next())
throw new UserNotFoundException($exceptionText);
throw new RuntimeException($exceptionText);
return new DbUserInfo($result);
return new UserInfo($result);
}
public function getUserInfoById(string $userId): IUserInfo {
public function getUserInfoById(string $userId): UserInfo {
$stmt = $this->stmts->getStatement('get info by id', fn() => ('SELECT ' . implode(',', self::USERS_FIELDS) . ' FROM ' . self::USERS_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userId, DbType::STRING);
$stmt->addParameter(1, $userId);
$stmt->execute();
return $this->fetchUserInfoSingle($stmt->getResult(), 'no user with $userId found');
}
public function getUserInfoByName(string $userName): IUserInfo {
public function getUserInfoByName(string $userName): UserInfo {
$stmt = $this->stmts->getStatement('get info by name', fn() => ('SELECT ' . implode(',', self::USERS_FIELDS) . ' FROM ' . self::USERS_TABLE . ' WHERE user_name = ?'));
$stmt->addParameter(1, $userName, DbType::STRING);
$stmt->addParameter(1, $userName);
$stmt->execute();
return $this->fetchUserInfoSingle($stmt->getResult(), 'no user with $userName found');
}
public function countUserTFAMethods(IUserInfo $userInfo): int {
public function countUserTFAMethods(UserInfo $userInfo): int {
$stmt = $this->stmts->getStatement('count user tfa methods', fn() => ('SELECT COUNT(*) FROM ' . self::TFA_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->execute();
$result = $stmt->getResult();
return $result->next() ? $result->getInteger(0) : 0;
}
public function getUserTFAMethods(IUserInfo $userInfo): array {
public function getUserTFAMethods(UserInfo $userInfo): array {
$stmt = $this->stmts->getStatement('get user tfa methods', fn() => ('SELECT ' . implode(',', self::TFA_FIELDS) . ' FROM ' . self::TFA_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->execute();
$result = $stmt->getResult();
$array = [];
while($result->next())
$array[] = new DbUserAuthInfo($result);
$array[] = new UserAuthInfo($result);
return $array;
}
public function checkUserTFAMethod(IUserInfo $userInfo, IAuthMethod $method): bool {
public function checkUserTFAMethod(UserInfo $userInfo, IAuthMethod $method): bool {
$stmt = $this->stmts->getStatement('check user auth method', fn() => ('SELECT COUNT(*) FROM ' . self::TFA_TABLE . ' WHERE user_id = ? AND user_tfa_type = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(2, $method->getName(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->addParameter(2, $method->getName());
$stmt->execute();
$result = $stmt->getResult();
@ -109,57 +106,57 @@ class DbUsers implements IUsers {
}
public function getUserPasswordInfo(IUserInfo $userInfo): IUserPasswordInfo {
public function getUserPasswordInfo(UserInfo $userInfo): UserPasswordInfo {
$stmt = $this->stmts->getStatement('get pwd', fn() => ('SELECT ' . implode(',', self::PASSWORDS_FIELDS) . ' FROM ' . self::PASSWORDS_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('no password info for $userInfo found');
return new DbUserPasswordInfo($result);
return new UserPasswordInfo($result);
}
public function getUserTOTPInfo(IUserInfo $userInfo): IUserTOTPInfo {
public function getUserTOTPInfo(UserInfo $userInfo): UserTOTPInfo {
$stmt = $this->stmts->getStatement('get totp', fn() => ('SELECT ' . implode(',', self::TOTP_FIELDS) . ' FROM ' . self::TOTP_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('no totp info for $userInfo found');
return new DbUserTOTPInfo($result);
return new UserTOTPInfo($result);
}
public function getUserEMailInfos(IUserInfo $userInfo): array {
public function getUserEMailInfos(UserInfo $userInfo): array {
$stmt = $this->stmts->getStatement('get emails', fn() => ('SELECT ' . implode(',', self::EMAILS_FIELDS) . ' FROM ' . self::EMAILS_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->execute();
$result = $stmt->getResult();
$array = [];
while($result->next())
$array[] = new DbUserEMailInfo($result);
$array[] = new UserEMailInfo($result);
return $array;
}
public function getUserBackupInfos(IUserInfo $userInfo): array {
public function getUserBackupInfos(UserInfo $userInfo): array {
$stmt = $this->stmts->getStatement('get backups', fn() => ('SELECT ' . implode(',', self::BACKUP_FIELDS) . ' FROM ' . self::BACKUP_TABLE . ' WHERE user_id = ?'));
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->addParameter(1, $userInfo->getId());
$stmt->execute();
$result = $stmt->getResult();
$array = [];
while($result->next())
$array[] = new DbUserBackupInfo($result);
$array[] = new UserBackupInfo($result);
return $array;
}