106 lines
3.0 KiB
PHP
106 lines
3.0 KiB
PHP
<?php
|
|
|
|
use objects\customer_password_reset_keys_o;
|
|
|
|
app_require('objects/customer_password_reset_keys_o.php');
|
|
|
|
if (!class_exists('PasswordResetTokenExpiryFakeResult')) {
|
|
class PasswordResetTokenExpiryFakeResult
|
|
{
|
|
public int $num_rows;
|
|
|
|
public function __construct(private readonly array $rows)
|
|
{
|
|
$this->num_rows = count($rows);
|
|
}
|
|
|
|
public function fetch_assoc(): ?array
|
|
{
|
|
return $this->rows[0] ?? null;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!class_exists('PasswordResetTokenExpiryFakeDb')) {
|
|
class PasswordResetTokenExpiryFakeDb
|
|
{
|
|
public array $queries = [];
|
|
|
|
public function __construct(private readonly array $results)
|
|
{
|
|
}
|
|
|
|
public function escape_string(string $string): string
|
|
{
|
|
return addslashes($string);
|
|
}
|
|
|
|
public function query(string $sql): PasswordResetTokenExpiryFakeResult
|
|
{
|
|
$this->queries[] = $sql;
|
|
|
|
return $this->results[count($this->queries) - 1] ?? new PasswordResetTokenExpiryFakeResult([]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!class_exists('PasswordResetTokenExpiryProbe')) {
|
|
class PasswordResetTokenExpiryProbe extends customer_password_reset_keys_o
|
|
{
|
|
public function getObjectProperties(): void
|
|
{
|
|
}
|
|
|
|
public function forceSelectedId(int $id): void
|
|
{
|
|
$this->id = $id;
|
|
}
|
|
}
|
|
}
|
|
|
|
beforeEach(function (): void {
|
|
$this->previousDb = $GLOBALS['db'] ?? null;
|
|
});
|
|
|
|
afterEach(function (): void {
|
|
if ($this->previousDb !== null) {
|
|
$GLOBALS['db'] = $this->previousDb;
|
|
return;
|
|
}
|
|
|
|
unset($GLOBALS['db']);
|
|
});
|
|
|
|
it('keeps password reset tokens valid for 72 hours', function (): void {
|
|
expect(customer_password_reset_keys_o::TOKEN_EXPIRY_SECONDS)->toBe(72 * 60 * 60);
|
|
});
|
|
|
|
it('looks up reset tokens using the database 72 hour validity window', function (): void {
|
|
$GLOBALS['db'] = new PasswordResetTokenExpiryFakeDb([
|
|
new PasswordResetTokenExpiryFakeResult([['id' => 42]]),
|
|
]);
|
|
|
|
$token = str_repeat('a', customer_password_reset_keys_o::TOKEN_LENGTH);
|
|
$probe = new PasswordResetTokenExpiryProbe();
|
|
|
|
$found = $probe->findValidByToken($token);
|
|
|
|
expect($found)->toBe($probe)
|
|
->and($probe->id)->toBe(42)
|
|
->and($GLOBALS['db']->queries[0])->toContain('created_at >= DATE_SUB(NOW(), INTERVAL 259200 SECOND)')
|
|
->and($GLOBALS['db']->queries[0])->not->toContain("DATE_SUB('");
|
|
});
|
|
|
|
it('uses the same database 72 hour window for the selected token guard', function (): void {
|
|
$GLOBALS['db'] = new PasswordResetTokenExpiryFakeDb([
|
|
new PasswordResetTokenExpiryFakeResult([['id' => 42]]),
|
|
]);
|
|
|
|
$probe = new PasswordResetTokenExpiryProbe();
|
|
$probe->forceSelectedId(42);
|
|
|
|
expect($probe->isValidToken())->toBeTrue()
|
|
->and($GLOBALS['db']->queries[0])->toContain('id = 42')
|
|
->and($GLOBALS['db']->queries[0])->toContain('created_at >= DATE_SUB(NOW(), INTERVAL 259200 SECOND)');
|
|
});
|