UNPKG

@ai-capabilities-suite/mcp-debugger-core

Version:

Core debugging engine for Node.js and TypeScript applications. Provides Inspector Protocol integration, breakpoint management, variable inspection, execution control, profiling, hang detection, and source map support.

251 lines 7.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.AuthManager = void 0; const crypto_1 = require("crypto"); /** * Manages authentication for MCP connections * Provides token-based authentication and API key validation */ class AuthManager { constructor(config = { enabled: false }) { this.tokens = new Map(); this.apiKeys = new Map(); this.validTokens = new Set(); // Pre-configured valid tokens this.config = { tokenExpirationMs: 60 * 60 * 1000, // 1 hour default ...config, }; // Add pre-configured tokens if provided if (config.tokens) { config.tokens.forEach((token) => this.validTokens.add(token)); } } /** * Generate a new authentication token * @param metadata Optional metadata to associate with the token * @returns The generated token */ generateToken(metadata) { const token = (0, crypto_1.randomBytes)(32).toString('hex'); const now = new Date(); const expiresAt = new Date(now.getTime() + (this.config.tokenExpirationMs || 60 * 60 * 1000)); const authToken = { token, createdAt: now, expiresAt, metadata, }; this.tokens.set(token, authToken); return authToken; } /** * Authenticate a token and return detailed result * @param token The token to authenticate * @returns Authentication result with status and error message */ authenticate(token) { if (!this.config.enabled) { return { authenticated: true }; // Authentication disabled } // Check for null/undefined/empty tokens if (!token || token.trim() === '') { return { authenticated: false, error: 'Authentication token is required', }; } // Use constant-time comparison to prevent timing attacks const isValid = this.constantTimeCompare(token); if (!isValid) { return { authenticated: false, error: 'Invalid authentication token', }; } return { authenticated: true }; } /** * Constant-time comparison to prevent timing attacks * @param token The token to check * @returns True if the token is valid */ constantTimeCompare(token) { // Check pre-configured tokens if (this.validTokens.size > 0) { let isValid = false; for (const validToken of this.validTokens) { // Use crypto.timingSafeEqual for constant-time comparison const tokenBuffer = Buffer.from(token); const validBuffer = Buffer.from(validToken); // Pad buffers to same length to avoid timing leaks const maxLen = Math.max(tokenBuffer.length, validBuffer.length); const paddedToken = Buffer.alloc(maxLen); const paddedValid = Buffer.alloc(maxLen); tokenBuffer.copy(paddedToken); validBuffer.copy(paddedValid); try { if (paddedToken.equals(paddedValid)) { isValid = true; } } catch { // Continue checking other tokens } } return isValid; } // Check generated tokens return this.validateToken(token); } /** * Validate an authentication token * @param token The token to validate * @returns True if the token is valid and not expired */ validateToken(token) { if (!this.config.enabled) { return true; // Authentication disabled } const authToken = this.tokens.get(token); if (!authToken) { return false; } // Check if token is expired if (new Date() > authToken.expiresAt) { this.tokens.delete(token); return false; } return true; } /** * Revoke an authentication token * @param token The token to revoke * @returns True if the token was found and revoked */ revokeToken(token) { return this.tokens.delete(token); } /** * Clean up expired tokens */ cleanupExpiredTokens() { const now = new Date(); for (const [token, authToken] of this.tokens.entries()) { if (now > authToken.expiresAt) { this.tokens.delete(token); } } } /** * Create an API key * @param name Name for the API key * @param metadata Optional metadata to associate with the key * @returns The created API key (with the unhashed key) */ createApiKey(name, metadata) { const key = (0, crypto_1.randomBytes)(32).toString('hex'); const hashedKey = this.hashApiKey(key); const apiKey = { key, // Return the unhashed key only once hashedKey, name, createdAt: new Date(), enabled: true, metadata, }; this.apiKeys.set(hashedKey, apiKey); return apiKey; } /** * Validate an API key * @param key The API key to validate * @returns True if the key is valid and enabled */ validateApiKey(key) { if (!this.config.enabled || !this.config.requireApiKey) { return true; // API key validation disabled } const hashedKey = this.hashApiKey(key); const apiKey = this.apiKeys.get(hashedKey); if (!apiKey) { return false; } return apiKey.enabled; } /** * Revoke an API key * @param key The API key to revoke * @returns True if the key was found and revoked */ revokeApiKey(key) { const hashedKey = this.hashApiKey(key); const apiKey = this.apiKeys.get(hashedKey); if (!apiKey) { return false; } apiKey.enabled = false; return true; } /** * Delete an API key * @param key The API key to delete * @returns True if the key was found and deleted */ deleteApiKey(key) { const hashedKey = this.hashApiKey(key); return this.apiKeys.delete(hashedKey); } /** * Get all API keys (without the actual key values) * @returns Array of API keys with hashed keys */ getAllApiKeys() { return Array.from(this.apiKeys.values()).map(({ key, ...rest }) => rest); } /** * Hash an API key for secure storage * @param key The API key to hash * @returns The hashed key */ hashApiKey(key) { return (0, crypto_1.createHash)('sha256').update(key).digest('hex'); } /** * Check if authentication is enabled * @returns True if authentication is enabled */ isEnabled() { return this.config.enabled; } /** * Check if API key validation is required * @returns True if API key validation is required */ requiresApiKey() { return this.config.enabled && (this.config.requireApiKey || false); } /** * Get the number of active tokens * @returns The number of active tokens */ getActiveTokenCount() { this.cleanupExpiredTokens(); return this.tokens.size; } /** * Get the number of API keys * @returns The number of API keys */ getApiKeyCount() { return this.apiKeys.size; } /** * Clear all tokens and API keys */ clear() { this.tokens.clear(); this.apiKeys.clear(); } } exports.AuthManager = AuthManager; //# sourceMappingURL=auth-manager.js.map