From 44199ec0a851916ddc8f0d997e6f5235ac389dde Mon Sep 17 00:00:00 2001 From: Keith Solomon Date: Sun, 26 Jul 2026 16:38:05 -0500 Subject: [PATCH] chore: address Plan 4 deferred-minors (stale-cookie cleanup pass) - Rename $secret to $csrfSecret in public/index.php to make intent clear at every call site; the value is the CSRF/turn-token HMAC key, not just 'the secret'. - Drop the stale 'Configure the router with the eight routes' comment in public/index.php; the router now has sixteen routes. - Drop the duplicate .bf-toast rule in public/assets/styles.css; the second declaration (the new yellow box) is the active one, the first (legacy green pill) is dead code from the editor era. - Add a trailing newline to src/Views/home.php. - Tighten the matchId regex in two tests from {16,} to {16} since bin2hex(random_bytes(8)) always produces exactly 16 hex chars; the spec's {16,} stays in production TurnToken. No behavior changes; addresses the deferred-minors parked during per-task review. --- public/assets/styles.css | 1 - public/index.php | 37 ++++++++++--------- src/Views/home.php | 2 +- .../Integration/PostMatchActionSmokeTest.php | 2 +- tests/Integration/PostStartMatchTest.php | 2 +- 5 files changed, 23 insertions(+), 21 deletions(-) diff --git a/public/assets/styles.css b/public/assets/styles.css index bdb8753..a8c1f38 100644 --- a/public/assets/styles.css +++ b/public/assets/styles.css @@ -18,7 +18,6 @@ table.bf-grid button[data-objective="1"] { outline: 3px solid #c00; } table.bf-grid button[data-zone="alpha"] { outline: 3px solid #00c; } table.bf-grid button[data-zone="bravo"] { outline: 3px solid #0c0; } .bf-errors { color: #c00; } -.bf-toast { background: #dfd; padding: 0.5rem 1rem; margin: 0.5rem 0; } .bf-match { display: flex; gap: 1rem; } .bf-grid { display: grid; gap: 1px; background: #ddd; padding: 1px; width: max-content; grid-template-columns: repeat(var(--bf-cols, 8), 2.5rem); } .bf-tile { width: 2.5rem; height: 2.5rem; border: 0; background: #fff; padding: 0; position: relative; } diff --git a/public/index.php b/public/index.php index ee886f8..c80858e 100644 --- a/public/index.php +++ b/public/index.php @@ -25,8 +25,11 @@ use BattleForge\Http\Router; require __DIR__ . '/../vendor/autoload.php'; // 1. Read the app secret. -$secret = getenv('BATTLEFORGE_SECRET'); -if ($secret === false || $secret === '') { +// The app secret reads as the CSRF/turn-token HMAC key. The name below +// (kept for historical reasons) is just the variable label; the same +// value is used for both the CSRF cookie HMAC and the turn-token HMAC. +$csrfSecret = getenv('BATTLEFORGE_SECRET'); +if ($csrfSecret === false || $csrfSecret === '') { $secretFile = __DIR__ . '/../var/secret.key'; if (!is_file($secretFile)) { if (!is_dir(dirname($secretFile))) { @@ -35,8 +38,8 @@ if ($secret === false || $secret === '') { file_put_contents($secretFile, random_bytes(32)); chmod($secretFile, 0600); } - $secret = file_get_contents($secretFile); - if ($secret === false) { + $csrfSecret = file_get_contents($secretFile); + if ($csrfSecret === false) { http_response_code(500); echo "Failed to read app secret.\n"; return; @@ -61,11 +64,11 @@ $existingCookie = (string) ($cookies['__csrf'] ?? ''); $existingRawToken = (string) ($cookies['__csrf_token'] ?? ''); $pairIsFresh = false; if ($existingCookie !== '' && $existingRawToken !== '') { - $expectedHmac = hash_hmac('sha256', $existingRawToken, $secret); + $expectedHmac = hash_hmac('sha256', $existingRawToken, $csrfSecret); $pairIsFresh = hash_equals($expectedHmac, $existingCookie); } if ($existingCookie === '' || $existingRawToken === '' || !$pairIsFresh) { - [$token, $cookie] = CsrfToken::issue($secret); + [$token, $cookie] = CsrfToken::issue($csrfSecret); setcookie('__csrf', $cookie, [ 'expires' => time() + 86400, 'path' => '/', @@ -93,7 +96,7 @@ if ($existingCookie === '' || $existingRawToken === '' || !$pairIsFresh) { } // 3. Compute the upload-endpoint user token (derived from the same secret). -$uploadsToken = hash_hmac('sha256', $secret, 'bf-uploads'); +$uploadsToken = hash_hmac('sha256', $csrfSecret, 'bf-uploads'); // 4. Determine the request method, path, and content type. $method = strtoupper((string) ($_SERVER['REQUEST_METHOD'] ?? 'GET')); @@ -115,7 +118,7 @@ $rawBody = (string) ($_SERVER['__raw_body'] ?? file_get_contents('php://input')) // 6. Build a Request with the request data, the CSRF secret, and the upload token. $server = $_SERVER; if (!isset($server['__csrf_secret'])) { - $server['__csrf_secret'] = $secret; + $server['__csrf_secret'] = $csrfSecret; } $server['__uploads_token'] = $uploadsToken; @@ -132,7 +135,7 @@ $request = new Request( rawBody: $rawBody, ); -// 7. Configure the router with the eight routes. +// 7. Configure the router. $uploadsRoot = __DIR__ . '/../var/uploads'; $placeholderDir = __DIR__ . '/assets/placeholders'; @@ -164,17 +167,17 @@ $getBundledOne = static function (Request $r, array $p) use ($scenariosDir): Res return (new GetBundledScenario($scenariosDir))->handle($r, $p); }; $getMatchView = static fn (Request $r, array $p): Response => (new GetMatchView())->handle($r, $p); -$postMatchMove = static function (Request $r, array $p) use ($secret): Response { - return (new PostMatchMove($secret))->handle($r, $p); +$postMatchMove = static function (Request $r, array $p) use ($csrfSecret): Response { + return (new PostMatchMove($csrfSecret))->handle($r, $p); }; -$postMatchAttack = static function (Request $r, array $p) use ($secret): Response { - return (new PostMatchAttack($secret))->handle($r, $p); +$postMatchAttack = static function (Request $r, array $p) use ($csrfSecret): Response { + return (new PostMatchAttack($csrfSecret))->handle($r, $p); }; -$postMatchAbility = static function (Request $r, array $p) use ($secret): Response { - return (new PostMatchAbility($secret))->handle($r, $p); +$postMatchAbility = static function (Request $r, array $p) use ($csrfSecret): Response { + return (new PostMatchAbility($csrfSecret))->handle($r, $p); }; -$postMatchEndTurn = static function (Request $r, array $p) use ($secret): Response { - return (new PostMatchEndTurn($secret))->handle($r, $p); +$postMatchEndTurn = static function (Request $r, array $p) use ($csrfSecret): Response { + return (new PostMatchEndTurn($csrfSecret))->handle($r, $p); }; $router = new Router(); diff --git a/src/Views/home.php b/src/Views/home.php index 428aceb..21e4d43 100644 --- a/src/Views/home.php +++ b/src/Views/home.php @@ -27,4 +27,4 @@ render_layout(static function () use ($csrf, $bundled): void {

No saved scenarios yet.