Fix Bus.unsubscribe splice(-1) bug and add auth validation to copilot-stream endpoint

Fixes two security issues:

1. CLI Bus.unsubscribe (issue #492): Fix splice(-1,1) bug when indexOf returns -1.
   - When unsubscribe is called twice, splice(-1,1) removes the last element instead of doing nothing.
   - Guard with indexOf check before splicing.

2. Copilot stream auth validation (issue #493/#494): Return 401 when Bearer token is missing.
   - Extract and validate apiKey before passing to controller.
   - Prevents undefined apiKey from bypassing auth checks.
This commit is contained in:
fuleinist 2026-04-17 06:06:40 +08:00
parent 2133d7226f
commit e0ca073f82
3 changed files with 14 additions and 3 deletions

View file

@ -29,7 +29,8 @@ export class InMemoryBus implements IBus {
}
this.subscribers.get(runId)!.push(handler);
return () => {
this.subscribers.get(runId)!.splice(this.subscribers.get(runId)!.indexOf(handler), 1);
const idx = this.subscribers.get(runId)!.indexOf(handler);
if (idx !== -1) this.subscribers.get(runId)!.splice(idx, 1);
};
}
}

View file

@ -10,6 +10,15 @@ export async function GET(request: Request, props: { params: Promise<{ streamId:
// get user data
const user = await requireAuth();
// Validate auth token
const apiKey = request.headers.get("Authorization")?.split(" ")[1];
if (!apiKey) {
return new Response(JSON.stringify({ error: "Missing or invalid Authorization header" }), {
status: 401,
headers: { "Content-Type": "application/json" },
});
}
const runCopilotCachedTurnController = container.resolve<IRunCopilotCachedTurnController>("runCopilotCachedTurnController");
const encoder = new TextEncoder();
@ -21,7 +30,7 @@ export async function GET(request: Request, props: { params: Promise<{ streamId:
for await (const event of runCopilotCachedTurnController.execute({
caller: "user",
userId: user.id,
apiKey: request.headers.get("Authorization")?.split(" ")[1],
apiKey,
key: params.streamId,
})) {
// Check if this is a content event

View file

@ -29,7 +29,8 @@ export class InMemoryBus implements IBus {
}
this.subscribers.get(runId)!.push(handler);
return () => {
this.subscribers.get(runId)!.splice(this.subscribers.get(runId)!.indexOf(handler), 1);
const idx = this.subscribers.get(runId)!.indexOf(handler);
if (idx !== -1) this.subscribers.get(runId)!.splice(idx, 1);
};
}
}