/** * Authentication Middleware * * Validates API keys for incoming requests. */ import * as http from 'node:http'; import { logger } from '../../logger.ts'; /** * Authentication middleware for API key validation */ export class AuthMiddleware { private apiKeys: Set; private allowNoAuth: boolean; constructor(apiKeys: string[], allowNoAuth: boolean = false) { this.apiKeys = new Set(apiKeys); this.allowNoAuth = allowNoAuth; if (this.apiKeys.size === 0 && !allowNoAuth) { logger.warn('No API keys configured - authentication will fail for all requests'); } } /** * Authenticate a request */ public authenticate(req: http.IncomingMessage): boolean { // If no keys configured and allowNoAuth is true, allow all requests if (this.apiKeys.size === 0 && this.allowNoAuth) { return true; } const authHeader = req.headers.authorization; if (!authHeader) { logger.dim('Request rejected: No Authorization header'); return false; } // Extract Bearer token const match = authHeader.match(/^Bearer\s+(.+)$/i); if (!match) { logger.dim('Request rejected: Invalid Authorization header format'); return false; } const apiKey = match[1]; // Check if key is valid if (!this.apiKeys.has(apiKey)) { logger.dim('Request rejected: Invalid API key'); return false; } return true; } /** * Get API key from request (if authenticated) */ public getApiKey(req: http.IncomingMessage): string | null { const authHeader = req.headers.authorization; if (!authHeader) { return null; } const match = authHeader.match(/^Bearer\s+(.+)$/i); return match ? match[1] : null; } /** * Add an API key */ public addApiKey(key: string): void { this.apiKeys.add(key); logger.info('API key added'); } /** * Remove an API key */ public removeApiKey(key: string): boolean { const removed = this.apiKeys.delete(key); if (removed) { logger.info('API key removed'); } return removed; } /** * Get count of configured API keys */ public getKeyCount(): number { return this.apiKeys.size; } /** * Check if authentication is required */ public isAuthRequired(): boolean { return !this.allowNoAuth || this.apiKeys.size > 0; } }