{"version":3,"sources":["../../src/auth/index.ts","../../src/auth/api-key.ts"],"sourcesContent":["/**\r\n * Credits auth providers - barrel exports\r\n *\r\n * Provides authentication abstraction for credits system\r\n */\r\n\r\n// Types and interfaces\r\nexport type {\r\n  ICreditsAuthProvider,\r\n  CreditsAuthProviderFactory,\r\n  CreditsUser,\r\n} from \"./types.js\";\r\n\r\n// API Key implementation (for admin routes)\r\nexport {\r\n  ApiKeyCreditsProvider,\r\n  verifyAdminApiKey,\r\n  createApiKeyProvider,\r\n  verifyBearerToken,\r\n} from \"./api-key.js\";\r\n","import type { ICreditsAuthProvider, CreditsUser } from \"./types.js\";\r\n\r\n/**\r\n * Timing-safe string comparison to prevent timing attacks\r\n */\r\nfunction timingSafeEqual(a: string, b: string): boolean {\r\n  if (!a || !b) {\r\n    return false;\r\n  }\r\n\r\n  // Pad strings to same length to prevent length-based timing attacks\r\n  const maxLength = Math.max(a.length, b.length);\r\n  const paddedA = a.padEnd(maxLength);\r\n  const paddedB = b.padEnd(maxLength);\r\n\r\n  let result = 0;\r\n  for (let i = 0; i < maxLength; i++) {\r\n    result |= paddedA.charCodeAt(i) ^ paddedB.charCodeAt(i);\r\n  }\r\n\r\n  // Also check that lengths were originally equal\r\n  return result === 0 && a.length === b.length;\r\n}\r\n\r\n/**\r\n * Verify a Bearer token from an Authorization header\r\n *\r\n * @param header - The Authorization header value (e.g., \"Bearer secret123\")\r\n * @param secret - The expected secret value\r\n * @returns True if token is valid\r\n */\r\nexport function verifyBearerToken(header: string | null, secret: string): boolean {\r\n  if (!header || !secret) {\r\n    return false;\r\n  }\r\n\r\n  // Extract token from \"Bearer {token}\" format\r\n  const token = header.replace(/^Bearer\\s+/i, \"\");\r\n\r\n  // Use timing-safe comparison\r\n  return timingSafeEqual(token, secret);\r\n}\r\n\r\n/**\r\n * API Key auth provider for admin routes\r\n *\r\n * Uses Bearer token authentication for external API access\r\n * The API key is stored in CREDITS_ADMIN_API_KEY environment variable\r\n */\r\nexport class ApiKeyCreditsProvider implements ICreditsAuthProvider {\r\n  private readonly apiKey: string | undefined;\r\n  private isValidated = false;\r\n\r\n  constructor(authHeader?: string | null, apiKey?: string) {\r\n    this.apiKey = apiKey ?? process.env.CREDITS_ADMIN_API_KEY;\r\n\r\n    // Validate the provided auth header using timing-safe comparison\r\n    if (authHeader && this.apiKey) {\r\n      this.isValidated = verifyBearerToken(authHeader, this.apiKey);\r\n    }\r\n  }\r\n\r\n  async getCurrentUser(): Promise<CreditsUser | null> {\r\n    if (!this.isValidated) {\r\n      return null;\r\n    }\r\n\r\n    // API key auth returns a special \"admin\" user\r\n    return {\r\n      id: \"api-admin\",\r\n      email: \"api@admin.internal\",\r\n      name: \"API Admin\",\r\n    };\r\n  }\r\n\r\n  async verifyAdminAccess(): Promise<boolean> {\r\n    return this.isValidated;\r\n  }\r\n}\r\n\r\n/**\r\n * Verify an API key from a request header\r\n * @param authHeader - Authorization header value\r\n * @param apiKey - Optional API key to use (defaults to CREDITS_ADMIN_API_KEY env var)\r\n * @returns True if API key is valid\r\n */\r\nexport function verifyAdminApiKey(authHeader: string | null, apiKey?: string): boolean {\r\n  if (!authHeader) {\r\n    return false;\r\n  }\r\n\r\n  const expectedKey = apiKey ?? process.env.CREDITS_ADMIN_API_KEY;\r\n  if (!expectedKey) {\r\n    console.warn(\"CREDITS_ADMIN_API_KEY not configured\");\r\n    return false;\r\n  }\r\n\r\n  // Use timing-safe comparison to prevent timing attacks\r\n  return verifyBearerToken(authHeader, expectedKey);\r\n}\r\n\r\n/**\r\n * Create an API key auth provider from a request\r\n * @param request - Request object with headers\r\n * @param apiKey - Optional API key to use\r\n * @returns API key auth provider\r\n */\r\nexport function createApiKeyProvider(request: Request, apiKey?: string): ApiKeyCreditsProvider {\r\n  const authHeader = request.headers.get(\"Authorization\");\r\n  return new ApiKeyCreditsProvider(authHeader, apiKey);\r\n}\r\n"],"mappings":";;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACKA,SAAS,gBAAgB,GAAW,GAAoB;AACtD,MAAI,CAAC,KAAK,CAAC,GAAG;AACZ,WAAO;AAAA,EACT;AAGA,QAAM,YAAY,KAAK,IAAI,EAAE,QAAQ,EAAE,MAAM;AAC7C,QAAM,UAAU,EAAE,OAAO,SAAS;AAClC,QAAM,UAAU,EAAE,OAAO,SAAS;AAElC,MAAI,SAAS;AACb,WAAS,IAAI,GAAG,IAAI,WAAW,KAAK;AAClC,cAAU,QAAQ,WAAW,CAAC,IAAI,QAAQ,WAAW,CAAC;AAAA,EACxD;AAGA,SAAO,WAAW,KAAK,EAAE,WAAW,EAAE;AACxC;AASO,SAAS,kBAAkB,QAAuB,QAAyB;AAChF,MAAI,CAAC,UAAU,CAAC,QAAQ;AACtB,WAAO;AAAA,EACT;AAGA,QAAM,QAAQ,OAAO,QAAQ,eAAe,EAAE;AAG9C,SAAO,gBAAgB,OAAO,MAAM;AACtC;AAQO,IAAM,wBAAN,MAA4D;AAAA,EAChD;AAAA,EACT,cAAc;AAAA,EAEtB,YAAY,YAA4B,QAAiB;AACvD,SAAK,SAAS,UAAU,QAAQ,IAAI;AAGpC,QAAI,cAAc,KAAK,QAAQ;AAC7B,WAAK,cAAc,kBAAkB,YAAY,KAAK,MAAM;AAAA,IAC9D;AAAA,EACF;AAAA,EAEA,MAAM,iBAA8C;AAClD,QAAI,CAAC,KAAK,aAAa;AACrB,aAAO;AAAA,IACT;AAGA,WAAO;AAAA,MACL,IAAI;AAAA,MACJ,OAAO;AAAA,MACP,MAAM;AAAA,IACR;AAAA,EACF;AAAA,EAEA,MAAM,oBAAsC;AAC1C,WAAO,KAAK;AAAA,EACd;AACF;AAQO,SAAS,kBAAkB,YAA2B,QAA0B;AACrF,MAAI,CAAC,YAAY;AACf,WAAO;AAAA,EACT;AAEA,QAAM,cAAc,UAAU,QAAQ,IAAI;AAC1C,MAAI,CAAC,aAAa;AAChB,YAAQ,KAAK,sCAAsC;AACnD,WAAO;AAAA,EACT;AAGA,SAAO,kBAAkB,YAAY,WAAW;AAClD;AAQO,SAAS,qBAAqB,SAAkB,QAAwC;AAC7F,QAAM,aAAa,QAAQ,QAAQ,IAAI,eAAe;AACtD,SAAO,IAAI,sBAAsB,YAAY,MAAM;AACrD;","names":[]}