hanyuu/src/Users/Db/DbUsers.php

171 lines
6.4 KiB
PHP

<?php
namespace Hanyuu\Users\Db;
use RuntimeException;
use Index\Data\IDbConnection;
use Index\Data\IDbStatement;
use Index\Data\IDbResult;
use Index\Data\DbType;
use Hanyuu\Users\IUsers;
use Hanyuu\Users\IUserInfo;
use Hanyuu\Users\IUserPasswordInfo;
use Hanyuu\Users\IUserTOTPInfo;
class DbUsers implements IUsers {
private const USERS_TABLE = 'hau_users';
private const AUTH_TABLE = 'hau_users_auth';
private const BACKUP_TABLE = 'hau_users_backup';
private const EMAILS_TABLE = 'hau_users_emails';
private const PASSWORDS_TABLE = 'hau_users_passwords';
private const TOTP_TABLE = 'hau_users_totp';
private const USERS_FIELDS = [
'user_id', 'user_name', 'user_country', 'user_colour', 'user_super', 'user_time_zone',
'UNIX_TIMESTAMP(user_created)', 'UNIX_TIMESTAMP(user_updated)', 'UNIX_TIMESTAMP(user_deleted)',
];
private const AUTH_FIELDS = [
'user_id', 'user_auth_type', 'UNIX_TIMESTAMP(user_auth_enabled)',
];
private const PASSWORDS_FIELDS = [
'user_id', 'user_password_hash', 'UNIX_TIMESTAMP(user_password_changed)',
];
private const TOTP_FIELDS = [
'user_id', 'user_totp_key', 'UNIX_TIMESTAMP(user_totp_changed)',
];
private const EMAILS_FIELDS = [
'user_id', 'user_email_address', 'UNIX_TIMESTAMP(user_email_created)', 'UNIX_TIMESTAMP(user_email_verified)', 'user_email_recovery',
];
private const BACKUP_FIELDS = [
'user_id', 'user_backup_code', 'UNIX_TIMESTAMP(user_backup_created)', 'UNIX_TIMESTAMP(user_backup_used)',
];
private const FIRST_FACTOR_AUTH = ['pwd'];
private const SECOND_FACTOR_AUTH = ['totp'];
public function __construct(
private IDbConnection $conn
) {}
private array $statements = [];
private function getStatement(string $name, callable $query): IDbStatement {
if(array_key_exists($name, $this->statements))
return $this->statements[$name];
return $this->statements[$name] = $this->conn->prepare($query());
}
private function fetchUserInfoSingle(IDbResult $result, string $exceptionText): IUserInfo {
if(!$result->next())
throw new RuntimeException($exceptionText);
return new DbUserInfo($result);
}
public function getUserInfoById(string $userId): IUserInfo {
$stmt = $this->getStatement('get info by id', fn() => ('SELECT ' . implode(',', self::USERS_FIELDS) . ' FROM ' . self::USERS_TABLE . ' WHERE user_id = ?'));
$stmt->reset();
$stmt->addParameter(1, $userId, DbType::STRING);
$stmt->execute();
return $this->fetchUserInfoSingle($stmt->getResult(), 'no user with $userId found');
}
public function getUserInfoByName(string $userName): IUserInfo {
$stmt = $this->getStatement('get info by name', fn() => ('SELECT ' . implode(',', self::USERS_FIELDS) . ' FROM ' . self::USERS_TABLE . ' WHERE user_name = ?'));
$stmt->reset();
$stmt->addParameter(1, $userName, DbType::STRING);
$stmt->execute();
return $this->fetchUserInfoSingle($stmt->getResult(), 'no user with $userName found');
}
private function fetchAuthInfoMultiple(IDbResult $result): array {
$array = [];
while($result->next())
$array[] = new DbUserAuthInfo($result);
return $array;
}
public function getUserFirstFactorAuthInfos(IUserInfo $userInfo): array {
$stmt = $this->getStatement('get auth first', fn() => ('SELECT ' . implode(',', self::AUTH_FIELDS) . ' FROM ' . self::AUTH_TABLE . ' WHERE user_id = ? AND user_auth_type IN ("' . implode('", "', self::FIRST_FACTOR_AUTH) . '")'));
$stmt->reset();
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->execute();
return $this->fetchAuthInfoMultiple($stmt->getResult());
}
public function getUserSecondFactorAuthInfos(IUserInfo $userInfo): array {
$stmt = $this->getStatement('get auth second', fn() => ('SELECT ' . implode(',', self::AUTH_FIELDS) . ' FROM ' . self::AUTH_TABLE . ' WHERE user_id = ? AND user_auth_type IN ("' . implode('", "', self::SECOND_FACTOR_AUTH) . '")'));
$stmt->reset();
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->execute();
return $this->fetchAuthInfoMultiple($stmt->getResult());
}
public function getUserPasswordInfo(IUserInfo $userInfo): IUserPasswordInfo {
$stmt = $this->getStatement('get pwd', fn() => ('SELECT ' . implode(',', self::PASSWORDS_FIELDS) . ' FROM ' . self::PASSWORDS_TABLE . ' WHERE user_id = ?'));
$stmt->reset();
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('no password info for $userInfo found');
return new DbUserPasswordInfo($result);
}
public function getUserTOTPInfo(IUserInfo $userInfo): IUserTOTPInfo {
$stmt = $this->getStatement('get totp', fn() => ('SELECT ' . implode(',', self::TOTP_FIELDS) . ' FROM ' . self::TOTP_TABLE . ' WHERE user_id = ?'));
$stmt->reset();
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
if(!$result->next())
throw new RuntimeException('no totp info for $userInfo found');
return new DbUserTOTPInfo($result);
}
public function getUserEMailInfos(IUserInfo $userInfo): array {
$stmt = $this->getStatement('get emails', fn() => ('SELECT ' . implode(',', self::EMAILS_FIELDS) . ' FROM ' . self::EMAILS_TABLE . ' WHERE user_id = ?'));
$stmt->reset();
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
$array = [];
while($result->next())
$array[] = new DbUserEMailInfo($result);
return $array;
}
public function getUserBackupInfos(IUserInfo $userInfo): array {
$stmt = $this->getStatement('get backups', fn() => ('SELECT ' . implode(',', self::BACKUP_FIELDS) . ' FROM ' . self::BACKUP_TABLE . ' WHERE user_id = ?'));
$stmt->reset();
$stmt->addParameter(1, $userInfo->getId(), DbType::STRING);
$stmt->execute();
$result = $stmt->getResult();
$array = [];
while($result->next())
$array[] = new DbUserBackupInfo($result);
return $array;
}
}