Files

106 lines
2.3 KiB
TypeScript
Raw Permalink Normal View History

2026-01-30 03:16:57 +00:00
/**
* 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<string>;
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;
}
}