instances added god may help
This commit is contained in:
94
lib/Service/Auth/MicrosoftOidcStateStoreService.php
Normal file
94
lib/Service/Auth/MicrosoftOidcStateStoreService.php
Normal file
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace MintyPHP\Service\Auth;
|
||||
|
||||
class MicrosoftOidcStateStoreService
|
||||
{
|
||||
private const SESSION_KEY = 'microsoft_oidc_states';
|
||||
|
||||
public function __construct(
|
||||
private readonly int $ttlSeconds = 600,
|
||||
private readonly int $maxEntries = 50
|
||||
) {
|
||||
}
|
||||
|
||||
public function store(string $state, array $payload): void
|
||||
{
|
||||
$state = trim($state);
|
||||
if ($state === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$states = $this->states();
|
||||
$states = $this->pruneExpiredStates($states);
|
||||
|
||||
$payload['created_at'] = (int) ($payload['created_at'] ?? time());
|
||||
$states[$state] = $payload;
|
||||
|
||||
if (count($states) > $this->maxEntries) {
|
||||
uasort($states, static function (array $a, array $b): int {
|
||||
return ((int) ($a['created_at'] ?? 0)) <=> ((int) ($b['created_at'] ?? 0));
|
||||
});
|
||||
while (count($states) > $this->maxEntries) {
|
||||
array_shift($states);
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION[self::SESSION_KEY] = $states;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{ok:bool,error?:string,entry?:array}
|
||||
*/
|
||||
public function consume(string $state): array
|
||||
{
|
||||
$state = trim($state);
|
||||
if ($state === '') {
|
||||
return ['ok' => false, 'error' => 'state_invalid'];
|
||||
}
|
||||
|
||||
$states = $this->states();
|
||||
$entry = is_array($states[$state] ?? null) ? $states[$state] : null;
|
||||
if ($entry === null) {
|
||||
return ['ok' => false, 'error' => 'state_invalid'];
|
||||
}
|
||||
|
||||
unset($states[$state]);
|
||||
$_SESSION[self::SESSION_KEY] = $states;
|
||||
|
||||
$createdAt = (int) ($entry['created_at'] ?? 0);
|
||||
if ($createdAt <= 0 || (time() - $createdAt) > $this->ttlSeconds) {
|
||||
return ['ok' => false, 'error' => 'state_expired'];
|
||||
}
|
||||
|
||||
return ['ok' => true, 'entry' => $entry];
|
||||
}
|
||||
|
||||
public function prune(): void
|
||||
{
|
||||
$_SESSION[self::SESSION_KEY] = $this->pruneExpiredStates($this->states());
|
||||
}
|
||||
|
||||
private function states(): array
|
||||
{
|
||||
$states = $_SESSION[self::SESSION_KEY] ?? [];
|
||||
return is_array($states) ? $states : [];
|
||||
}
|
||||
|
||||
private function pruneExpiredStates(array $states): array
|
||||
{
|
||||
$now = time();
|
||||
foreach ($states as $key => $payload) {
|
||||
if (!is_array($payload)) {
|
||||
unset($states[$key]);
|
||||
continue;
|
||||
}
|
||||
$createdAt = (int) ($payload['created_at'] ?? 0);
|
||||
if ($createdAt <= 0 || ($now - $createdAt) > $this->ttlSeconds) {
|
||||
unset($states[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $states;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user