Files
OmniRoute/src/lib/usage/callLogApiKeyContext.ts
Alex 53f8284842 fix(api): enforce image generation API key auth (#8306)
* fix(api): enforce image generation API key auth

* fix(api): align image route auth guard with clientApiPolicy

The route-level guard added for image generation was stricter than the
authz middleware that already fronts /api/v1/* (src/proxy.ts →
clientApiPolicy), so requests the pipeline admits were 401'd by the
handler:

- A cookie-authenticated dashboard session was rejected under
  REQUIRE_API_KEY=true. The dashboard Media page
  (dashboard/cache/media) and the Playground call these routes with a
  session and no Bearer — the same mismatch already fixed for
  /api/playground/presets.
- A presented invalid key was rejected even with REQUIRE_API_KEY=false,
  where clientApiPolicy (#2257) and the sibling /v1/embeddings and
  /v1/web/fetch routes degrade a stale CLI key to anonymous instead.

Extract the shared guard into shared/utils/clientApiRouteAuth so both
image routes (and future /v1 handlers) mirror the middleware contract
instead of re-deriving it, and drop the now-dead auth imports.

Also switch the call-log attribution fallback back to `||`: with `??`,
an empty-string apiKeyId/apiKeyName would be persisted verbatim and
would block the request-scoped context, which the previous
`entry.apiKeyId || null` never did.

Tests: cover the dashboard-session and keyless-mode-invalid-key
branches, and split the auth/attribution cases into
image-generation-route-auth.test.ts to stay under the 800-line
new-test-file cap.

Co-authored-by: Claude Opus 5 <noreply@anthropic.com>

---------

Co-authored-by: alexey.nazarov@softmg.ru <alexey.nazarov@softmg.ru>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
2026-07-27 22:38:25 -03:00

27 lines
841 B
TypeScript

import { AsyncLocalStorage } from "node:async_hooks";
export interface CallLogApiKeyContext {
apiKeyId: string | null;
apiKeyName: string | null;
}
const callLogApiKeyContext = new AsyncLocalStorage<CallLogApiKeyContext>();
/**
* Bind API-key attribution to every call log emitted by one request.
*
* Modal handlers fan out into provider-specific helpers that write their own
* call logs. Request-scoped storage keeps that attribution available without
* threading identity parameters through every provider handler.
*/
export function runWithCallLogApiKeyContext<TResult>(
context: CallLogApiKeyContext,
callback: () => TResult
): TResult {
return callLogApiKeyContext.run(context, callback);
}
export function getCallLogApiKeyContext(): CallLogApiKeyContext | null {
return callLogApiKeyContext.getStore() ?? null;
}