initial
This commit is contained in:
105
ts/api/middleware/auth.ts
Normal file
105
ts/api/middleware/auth.ts
Normal file
@@ -0,0 +1,105 @@
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user