/** * Shared API key and admin-access helpers. */ import { config } from '../config.js'; import { createOpenAIError } from '../format/openai-compat.js'; import { logger } from '../utils/logger.js'; export function extractProvidedApiKey(req) { const authHeader = req.headers['authorization']; const xApiKey = req.headers['x-api-key']; if (authHeader && authHeader.startsWith('Bearer ')) { return authHeader.substring(7); } if (xApiKey) { return xApiKey; } return ''; } export function extractWebuiPassword(req) { return req.headers['x-webui-password'] || req.query.password || ''; } export function hasValidApiKey(req) { return Boolean(config.apiKey) && extractProvidedApiKey(req) === config.apiKey; } export function hasAdminAccess(req) { if (hasValidApiKey(req)) { return true; } if (config.webuiPassword && extractWebuiPassword(req) === config.webuiPassword) { return true; } return false; } export function requireAdminAccess(req, res, next) { if (hasAdminAccess(req)) { return next(); } logger.warn(`[API] Unauthorized admin request from ${req.ip} to ${req.method} ${req.originalUrl}`); return res.status(401).json({ type: 'error', error: { type: 'authentication_error', message: 'Authentication required' } }); } export function createV1ApiKeyMiddleware() { return (req, res, next) => { if (!config.apiKey) { logger.error('[API] PROXY_API_KEY is not configured; rejecting /v1 request'); const isOpenAIEndpoint = req.path === '/chat/completions' || req.path === '/models'; if (isOpenAIEndpoint) { return res.status(503).json(createOpenAIError('Proxy API key is not configured', { type: 'api_error', code: 'service_unavailable' })); } return res.status(503).json({ type: 'error', error: { type: 'api_error', message: 'Proxy API key is not configured' } }); } const providedKey = extractProvidedApiKey(req); if (!providedKey || providedKey !== config.apiKey) { logger.warn(`[API] Unauthorized request from ${req.ip}, invalid API key`); const isOpenAIEndpoint = req.path === '/chat/completions' || req.path === '/models'; if (isOpenAIEndpoint) { return res.status(401).json(createOpenAIError('Invalid or missing API key', { type: 'authentication_error', code: 'invalid_api_key' })); } return res.status(401).json({ type: 'error', error: { type: 'authentication_error', message: 'Invalid or missing API key' } }); } next(); }; }