UNPKG

mcp-cve-intelligence-server-lite-test

Version:

Lite Model Context Protocol server for comprehensive CVE intelligence gathering with multi-source exploit discovery, designed for security professionals and cybersecurity researchers - Alpha Release

242 lines 10.7 kB
import { createContextLogger } from '../utils/logger.js'; import { BaseCVESourceImplementation } from './base.js'; import { NVDSourceImplementation } from './nvd.js'; import { GitHubSourceImplementation } from './github.js'; import { MITRESourceImplementation } from './mitre.js'; import { GenericSourceImplementation } from './generic.js'; const logger = createContextLogger('SourceFactory'); // Re-export the base class for backward compatibility export { BaseCVESourceImplementation }; // Source Factory that works with existing configuration export class SourceFactory { static sourceImplementations = new Map([ ['nvd', NVDSourceImplementation], ['github', GitHubSourceImplementation], ['mitre', MITRESourceImplementation], ]); // Register a new source implementation static registerSourceImplementation(type, implementationClass) { this.sourceImplementations.set(type, implementationClass); logger.info(`Registered new source implementation: ${type}`); } // Create a source implementation from existing CVESource configuration static createSourceImplementation(sourceName, config, apiKey) { // Determine source type from name or URL const sourceType = this.determineSourceType(sourceName, config); const ImplementationClass = this.sourceImplementations.get(sourceType) || GenericSourceImplementation; logger.debug(`Creating source implementation: ${sourceName} (${sourceType})`, { name: config.name, enabled: config.enabled, hasApiKey: !!apiKey, }); return new ImplementationClass(config, apiKey); } // Create implementations for all sources from existing config static createSourceImplementations(sources, apiKeys = {}) { const implementations = {}; for (const [name, config] of Object.entries(sources)) { if (config.enabled) { try { const apiKey = this.getApiKeyForSource(name, config, apiKeys); const implementation = this.createSourceImplementation(name, config, apiKey); implementations[name] = implementation; logger.info(`Created implementation for source: ${name}`, { type: this.determineSourceType(name, config), hasApiKey: !!apiKey, priority: config.priority, }); } catch (error) { logger.error(`Failed to create implementation for source ${name}:`, error instanceof Error ? error : new Error(String(error))); } } } return implementations; } // Validation methods for source factory /** * Validates all source configurations and returns aggregated results */ static validateAllSources(sources, apiKeys = {}) { const allErrors = []; const allWarnings = []; const sourceResults = {}; for (const [name, config] of Object.entries(sources)) { try { const apiKey = this.getApiKeyForSource(name, config, apiKeys); const implementation = this.createSourceImplementation(name, config, apiKey); const validation = implementation.validateFull(); sourceResults[name] = { isValid: validation.isValid, errors: validation.errors, warnings: validation.warnings, enabled: config.enabled, hasApiKey: !!apiKey, }; // Only include errors/warnings for enabled sources in the global result if (config.enabled) { allErrors.push(...validation.errors); allWarnings.push(...validation.warnings); } logger.debug(`Validated source ${name}`, { isValid: validation.isValid, errors: validation.errors.length, warnings: validation.warnings.length, enabled: config.enabled, }); } catch (error) { const errorMsg = `Failed to validate source ${name}: ${error.message}`; allErrors.push(errorMsg); sourceResults[name] = { isValid: false, errors: [errorMsg], warnings: [], enabled: config.enabled, hasApiKey: false, }; logger.error(`Validation failed for source ${name}:`, error); } } return { isValid: allErrors.length === 0, errors: allErrors, warnings: allWarnings, sourceResults, }; } /** * Validates a specific source configuration */ static validateSource(name, config, apiKey) { try { const implementation = this.createSourceImplementation(name, config, apiKey); return implementation.validateFull(); } catch (error) { const errorMsg = `Failed to create implementation for validation: ${error.message}`; return { isValid: false, errors: [errorMsg], warnings: [], }; } } // Get enabled source implementations sorted by priority static getEnabledImplementations(implementations) { return Object.values(implementations) .filter(impl => impl.isEnabled()) .sort((a, b) => a.getPriority() - b.getPriority()); } // Get implementations that support a specific feature static getImplementationsByFeature(implementations, feature) { return Object.values(implementations) .filter(impl => impl.isEnabled() && impl.hasFeature(feature)) .sort((a, b) => a.getPriority() - b.getPriority()); } // Get available source types static getAvailableSourceTypes() { return Array.from(this.sourceImplementations.keys()); } // Determine source type from name or configuration static determineSourceType(sourceName, config) { const name = sourceName.toLowerCase(); const baseUrl = config.baseUrl.toLowerCase(); if (name.includes('nvd') || baseUrl.includes('nvd.nist.gov')) { return 'nvd'; } if (name.includes('github') || baseUrl.includes('github.com')) { return 'github'; } if (name.includes('mitre') || baseUrl.includes('mitre.org')) { return 'mitre'; } return 'generic'; } // Get API key for a source using distributed logic static getApiKeyForSource(sourceName, config, apiKeys) { // Create a temporary implementation to access source-specific API key logic try { const tempImplementation = this.createSourceImplementation(sourceName, config); // 1. Try explicit source name from provided mapping if (apiKeys[sourceName]) { const key = apiKeys[sourceName]; if (tempImplementation.canUseApiKey(key)) { return key; } } // 2. Try API key identifier from source const identifier = tempImplementation.getApiKeyIdentifier(); if (identifier && apiKeys[identifier]) { const key = apiKeys[identifier]; if (tempImplementation.canUseApiKey(key)) { return key; } } // 3. Try matching source identifiers for (const [keyName, key] of Object.entries(apiKeys)) { if (tempImplementation.matchesSourceIdentifier(keyName) && tempImplementation.canUseApiKey(key)) { return key; } } // 4. Try primary environment variable const primaryEnvVar = tempImplementation.getApiKeyEnvironmentVariable(); if (primaryEnvVar) { const envValue = process.env[primaryEnvVar]; if (envValue && tempImplementation.canUseApiKey(envValue)) { return envValue; } } // 5. Try alternative environment variables const altEnvVars = tempImplementation.getAlternativeApiKeyEnvironmentVariables(); for (const envVar of altEnvVars) { const envValue = process.env[envVar]; if (envValue && tempImplementation.canUseApiKey(envValue)) { return envValue; } } // 6. Try environment variable specified in config (fallback) if (config.apiKeyEnvVar) { const envValue = process.env[config.apiKeyEnvVar]; if (envValue && tempImplementation.canUseApiKey(envValue)) { return envValue; } } return undefined; } catch (error) { logger.warn(`Failed to resolve API key for source ${sourceName}: ${error.message}`); // Fallback to simple logic if source creation fails return apiKeys[sourceName] || (config.apiKeyEnvVar ? process.env[config.apiKeyEnvVar] : undefined); } } /** * Resolves API keys for all sources using distributed logic */ static resolveApiKeysForSources(sources, providedApiKeys = {}) { const resolvedKeys = {}; for (const [sourceName, config] of Object.entries(sources)) { const apiKey = this.getApiKeyForSource(sourceName, config, providedApiKeys); resolvedKeys[sourceName] = apiKey; } return resolvedKeys; } // Test all source connections static async testAllConnections(implementations) { const results = {}; const testPromises = Object.entries(implementations).map(async ([name, impl]) => { try { const isConnected = await impl.testConnection(); results[name] = isConnected; logger.info(`Source ${name} connection test: ${isConnected ? 'SUCCESS' : 'FAILED'}`); } catch (error) { results[name] = false; logger.error(`Source ${name} connection test failed:`, error instanceof Error ? error : new Error(String(error))); } }); await Promise.allSettled(testPromises); return results; } } //# sourceMappingURL=factory.js.map