<?php
/** Local JWT verification: the fast path that removes an upstream call per request. */
putenv('SUPABASE_JWT_SECRET=902343981eb82f43ff7a3757f3fcf25f14a2b9c729454eae5029ee3d1f189eb7');
putenv('SUPABASE_URL=http://127.0.0.1:1');   // must never be reached on this path
require_once dirname(__DIR__) . '/includes/auth.php';

$SECRET = '902343981eb82f43ff7a3757f3fcf25f14a2b9c729454eae5029ee3d1f189eb7';
$fail = 0;
function check($l, $c, $d = '') { global $fail; if ($c) { echo "  ok    $l\n"; } else { $fail++; echo "  FAIL  $l" . ($d ? " — $d" : '') . "\n"; } }

function b64u(string $s): string { return rtrim(strtr(base64_encode($s), '+/', '-_'), '='); }
function mint(array $payload, string $secret, bool $valid = true): string {
    $h = b64u(json_encode(['alg' => 'HS256', 'typ' => 'JWT']));
    $p = b64u(json_encode($payload));
    $sig = hash_hmac('sha256', "$h.$p", $valid ? $secret : 'wrong-secret', true);
    return "$h.$p." . b64u($sig);
}

$uid = '5ed4d72d-555f-4d19-8315-204dafd3a2e7';

$t = mint(['sub' => $uid, 'role' => 'authenticated', 'exp' => time() + 3600], $SECRET);
$u = verifyTokenLocally($t);
check('a correctly signed token verifies with no network call', $u && $u['id'] === $uid, json_encode($u));

$t = mint(['sub' => $uid, 'exp' => time() + 3600], $SECRET, false);
check('a token signed with the wrong secret is rejected', verifyTokenLocally($t) === null);

$t = mint(['sub' => $uid, 'exp' => time() - 10], $SECRET);
check('an expired token is rejected', verifyTokenLocally($t) === null);

$t = mint(['role' => 'authenticated', 'exp' => time() + 3600], $SECRET);
check('a token with no subject is rejected', verifyTokenLocally($t) === null);

// alg:none downgrade — a classic JWT attack.
$h = b64u(json_encode(['alg' => 'none', 'typ' => 'JWT']));
$p = b64u(json_encode(['sub' => $uid, 'exp' => time() + 3600]));
check('an alg=none token is rejected', verifyTokenLocally("$h.$p.") === null);

check('a malformed token is rejected', verifyTokenLocally('not-a-jwt') === null);
check('an empty token is rejected', verifyTokenLocally('') === null);

// Tampered payload keeps the original signature.
$good = mint(['sub' => $uid, 'exp' => time() + 3600], $SECRET);
[$h2, $p2, $s2] = explode('.', $good);
$evil = $h2 . '.' . b64u(json_encode(['sub' => '00000000-0000-0000-0000-000000000000', 'exp' => time() + 3600])) . '.' . $s2;
check('a tampered payload is rejected', verifyTokenLocally($evil) === null);

echo "\n";
if ($fail) { echo "$fail FAILURE(S)\n"; exit(1); }
echo "ALL AUTH CHECKS PASSED\n";
