From 4cd7017da9a37e5b9f38c3f50dd1c904ea41cbcb Mon Sep 17 00:00:00 2001 From: winter Date: Tue, 31 Dec 2024 22:30:16 +0000 Subject: implement user accounts and login --- .../HttpResponseStatus/TemporaryRedirect.php | 9 +++- Digitigrade/Model/Session.php | 43 ++++++++++++++++++ Digitigrade/Model/UserAccount.php | 52 ++++++++++++++++++++++ 3 files changed, 103 insertions(+), 1 deletion(-) create mode 100644 Digitigrade/Model/Session.php create mode 100644 Digitigrade/Model/UserAccount.php (limited to 'Digitigrade') diff --git a/Digitigrade/HttpResponseStatus/TemporaryRedirect.php b/Digitigrade/HttpResponseStatus/TemporaryRedirect.php index fbf0def..4c9a794 100644 --- a/Digitigrade/HttpResponseStatus/TemporaryRedirect.php +++ b/Digitigrade/HttpResponseStatus/TemporaryRedirect.php @@ -12,6 +12,9 @@ class TemporaryRedirect extends \Exception implements HttpResponseStatus { } public function httpCode(): int { + if (isset($_SERVER['HTTP_HX_REQUEST'])) { + return 200; + } return 302; } @@ -20,6 +23,10 @@ class TemporaryRedirect extends \Exception implements HttpResponseStatus { } public function httpHeaders() { - header("Location: $this->target"); + if (isset($_SERVER['HTTP_HX_REQUEST'])) { + header("HX-Location: $this->target"); + } else { + header("Location: $this->target"); + } } } \ No newline at end of file diff --git a/Digitigrade/Model/Session.php b/Digitigrade/Model/Session.php new file mode 100644 index 0000000..31fb8bb --- /dev/null +++ b/Digitigrade/Model/Session.php @@ -0,0 +1,43 @@ +userAccount = $user; + $session->token = random_printable_bytes(); + $session->save(); + return $session; + } + + protected function getUpdateWhereClause(\PDO $db): ?string { + if (self::findByToken($this->token) != null) { + return 'token = ' . $db->quote($this->token); + } + return null; + } + + public static function findByToken(#[\SensitiveParameter] string $token): ?self { + return self::findWhere('token = ?', [$token]); + } + + public static function findAllByAccount(UserAccount $userAccount): array { + return self::findAllWhere('user_account = ?', [$userAccount->id]); + } + + public function setCookie(bool $rememberSession) { + setcookie('digitigrade-session', $this->token, [ + 'expires' => $rememberSession ? (new \DateTimeImmutable('1 year'))->getTimestamp() : null, + 'httponly' => true, + 'samesite' => 'Lax', + 'path' => '/', + 'secure' => GlobalConfig::getInstance()->isHttps() + ]); + } +} \ No newline at end of file diff --git a/Digitigrade/Model/UserAccount.php b/Digitigrade/Model/UserAccount.php new file mode 100644 index 0000000..3d0e2a4 --- /dev/null +++ b/Digitigrade/Model/UserAccount.php @@ -0,0 +1,52 @@ +email = $email; + $user->passwordHash = defaults_password_hash($password); + $user->actor = null; + $user->save(); + return $user; + } + + public function createLinkedActor(string $handle) { + $this->actor = Actor::create($handle); + $this->save(); + } + + protected function getUpdateWhereClause(\PDO $db): ?string { + if (isset($this->id) && self::find($this->{'id'}) != null) { + return 'id = ' . $this->{'id'}; + } + if (self::findByEmail($this->email) != null) { + return 'email = ' . $db->quote($this->email); + } + return null; + } + + public static function findByEmail(string $email): ?self { + return self::findWhere('email = ?', [$email]); + } + + public static function findByCurrentSession(): ?self { + if (!isset($_COOKIE['digitigrade-session'])) { + return null; + } + $token = $_COOKIE['digitigrade-session']; + return Session::findByToken($token)?->userAccount; + } + + public function verifyPassword(#[\SensitiveParameter] $attemptedPassword): bool { + return password_verify($attemptedPassword, $this->passwordHash); + } +} \ No newline at end of file -- cgit v1.3