mirror of
https://github.com/garrytan/gstack.git
synced 2026-09-14 17:05:28 +02:00
fix(browse): revokeToken deletes ALL tokens for a clientId, not the first Map hit
revokeToken deleted the first Map entry matching the clientId and returned true. After a normal pairing, two entries share one clientId: the spent setup key (kept by exchangeSetupKey for idempotent re-exchange) and the session token, in that insertion order. Revoke ate the setup key, reported success, and the live session survived: DELETE /token/<id> returned a false 200 while /agents kept listing the agent. Worse, an unspent setup key created after the session survived revoke, so a "revoked" agent could POST /connect and mint a fresh session within the key's 5-minute validity window. revokeToken now deletes every matching entry and returns the delete count (truthy-compatible with the old boolean). The DELETE /token handler logs "Revoked N token(s)" and returns tokens_deleted so the multi-token class stays visible; revokeSkillToken wraps Boolean() to keep its documented contract. Regression tests pin shapes a (spent-key shadowing), b (re-grant hole), c (multiple pending keys), and bystander isolation. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
9da6692930
commit
b9eb108f16
@@ -2337,8 +2337,8 @@ export function buildFetchHandler(cfg: ServerConfig): ServerHandle {
|
||||
status: 404, headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
console.log(`[browse] Revoked token for: ${clientId}`);
|
||||
return new Response(JSON.stringify({ revoked: clientId }), {
|
||||
console.log(`[browse] Revoked ${revoked} token(s) for: ${clientId}`);
|
||||
return new Response(JSON.stringify({ revoked: clientId, tokens_deleted: revoked }), {
|
||||
status: 200, headers: { 'Content-Type': 'application/json' },
|
||||
});
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user