1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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)) ?: null;
}
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');
}
}
|