UNPKG

@burtthecoder/mcp-virustotal

Version:
100 lines (99 loc) 3.75 kB
import { queryVirusTotal, encodeUrlForVt } from '../utils/api.js'; import { formatUrlScanResults } from '../formatters/index.js'; import { GetUrlReportArgsSchema, GetUrlRelationshipArgsSchema } from '../schemas/index.js'; import { logToFile } from '../utils/logging.js'; // Default relationships to fetch const DEFAULT_RELATIONSHIPS = [ 'communicating_files', 'contacted_domains', 'contacted_ips', 'downloaded_files', 'redirects_to', 'redirecting_urls', 'related_threat_actors' ]; export async function handleGetUrlReport(axiosInstance, args) { const parsedArgs = GetUrlReportArgsSchema.safeParse(args); if (!parsedArgs.success) { throw new Error("Invalid URL format"); } const url = parsedArgs.data.url; const encodedUrl = encodeUrlForVt(url); // First submit URL for scanning logToFile(`Scanning URL: ${url}`); const scanResponse = await queryVirusTotal(axiosInstance, '/urls', 'post', new URLSearchParams({ url })); const analysisId = scanResponse.data.id; logToFile(`Analysis ID: ${analysisId}`); // Wait for analysis to complete await new Promise(resolve => setTimeout(resolve, 3000)); // Get analysis results const analysisResponse = await queryVirusTotal(axiosInstance, `/analyses/${analysisId}`); // Then get full data for specified relationships const relationshipData = {}; for (const relType of DEFAULT_RELATIONSHIPS) { logToFile(`Fetching ${relType}`); try { const response = await queryVirusTotal(axiosInstance, `/urls/${encodedUrl}/${relType}`, 'get'); // Only log relationship metadata logToFile(`${relType} count: ${Array.isArray(response.data) ? response.data.length : response.data ? '1' : '0'}`); // Format the relationship data if (Array.isArray(response.data)) { relationshipData[relType] = { data: response.data, meta: response.meta }; } else if (response.data) { relationshipData[relType] = { data: response.data, meta: response.meta }; } } catch (error) { logToFile(`Failed to fetch ${relType}`); // Continue with other relationships even if one fails } } // Combine the analysis results with relationships const combinedData = { id: analysisId, url: url, attributes: analysisResponse.data.attributes, scan_date: new Date().toISOString(), relationships: relationshipData }; return { content: [ formatUrlScanResults(combinedData) ], }; } export async function handleGetUrlRelationship(axiosInstance, args) { const parsedArgs = GetUrlRelationshipArgsSchema.safeParse(args); if (!parsedArgs.success) { throw new Error("Invalid arguments for URL relationship query"); } const { url, relationship, limit, cursor } = parsedArgs.data; const encodedUrl = encodeUrlForVt(url); const params = { limit }; if (cursor) params.cursor = cursor; logToFile(`Fetching ${relationship} for URL: ${url}`); const result = await queryVirusTotal(axiosInstance, `/urls/${encodedUrl}/${relationship}`, 'get'); return { content: [ formatUrlScanResults({ url: url, attributes: result.data.attributes, relationships: { [relationship]: { data: result.data, meta: result.meta } } }) ], }; }