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
JavaScript
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