====================================================================================================================================================================================== ===================================================== // SentinelAI - Real API Service (Operational Mode) // Free public APIs: ipinfo.io, NVD CVE, Google DNS // ===================================================== // ===================================================== // SentinelAI - Real API Service (Operational Mode) // Free public APIs: ipinfo.io, NVD CVE, Google DNS, API Ninjas // ===================================================== const SentinelAPI = { // ---- IP Geolocation via ipinfo.io (free, no key) ---- async lookupIP(query) { try { const isIP = /^(\d{1,3}\.){3}\d{1,3}/.test(query); const url = query.trim() ? `https://ipinfo.io/${query}/json` : `https://ipinfo.io/json`; const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); if (data.bogon) return { error: 'Private/bogon IP', ip: query }; const [lat, lng] = (data.loc || '0,0').split(','); return { ip: data.ip || query, hostname: data.hostname || query, city: data.city || 'Unknown', region: data.region || 'Unknown', country: data.country || 'Unknown', loc: data.loc || '0,0', lat: parseFloat(lat) || 0, lng: parseFloat(lng) || 0, org: data.org || 'Unknown', timezone: data.timezone || 'Unknown', asn: data.asn || {}, }; } catch (e) { console.error('[SentinelAPI] ipinfo.io error:', e); return { error: e.message, ip: query }; } }, // ---- NVD CVE Search (free, public) ---- async searchCVEs(keyword, limit = 20) { try { const url = `https://services.nvd.nist.gov/rest/json/cves/2.0?keywordSearch=${encodeURIComponent(keyword)}&resultsPerPage=${limit}`; const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return (data.vulnerabilities || []).map(v => { const cve = v.cve; const descriptions = cve.descriptions || []; const desc = descriptions.find(d => d.lang === 'en')?.value || 'No description'; const metrics = cve.metrics || {}; const cvssV31 = metrics.cvssMetricV31?.[0]?.cvssData; const cvssV2 = metrics.cvssMetricV2?.[0]?.cvssData; const cvss = cvssV31 || cvssV2 || {}; const severity = cvss.baseSeverity || 'N/A'; const score = cvss.baseScore || 0; const references = (cve.references || []).map(r => r.url).slice(0, 5); const weaknesses = (cve.weaknesses || []).flatMap(w => (w.description || []).map(d => d.value) ).slice(0, 5); const published = cve.published || ''; const lastModified = cve.lastModified || ''; return { id: cve.id || 'CVE-Unknown', description: (desc || 'No description').length > 200 ? (desc || 'No description').substring(0, 200) + '...' : (desc || 'No description'), severity: (severity || 'N/A').toLowerCase(), score: score || 0, published: published || '', lastModified: lastModified || '', references: references || [], weaknesses: weaknesses || [], source: 'NVD', technique: (weaknesses && weaknesses[0]) || 'T1190', tactic: this._mapTactic(weaknesses && weaknesses[0]), }; }); } catch (e) { console.error('[SentinelAPI] NVD error:', e); return []; } }, // ---- Get specific CVE ---- async getCVE(cveId) { try { const url = `https://services.nvd.nist.gov/rest/json/cves/2.0?cveId=${encodeURIComponent(cveId)}`; const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); const cve = data.vulnerabilities?.[0]?.cve; if (!cve) return null; const desc = (cve.descriptions || []).find(d => d.lang === 'en')?.value || ''; const metrics = cve.metrics || {}; const cvss = metrics.cvssMetricV31?.[0]?.cvssData || metrics.cvssMetricV2?.[0]?.cvssData || {}; return { id: cve.id, description: desc, severity: (cvss.baseSeverity || 'N/A').toLowerCase(), score: cvss.baseScore || 0, vector: cvss.vectorString || '', published: cve.published || '', lastModified: cve.lastModified || '', references: (cve.references || []).map(r => r.url), weaknesses: (cve.weaknesses || []).flatMap(w => (w.description || []).map(d => d.value)), configs: (cve.configurations || []).flatMap(c => (c.nodes || []).flatMap(n => (n.cpeMatch || []).map(m => ({ criteria: m.criteria, vulnerable: m.vulnerable, }))) ).slice(0, 10), }; } catch (e) { console.error('[SentinelAPI] NVD CVE error:', e); return null; } }, // ---- DNS Resolution via Google DNS (free) ---- async resolveDomain(domain) { try { const res = await fetch(`https://dns.google/resolve?name=${encodeURIComponent(domain)}&type=A`); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); const answers = data.Answer || []; return { domain, ips: answers.filter(a => a.type === 1).map(a => a.data), answers: answers.map(a => ({ name: a.name, type: a.type, ttl: a.TTL, data: a.data })), status: data.Status === 0 ? 'resolved' : 'failed', }; } catch (e) { console.error('[SentinelAPI] DNS error:', e); return { domain, ips: [], answers: [], status: 'error', error: e.message }; } }, // ---- Map CWE to MITRE tactic ---- _mapTactic(cwe) { if (!cwe) return 'Initial Access'; const map = { 'CWE-79': 'Execution', 'CWE-89': 'Initial Access', 'CWE-78': 'Execution', 'CWE-22': 'Discovery', 'CWE-352': 'Initial Access', 'CWE-434': 'Execution', 'CWE-502': 'Execution', 'CWE-190': 'Execution', 'CWE-476': 'Execution', 'CWE-306': 'Initial Access', 'CWE-862': 'Privilege Escalation', 'CWE-863': 'Authorization', 'CWE-287': 'Credential Access', 'CWE-522': 'Credential Access', 'CWE-312': 'Collection', 'CWE-327': 'Defense Evasion', 'CWE-732': 'Privilege Escalation', 'CWE-250': 'Privilege Escalation', 'CWE-610': 'Exfiltration', 'CWE-400': 'Impact', 'CWE-918': 'Initial Access', 'CWE-94': 'Persistence', 'CWE-416': 'Execution', }; return map[cwe] || 'Initial Access'; }, // ---- API Ninjas: IP Geolocation (free, no key required for basic) ---- async lookupIPNinjas(query) { try { const url = query.trim() ? `https://api.api-ninjas.com/v1/iplookup?address=${encodeURIComponent(query)}` : `https://api.api-ninjas.com/v1/iplookup?address=8.8.8.8`; const res = await fetch(url, { headers: { 'X-Api-Key': SentinelConfig.apiNinjasKey } }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return { ip: data.address || query, hostname: data.hostname || query, city: data.city || 'Unknown', region: data.region || 'Unknown', country: data.country || 'Unknown', loc: `${data.lat || 0},${data.lon || 0}`, lat: parseFloat(data.lat) || 0, lng: parseFloat(data.lon) || 0, org: data.org || 'Unknown', timezone: data.timezone || 'Unknown', asn: data.asn || {}, source: 'API Ninjas', }; } catch (e) { console.error('[SentinelAPI] API Ninjas IP error:', e); return { error: e.message, ip: query }; } }, // ---- API Ninjas: WHOIS Lookup ---- async whoisLookup(domain) { try { const url = `https://api.api-ninjas.com/v1/whois?domain=${encodeURIComponent(domain)}`; const res = await fetch(url, { headers: { 'X-Api-Key': SentinelConfig.apiNinjasKey } }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return { domain: data.domain || domain, registrar: data.registrar || 'Unknown', creationDate: data.creation_date || '', expirationDate: data.expiration_date || '', updatedDate: data.updated_date || '', nameServers: data.name_servers || [], status: data.status || [], emails: data.emails || [], source: 'API Ninjas WHOIS', }; } catch (e) { console.error('[SentinelAPI] API Ninjas WHOIS error:', e); return { error: e.message, domain }; } }, // ---- API Ninjas: DNS Records ---- async dnsLookupNinjas(domain) { try { const url = `https://api.api-ninjas.com/v1/dnslookup?domain=${encodeURIComponent(domain)}`; const res = await fetch(url, { headers: { 'X-Api-Key': SentinelConfig.apiNinjasKey } }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return { domain, records: Array.isArray(data) ? data.map(r => ({ record_type: r.record_type, value: r.value, ttl: r.ttl, })) : [], status: 'resolved', source: 'API Ninjas', }; } catch (e) { console.error('[SentinelAPI] API Ninjas DNS error:', e); return { error: e.message, domain, records: [], status: 'error' }; } }, // ---- API Ninjas: URL Shortener ---- async shortenURL(longUrl) { try { const url = `https://api.api-ninjas.com/v1/shortenurl?url=${encodeURIComponent(longUrl)}`; const res = await fetch(url, { headers: { 'X-Api-Key': SentinelConfig.apiNinjasKey } }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return { original: longUrl, short: data.short_url || '', source: 'API Ninjas', }; } catch (e) { console.error('[SentinelAPI] API Ninjas URL shortener error:', e); return { error: e.message, original: longUrl }; } }, // ---- API Ninjas: Password Generator ---- async generatePassword(length = 16) { try { const url = `https://api.api-ninjas.com/v1/passwordgenerator?length=${length}`; const res = await fetch(url, { headers: { 'X-Api-Key': SentinelConfig.apiNinjasKey } }); if (!res.ok) throw new Error(`HTTP ${res.status}`); const data = await res.json(); return { password: data.password || '', length, source: 'API Ninjas', }; } catch (e) { console.error('[SentinelAPI] API Ninjas password error:', e); return { error: e.message }; } }, // ---- Batch IP lookup ---- async batchLookup(ips) { const results = []; for (const ip of ips.slice(0, 5)) { const data = await this.lookupIP(ip); results.push(data); await new Promise(r => setTimeout(r, 300)); // Rate limit } return results; }, // ---- Batch IP lookup via API Ninjas ---- async batchLookupNinjas(ips) { const results = []; for (const ip of ips.slice(0, 5)) { const data = await this.lookupIPNinjas(ip); results.push(data); await new Promise(r => setTimeout(r, 300)); // Rate limit } return results; }, };