mirror of
https://codeberg.org/PostERG/xamxam.git
synced 2026-09-25 01:53:03 +02:00
add password-reset smoke test + AdminAuth DI + OneTimeToken empty-context redeem fix
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
<?php
|
||||
/**
|
||||
* smoke-test-password-reset.php — end-to-end smoke test for the password-reset
|
||||
* flow, against a throwaway SQLite DB (never touches the live dev/prod DB).
|
||||
*
|
||||
* Covers:
|
||||
* 1. Issue a reset token via AdminAuth (shared OneTimeToken model).
|
||||
* 2. Invalid / short / one-time redeem semantics.
|
||||
* 3. A successful redeem installs a new bcrypt hash and invalidates the token.
|
||||
*
|
||||
* Usage:
|
||||
* php scripts/smoke-test-password-reset.php
|
||||
*
|
||||
* Exits 0 on success, 1 on any failure. No email is sent (issue only, not
|
||||
* requestPasswordReset()).
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
$root = dirname(__DIR__);
|
||||
|
||||
require_once $root . '/app/bootstrap.php';
|
||||
require_once $root . '/app/src/Database.php';
|
||||
require_once $root . '/app/src/AdminAuth.php';
|
||||
require_once $root . '/app/src/OneTimeToken.php';
|
||||
|
||||
$failures = 0;
|
||||
function check(string $label, bool $ok): void
|
||||
{
|
||||
global $failures;
|
||||
echo ($ok ? " ✓ " : " ✗ ") . $label . "\n";
|
||||
if (!$ok) {
|
||||
$failures++;
|
||||
}
|
||||
}
|
||||
|
||||
// ── Build a throwaway DB ─────────────────────────────────────────────────────
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'xamxam-reset-');
|
||||
unlink($tmp);
|
||||
$tmpDb = $tmp . '.db';
|
||||
|
||||
$pdo = new PDO('sqlite:' . $tmpDb);
|
||||
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
|
||||
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
|
||||
$pdo->exec('PRAGMA foreign_keys = ON');
|
||||
|
||||
$schema = APP_ROOT . '/storage/schema.sql';
|
||||
$pdo->exec(file_get_contents($schema));
|
||||
|
||||
$db = new Database($tmpDb); // real connection, isolated file
|
||||
AdminAuth::setDatabase($db);
|
||||
|
||||
// ── Seed an existing admin password ─────────────────────────────────────────
|
||||
$db->setSetting('admin_password_hash', password_hash('initial-password-123', PASSWORD_BCRYPT));
|
||||
check('admin password hash configured', AdminAuth::hasPassword());
|
||||
|
||||
// ── 1. Issue a reset token ───────────────────────────────────────────────────
|
||||
$token = AdminAuth::issuePasswordResetToken(1800);
|
||||
check('issued 256-bit hex token', (bool) preg_match('/^[0-9a-f]{64}$/', $token));
|
||||
|
||||
$ot = new OneTimeToken($db->getPDO());
|
||||
check('token is valid (shared model)', $ot->isValid('password_reset', $token));
|
||||
|
||||
// ── 2. Reject short password ─────────────────────────────────────────────────
|
||||
check('rejects <12 char password', AdminAuth::redeemPasswordResetToken($token, 'short') === false);
|
||||
|
||||
// ── 3. Successful redeem installs a new hash ────────────────────────────────
|
||||
$before = $db->getSetting('admin_password_hash');
|
||||
check('redeems valid token + 12-char password', AdminAuth::redeemPasswordResetToken($token, 'new-secure-password-999'));
|
||||
$after = $db->getSetting('admin_password_hash');
|
||||
check('hash changed', $after !== '' && $after !== $before);
|
||||
check('new password verifies', password_verify('new-secure-password-999', $after));
|
||||
check('old password no longer verifies', !password_verify('initial-password-123', $after));
|
||||
|
||||
// ── 4. One-time use ─────────────────────────────────────────────────────────
|
||||
check('token now invalid (consumed)', $ot->isValid('password_reset', $token) === false);
|
||||
check('second redeem fails', AdminAuth::redeemPasswordResetToken($token, 'another-secure-password-000') === false);
|
||||
|
||||
// ── 5. Unknown token fails ──────────────────────────────────────────────────
|
||||
check('unknown token fails', AdminAuth::redeemPasswordResetToken(str_repeat('ab', 32), 'another-secure-password-000') === false);
|
||||
|
||||
// ── Cleanup ─────────────────────────────────────────────────────────────────
|
||||
$db->setSetting('admin_password_hash', '');
|
||||
unlink($tmpDb);
|
||||
|
||||
echo "\n";
|
||||
if ($failures === 0) {
|
||||
echo "✅ Password-reset smoke test passed.\n";
|
||||
exit(0);
|
||||
}
|
||||
echo "❌ {$failures} check(s) failed.\n";
|
||||
exit(1);
|
||||
Reference in New Issue
Block a user