diff options
| author | winter Sparkles | 2026-08-09 02:26:33 +0100 |
|---|---|---|
| committer | winter Sparkles | 2026-08-09 02:26:33 +0100 |
| commit | 3354d45762bbe0db33e3d26d8997e6f6624f24d7 (patch) | |
| tree | 4bef4bf59488f443ed54ff6e30002268836ac259 /Psso/Session.php | |
| parent | 4bb659e1f7bb5850db5695a536428a9b71e3ffe5 (diff) | |
implement sessions and also log in/out
session data is stored in sqlite, not using php sessions
Diffstat (limited to 'Psso/Session.php')
| -rw-r--r-- | Psso/Session.php | 101 |
1 files changed, 101 insertions, 0 deletions
diff --git a/Psso/Session.php b/Psso/Session.php new file mode 100644 index 0000000..35a6228 --- /dev/null +++ b/Psso/Session.php @@ -0,0 +1,101 @@ +<?php +namespace Psso; + +class Session { + protected static ?self $instance = null; + protected static ?array $pdoSetup = null; + protected static ?array $config = null; + + protected \PDO $db; + private ?string $token = null; + + public static function setDsn( + array $config, + string $dsn, + ?string $username = null, + #[\SensitiveParameter] ?string $password = null + ): void { + static::$config = $config; + static::$pdoSetup = [$dsn, $username, $password]; + } + + protected function __construct() { + $args = static::$pdoSetup; + $args[] = [\PDO::ATTR_PERSISTENT => true]; + $this->db = new \PDO(...$args); + $this->setup(); + } + + public static function get(): self { + if (!isset(self::$instance)) { + self::$instance = new self(); + } + self::$instance->setCookie(); + return self::$instance; + } + + protected function setup(): void { + $this->db->exec( + <<<'END' + create table if not exists session ( + token text primary key not null, + identity text not null default 'N;', + challenges text not null default 'N;' + ); + END + ); + } + + protected function domain(): string { + return explode('.', $_SERVER['HTTP_HOST'], 2)[1]; + } + + protected function setCookie(): void { + if (isset($_COOKIE['PSSO_session'])) return; + header( + 'Set-Cookie: PSSO_session=' . $this->currentToken() + . '; Domain=' . $this->domain() + . '; HttpOnly' + . '; Max-Age=' . static::$config['auth']['lifetime'] + . '; Path=/' + . '; SameSite=Lax' + . '; Secure' + ); + } + + protected function currentToken(): string { + return $this->token = $this->token ?? + $_COOKIE['PSSO_session'] ?? + base64_encode(random_bytes(129)); + } + + protected function setColumn(string $column, mixed $data): void { + $stmt = $this->db->prepare( + "insert into session(token, $column) values (?, ?) " + . "on conflict do update set $column=excluded.$column" + ); + $stmt->execute([$this->currentToken(), serialize($data)]); + } + + public function getColumn(string $column): mixed { + $stmt = $this->db->prepare("select $column from session where token=?"); + $stmt->execute([$this->currentToken()]); + return unserialize($stmt->fetchColumn(0)); + } + + public function setIdentity(mixed $identity): void { + $this->setColumn('identity', $identity); + } + + public function getIdentity(): mixed { + return $this->getColumn('identity'); + } + + public function setChallenges(mixed $challenges): void { + $this->setColumn('challenges', $challenges); + } + + public function getChallenges(): mixed { + return $this->getColumn('challenges'); + } +} |
