fix: scoped tokens rejected on /command — auth gate ordering bug

The blanket validateAuth() gate (root-only) sat above the /command
endpoint, rejecting all scoped tokens with 401 before they reached
getTokenInfo(). Moved /command above the gate so both root and
scoped tokens are accepted. This was the bug Wintermute hit.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-04-05 00:06:52 -07:00
parent d5753b16f1
commit 87a3e62569
+17 -17
View File
@@ -1792,7 +1792,23 @@ async function start() {
return new Response(JSON.stringify({ ok: true }), { status: 200, headers: { 'Content-Type': 'application/json' } });
}
// ─── Auth-required endpoints ──────────────────────────────────
// ─── Command endpoint (accepts both root AND scoped tokens) ────
// Must be checked BEFORE the blanket root-only auth gate below,
// because scoped tokens from /connect are valid for /command.
if (url.pathname === '/command' && req.method === 'POST') {
const tokenInfo = getTokenInfo(req);
if (!tokenInfo) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
});
}
resetIdleTimer();
const body = await req.json();
return handleCommand(body, tokenInfo);
}
// ─── Auth-required endpoints (root token only) ─────────────────
if (!validateAuth(req)) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
@@ -1952,22 +1968,6 @@ async function start() {
});
}
// ─── Command endpoint ──────────────────────────────────────────
if (url.pathname === '/command' && req.method === 'POST') {
// Accept both root token and scoped tokens
const tokenInfo = getTokenInfo(req);
if (!tokenInfo) {
return new Response(JSON.stringify({ error: 'Unauthorized' }), {
status: 401,
headers: { 'Content-Type': 'application/json' },
});
}
resetIdleTimer(); // Only commands reset idle timer
const body = await req.json();
return handleCommand(body, tokenInfo);
}
return new Response('Not found', { status: 404 });
},
});