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
219 lines • 8.64 kB
JavaScript
import { BaseCVESourceImplementation } from './base.js';
import { normalizeDescriptions } from '../utils/cve-utils.js';
import { safeString, safeNumber, isNonEmptyArray } from '../utils/validation.js';
// Generic implementation for unknown source types
export class GenericSourceImplementation extends BaseCVESourceImplementation {
buildSearchRequest(filters) {
const params = new URLSearchParams();
// Generic parameter mapping - may not work for all APIs
if (filters.keyword) {
params.append('q', filters.keyword);
}
if (filters.cveId) {
params.append('cve', filters.cveId);
}
if (filters.cvssV3Severity) {
params.append('severity', filters.cvssV3Severity);
}
if (filters.pubStartDate) {
params.append('start_date', filters.pubStartDate);
}
if (filters.pubEndDate) {
params.append('end_date', filters.pubEndDate);
}
if (filters.resultsPerPage) {
params.append('limit', filters.resultsPerPage.toString());
}
if (filters.startIndex) {
params.append('offset', filters.startIndex.toString());
}
const url = `${this.getBaseUrl()}?${params.toString()}`;
return { url, options: this.getRequestOptions() };
}
buildDetailsRequest(cveId) {
// Generic approach - append CVE ID to base URL
const url = `${this.getBaseUrl()}/${cveId}`;
return { url, options: this.getRequestOptions() };
}
normalizeSearchResults(data) {
// Generic normalization - try to handle common response formats
let cves = [];
let totalResults = 0;
if (Array.isArray(data)) {
// Response is directly an array
cves = data.map((item) => this.normalizeCVEData(item));
totalResults = data.length;
}
else if (data && typeof data === 'object') {
// Try common property names for arrays
const items = data.items ||
data.results ||
data.data ||
data.vulnerabilities ||
data.cves;
if (isNonEmptyArray(items)) {
cves = items.map((item) => this.normalizeCVEData(item));
totalResults = safeNumber(data.total ??
data.totalResults ??
data.count, items.length);
}
else {
// Single object response
const cve = this.normalizeCVEData(data);
if (cve.id !== 'unknown') {
cves = [cve];
totalResults = 1;
}
}
}
return {
cves,
totalResults,
startIndex: 0,
resultsPerPage: cves.length,
format: 'Generic',
version: '1.0',
timestamp: new Date().toISOString(),
};
}
normalizeCVEData(data) {
const item = data;
// Try to extract CVE data from common property names with proper type handling
const id = safeString(item.id ?? item.cve_id ?? item.cveId ?? item.identifier, 'unknown');
const published = safeString(item.published ?? item.published_at ?? item.publishedDate ?? item.date, new Date().toISOString());
const lastModified = safeString(item.lastModified ?? item.last_modified ?? item.updated_at ?? item.modified, published);
const description = safeString(item.description ?? item.summary ?? item.title, 'No description found');
const normalizedReferences = this.normalizeGenericReferences(item);
return {
id,
sourceIdentifier: this.config.name || 'generic',
published,
lastModified,
vulnStatus: this.normalizeStatus(safeString(item.status ?? item.state, 'PUBLISHED')),
cveTags: Array.isArray(item.cveTags) ? item.cveTags :
Array.isArray(item.tags) ? item.tags : [],
descriptions: normalizeDescriptions([{
lang: 'en',
value: description,
}]),
metrics: this.normalizeGenericMetrics(item),
weaknesses: this.normalizeGenericWeaknesses(item),
configurations: [],
references: normalizedReferences,
// Calculate exploit indicators during normalization
exploitIndicators: this.calculateExploitIndicators(normalizedReferences),
dataSource: {
name: this.config.name || 'generic',
version: '1.0',
lastUpdated: new Date().toISOString(),
url: this.getBaseUrl(),
},
processingInfo: {
extractedAt: new Date().toISOString(),
normalizedBy: 'generic_source',
rawDataAvailable: true,
},
};
}
normalizeStatus(status) {
if (!status) {
return 'PUBLISHED';
}
const statusLower = status.toLowerCase();
if (statusLower.includes('publish') || statusLower === 'active') {
return 'PUBLISHED';
}
if (statusLower.includes('reject') || statusLower === 'withdrawn') {
return 'REJECTED';
}
if (statusLower.includes('reserve') || statusLower === 'draft') {
return 'RESERVED';
}
return 'PUBLISHED';
}
normalizeGenericMetrics(item) {
// Try to extract CVSS information
const cvss = item.cvss || item.cvssV3 || item.cvss_v3 || item.metrics;
if (!cvss) {
return undefined;
}
// Type-safe property access
const cvssData = cvss;
const score = safeNumber(cvssData.score ?? cvssData.baseScore ?? cvssData.base_score, 0);
const severity = safeString(cvssData.severity ?? cvssData.baseSeverity ?? cvssData.base_severity, 'UNKNOWN');
const vectorString = safeString(cvssData.vectorString ?? cvssData.vector_string ?? cvssData.vector, '');
return {
cvssMetricV31: [{
source: this.config.name || 'generic',
type: 'Primary',
cvssData: {
version: '3.1',
vectorString,
baseScore: score,
baseSeverity: severity.toUpperCase(),
attackVector: 'UNKNOWN',
attackComplexity: 'UNKNOWN',
privilegesRequired: 'UNKNOWN',
userInteraction: 'UNKNOWN',
scope: 'UNKNOWN',
confidentialityImpact: 'UNKNOWN',
integrityImpact: 'UNKNOWN',
availabilityImpact: 'UNKNOWN',
},
}],
};
}
normalizeGenericWeaknesses(item) {
const weaknesses = item.weaknesses ??
item.cwe ??
item.cwes ??
item.cwe_ids ??
[];
if (!isNonEmptyArray(weaknesses)) {
return [];
}
return weaknesses.map(weakness => ({
source: this.config.name || 'generic',
type: 'Primary',
description: [{
lang: 'en',
value: typeof weakness === 'string' ? weakness :
safeString(weakness.value ??
weakness.description, 'Unknown weakness'),
}],
}));
}
normalizeGenericReferences(item) {
const references = item.references ??
item.links ??
item.urls ??
[];
if (!isNonEmptyArray(references)) {
return [];
}
return references.map(ref => ({
url: typeof ref === 'string' ? ref :
safeString(ref.url ??
ref.link, ''),
source: this.config.name || 'generic',
tags: Array.isArray(ref.tags) ?
ref.tags : [],
name: safeString(ref.name ??
ref.title) || undefined,
refsource: safeString(ref.refsource ??
ref.source, 'MISC'),
}));
}
getRequestOptions() {
const headers = {
'Accept': 'application/json',
'User-Agent': this.getUserAgent(),
...this.getAuthHeaders(),
};
return {
headers,
timeout: this.getTimeout(),
};
}
}
//# sourceMappingURL=generic.js.map