LOT 1 - Optimizare script build -Instalare mono comanda

This commit is contained in:
Dezvoltari Evotech 2026-06-27 06:42:02 -07:00
parent 5380c3fc63
commit 42ff22bf85
127 changed files with 16163 additions and 532 deletions

View file

@ -0,0 +1,637 @@
<!DOCTYPE html>
<html lang="ro">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Domain Check - Verificare Completă Domenii</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Segoe UI', system-ui, sans-serif;
background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%);
min-height: 100vh;
color: #e4e4e4;
}
.container { max-width: 1400px; margin: 0 auto; padding: 20px; }
h1 {
text-align: center;
font-size: 2rem;
margin-bottom: 10px;
background: linear-gradient(90deg, #00d9ff, #00ff88);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
.subtitle { text-align: center; color: #888; margin-bottom: 30px; font-size: 0.9rem; }
.search-box {
background: rgba(255,255,255,0.05);
border-radius: 16px;
padding: 25px;
margin-bottom: 25px;
border: 1px solid rgba(255,255,255,0.1);
}
.input-group {
display: flex;
gap: 15px;
flex-wrap: wrap;
align-items: center;
}
.input-group input {
flex: 1;
min-width: 250px;
padding: 15px 20px;
border: 2px solid rgba(255,255,255,0.2);
border-radius: 10px;
font-size: 1.1rem;
background: rgba(0,0,0,0.3);
color: #fff;
}
.input-group input:focus { outline: none; border-color: #00d9ff; }
.btn {
padding: 15px 35px;
border: none;
border-radius: 10px;
font-size: 1rem;
cursor: pointer;
font-weight: 600;
transition: all 0.3s;
}
.btn-primary {
background: linear-gradient(135deg, #00d9ff, #00ff88);
color: #1a1a2e;
}
.btn-primary:hover { transform: translateY(-2px); box-shadow: 0 5px 20px rgba(0,217,255,0.4); }
.btn-primary:disabled { opacity: 0.5; cursor: not-allowed; transform: none; }
.options {
display: flex;
flex-wrap: wrap;
gap: 15px;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid rgba(255,255,255,0.1);
}
.option-group { display: flex; align-items: center; gap: 8px; }
.option-group input[type="checkbox"] { width: 18px; height: 18px; cursor: pointer; }
.option-group label { cursor: pointer; font-size: 0.9rem; }
.option-group.slow label { color: #ff9800; }
.loading { display: none; text-align: center; padding: 50px; }
.spinner {
width: 50px; height: 50px;
border: 4px solid rgba(255,255,255,0.1);
border-top-color: #00d9ff;
border-radius: 50%;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin { to { transform: rotate(360deg); } }
.results { display: none; }
.results-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(400px, 1fr));
gap: 20px;
}
.card {
background: rgba(255,255,255,0.05);
border-radius: 12px;
border: 1px solid rgba(255,255,255,0.1);
overflow: hidden;
}
.card-header {
padding: 15px 20px;
background: rgba(0,0,0,0.3);
display: flex;
justify-content: space-between;
align-items: center;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.card-header h3 { font-size: 1rem; display: flex; align-items: center; gap: 10px; }
.card-header .source { font-size: 0.75rem; color: #888; background: rgba(255,255,255,0.1); padding: 3px 8px; border-radius: 4px; }
.card-body { padding: 20px; }
.risk-card { grid-column: 1 / -1; }
.risk-score-display {
display: flex;
align-items: center;
gap: 30px;
flex-wrap: wrap;
}
.risk-circle {
width: 150px; height: 150px;
border-radius: 50%;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
font-size: 3rem;
font-weight: bold;
flex-shrink: 0;
}
.risk-circle .label { font-size: 0.9rem; font-weight: normal; margin-top: 5px; }
.risk-low { background: linear-gradient(135deg, #00c853, #00e676); color: #1a1a2e; }
.risk-medium { background: linear-gradient(135deg, #ffc107, #ffeb3b); color: #1a1a2e; }
.risk-high { background: linear-gradient(135deg, #ff5722, #ff9800); color: #fff; }
.risk-critical { background: linear-gradient(135deg, #d32f2f, #f44336); color: #fff; }
.risk-details { flex: 1; min-width: 300px; }
.risk-factor {
display: flex;
justify-content: space-between;
align-items: center;
padding: 10px 0;
border-bottom: 1px solid rgba(255,255,255,0.1);
}
.risk-factor:last-child { border-bottom: none; }
.risk-factor .name { font-weight: 500; }
.risk-factor .score {
display: flex;
align-items: center;
gap: 10px;
}
.risk-factor .bar {
width: 100px;
height: 8px;
background: rgba(255,255,255,0.1);
border-radius: 4px;
overflow: hidden;
}
.risk-factor .bar-fill { height: 100%; transition: width 0.5s; }
.risk-factor .value { width: 40px; text-align: right; font-weight: bold; }
.formula-box {
background: rgba(0,0,0,0.3);
border-radius: 8px;
padding: 15px;
margin-top: 20px;
font-family: monospace;
font-size: 0.85rem;
overflow-x: auto;
}
.formula-box h4 { margin-bottom: 10px; color: #00d9ff; }
.formula-line { padding: 3px 0; }
.data-row {
display: flex;
padding: 10px 0;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.data-row:last-child { border-bottom: none; }
.data-label { width: 140px; color: #888; font-size: 0.9rem; flex-shrink: 0; }
.data-value { flex: 1; word-break: break-all; }
.badge {
display: inline-block;
padding: 3px 10px;
border-radius: 4px;
font-size: 0.8rem;
margin: 2px;
}
.badge.success { background: rgba(0,200,83,0.2); color: #00c853; }
.badge.danger { background: rgba(244,67,54,0.2); color: #f44336; }
.badge.warning { background: rgba(255,152,0,0.2); color: #ff9800; }
.badge.info { background: rgba(0,217,255,0.2); color: #00d9ff; }
.badge.neutral { background: rgba(255,255,255,0.1); color: #aaa; }
.port-list { display: flex; flex-wrap: wrap; gap: 5px; }
.port-item {
padding: 5px 10px;
border-radius: 4px;
font-size: 0.8rem;
background: rgba(255,255,255,0.1);
}
.port-item.danger { background: rgba(244,67,54,0.2); color: #f44336; }
.port-item.warning { background: rgba(255,152,0,0.2); color: #ff9800; }
.port-item.safe { background: rgba(0,200,83,0.2); color: #00c853; }
.blacklist-item {
display: flex;
justify-content: space-between;
padding: 8px 0;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.blacklist-clean { color: #00c853; }
.blacklist-listed { color: #f44336; }
.error {
background: rgba(244,67,54,0.2);
border: 1px solid #f44336;
border-radius: 8px;
padding: 20px;
text-align: center;
color: #f44336;
}
.tech-tags { display: flex; flex-wrap: wrap; gap: 8px; }
.tech-tag {
background: linear-gradient(135deg, rgba(0,217,255,0.2), rgba(0,255,136,0.2));
padding: 5px 12px;
border-radius: 20px;
font-size: 0.85rem;
}
.security-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px 0;
border-bottom: 1px solid rgba(255,255,255,0.05);
}
.header-present { color: #00c853; }
.header-missing { color: #f44336; }
@media (max-width: 768px) {
.results-grid { grid-template-columns: 1fr; }
.risk-score-display { flex-direction: column; text-align: center; }
.input-group { flex-direction: column; }
.input-group input { width: 100%; }
}
</style>
</head>
<body>
<div class="container">
<h1>🔍 Domain Check</h1>
<p class="subtitle">Verificare completă domenii - WHOIS, DNS, SSL, IP Intelligence, HTTP Security, Blacklists</p>
<div class="search-box">
<div class="input-group">
<input type="text" id="domainInput" placeholder="Introdu domeniul (ex: google.com, example.ro)" autofocus>
<button class="btn btn-primary" id="checkBtn" onclick="checkDomain()">Verifică Domeniul</button>
</div>
<div class="options">
<div class="option-group">
<input type="checkbox" id="optWhois" checked>
<label for="optWhois">WHOIS</label>
</div>
<div class="option-group">
<input type="checkbox" id="optDns" checked>
<label for="optDns">DNS</label>
</div>
<div class="option-group">
<input type="checkbox" id="optSsl" checked>
<label for="optSsl">SSL/TLS</label>
</div>
<div class="option-group">
<input type="checkbox" id="optIp" checked>
<label for="optIp">IP Intelligence</label>
</div>
<div class="option-group">
<input type="checkbox" id="optHttp" checked>
<label for="optHttp">HTTP Analysis</label>
</div>
<div class="option-group">
<input type="checkbox" id="optBlacklist" checked>
<label for="optBlacklist">Blacklists</label>
</div>
<div class="option-group slow">
<input type="checkbox" id="optPorts">
<label for="optPorts">Port Scan (lent)</label>
</div>
<div class="option-group slow">
<input type="checkbox" id="optSubdomains">
<label for="optSubdomains">Subdomenii (lent)</label>
</div>
</div>
</div>
<div class="loading" id="loading">
<div class="spinner"></div>
<p>Se verifică domeniul... Acest proces poate dura până la 30 de secunde.</p>
</div>
<div class="results" id="results"></div>
</div>
<script>
const API_URL = '/api/v1/check/check';
document.getElementById('domainInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') checkDomain();
});
async function checkDomain() {
const domain = document.getElementById('domainInput').value.trim();
if (!domain) { alert('Introdu un domeniu!'); return; }
const btn = document.getElementById('checkBtn');
const loading = document.getElementById('loading');
const results = document.getElementById('results');
btn.disabled = true;
loading.style.display = 'block';
results.style.display = 'none';
const checkOptions = {
whois: document.getElementById('optWhois').checked,
dns: document.getElementById('optDns').checked,
ssl: document.getElementById('optSsl').checked,
ip_intelligence: document.getElementById('optIp').checked,
http_analysis: document.getElementById('optHttp').checked,
blacklist: document.getElementById('optBlacklist').checked,
port_scan: document.getElementById('optPorts').checked,
subdomains: document.getElementById('optSubdomains').checked
};
try {
const response = await fetch(API_URL, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ domain, check_options: checkOptions })
});
const data = await response.json();
if (data.success) {
displayResults(data.data, data.metadata);
} else {
results.innerHTML = `<div class="error">❌ ${data.error?.message || 'Eroare necunoscută'}</div>`;
}
} catch (err) {
results.innerHTML = `<div class="error">❌ Eroare de conexiune: ${err.message}</div>`;
}
btn.disabled = false;
loading.style.display = 'none';
results.style.display = 'block';
}
function displayResults(d, meta) {
let html = '<div class="results-grid">';
if (d.availability) html += renderAvailabilityCard(d.availability);
if (d.risk_score) html += renderRiskCard(d.risk_score);
if (d.whois) html += renderWhoisCard(d.whois);
if (d.dns) html += renderDnsCard(d.dns);
if (d.mail) html += renderMailCard(d.mail);
if (d.ssl) html += renderSslCard(d.ssl);
if (d.ip_intelligence) html += renderIpCard(d.ip_intelligence);
if (d.http_analysis) html += renderHttpCard(d.http_analysis);
if (d.blacklist) html += renderBlacklistCard(d.blacklist);
if (d.port_scan) html += renderPortCard(d.port_scan);
if (d.subdomains) html += renderSubdomainsCard(d.subdomains);
html += '</div>';
html += `<div style="text-align: center; margin-top: 20px; color: #666; font-size: 0.85rem;">
Check ID: ${d.check_id} | Timp procesare: ${meta.processing_time_ms}ms | API: ${meta.api_version}
</div>`;
document.getElementById('results').innerHTML = html;
}
function renderAvailabilityCard(a) {
const reg = a.is_registered;
const label = reg ? '🔒 Înregistrat' : '🟢 Disponibil';
const badgeClass = reg ? 'info' : 'success';
return `
<div class="card">
<div class="card-header"><h3>📌 Disponibilitate</h3><span class="source">WHOIS+DNS</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">Status:</div><div class="data-value"><span class="badge ${badgeClass}" style="font-size:1rem">${label}</span></div></div>
<div class="data-row"><div class="data-label">Încredere:</div><div class="data-value">${a.confidence}</div></div>
<div class="data-row"><div class="data-label">Semnale:</div><div class="data-value">
<span class="badge ${a.signals?.whois_has_data ? 'success' : 'neutral'}">WHOIS ${a.signals?.whois_has_data ? '✓' : ''}</span>
<span class="badge ${a.signals?.dns_resolves ? 'success' : 'neutral'}">DNS ${a.signals?.dns_resolves ? '✓' : ''}</span>
</div></div>
</div>
</div>`;
}
function renderMailCard(m) {
const gradeColor = {A:'#00c853', B:'#8bc34a', C:'#ffc107', D:'#ff9800', F:'#f44336'}[m.mail_security_grade] || '#888';
const spf = m.spf || {}, dmarc = m.dmarc || {}, dkim = m.dkim || {}, mx = m.mx || {}, sts = m.mta_sts || {};
const tlsRow = (mx.starttls !== null && mx.starttls !== undefined) ? ` · STARTTLS ${mx.starttls ? '✓' : '✗'}` : '';
return `
<div class="card">
<div class="card-header"><h3>📧 Mail Intelligence</h3><span class="source">EMAIL</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">Securitate email:</div><div class="data-value"><span class="badge" style="background:${gradeColor};color:#fff">${m.mail_security_grade} · ${m.mail_security_score}/100</span></div></div>
${m.provider ? `<div class="data-row"><div class="data-label">Provider:</div><div class="data-value">${m.provider}</div></div>` : ''}
<div class="data-row"><div class="data-label">MX:</div><div class="data-value">${mx.count || 0} servere${tlsRow}${mx.dane ? ' · DANE ✓' : ''}</div></div>
<div class="data-row"><div class="data-label">SPF:</div><div class="data-value"><span class="badge ${spf.present ? 'success' : 'danger'}">${spf.present ? '✓' : '✗'}</span> ${spf.policy || ''}</div></div>
<div class="data-row"><div class="data-label">DKIM:</div><div class="data-value"><span class="badge ${dkim.present ? 'success' : 'danger'}">${dkim.present ? '✓' : '✗'}</span> ${(dkim.selectors_found || []).join(', ')}</div></div>
<div class="data-row"><div class="data-label">DMARC:</div><div class="data-value"><span class="badge ${dmarc.present ? 'success' : 'danger'}">${dmarc.present ? '✓' : '✗'}</span> ${dmarc.policy ? ('p=' + dmarc.policy) : ''}</div></div>
<div class="data-row"><div class="data-label">MTA-STS:</div><div class="data-value"><span class="badge ${sts.present ? 'success' : 'neutral'}">${sts.present ? '✓' : ''}</span>${sts.mode ? (' ' + sts.mode) : ''} ${m.tls_rpt?.present ? '<span class="badge success">TLS-RPT ✓</span>' : ''}</div></div>
${m.deliverability?.tested ? `<div class="data-row"><div class="data-label">Catch-all:</div><div class="data-value">${m.deliverability.catch_all ? '<span class="badge warning">DA</span>' : '<span class="badge success">NU</span>'}</div></div>` : ''}
</div>
</div>`;
}
function renderRiskCard(risk) {
const levelClass = `risk-${risk.level.toLowerCase()}`;
let factorsHtml = '';
if (risk.factors && risk.factors.length > 0) {
risk.factors.forEach(f => {
const barColor = f.score <= 25 ? '#00c853' : f.score <= 50 ? '#ffc107' : f.score <= 75 ? '#ff9800' : '#f44336';
factorsHtml += `
<div class="risk-factor">
<div class="name">${formatFactorName(f.factor)}</div>
<div class="score">
<div class="bar"><div class="bar-fill" style="width: ${f.score}%; background: ${barColor}"></div></div>
<div class="value">${f.score}</div>
</div>
</div>`;
});
}
let formulaHtml = '';
if (risk.formula_breakdown && risk.formula_breakdown.length > 0) {
formulaHtml = '<div class="formula-box"><h4>📐 Formula de Calcul</h4>';
risk.formula_breakdown.forEach(fb => {
formulaHtml += `<div class="formula-line">${fb.category}: ${fb.formula}</div>`;
});
formulaHtml += `<div class="formula-line" style="margin-top: 10px; font-weight: bold; color: #00d9ff;">${risk.formula_string || ''}</div></div>`;
}
return `
<div class="card risk-card">
<div class="card-header"><h3>🎯 Scor de Risc</h3><span class="source">CALCULATED</span></div>
<div class="card-body">
<div class="risk-score-display">
<div class="risk-circle ${levelClass}">${risk.total}<span class="label">${risk.level}</span></div>
<div class="risk-details">
<div style="margin-bottom: 15px;">
${risk.is_new_domain ? '<span class="badge warning">Domeniu Nou</span>' : ''}
${risk.is_suspicious ? '<span class="badge danger">Suspect</span>' : ''}
${risk.is_blacklisted ? '<span class="badge danger">Blacklisted</span>' : ''}
${!risk.is_suspicious && !risk.is_blacklisted ? '<span class="badge success">OK</span>' : ''}
</div>
${factorsHtml}
</div>
</div>
${formulaHtml}
<div style="margin-top: 15px; font-size: 0.85rem; color: #888;">Praguri: LOW (0-25) | MEDIUM (26-50) | HIGH (51-75) | CRITICAL (76-100)</div>
</div>
</div>`;
}
function renderWhoisCard(w) {
const statusArray = Array.isArray(w.status) ? w.status : (w.status ? [w.status] : []);
const nsArray = Array.isArray(w.name_servers) ? w.name_servers : (w.name_servers ? [w.name_servers] : []);
return `
<div class="card">
<div class="card-header"><h3>📋 WHOIS</h3><span class="source">${w.data_source || 'WHOIS'}</span></div>
<div class="card-body">
${w.creation_date ? `<div class="data-row"><div class="data-label">Data Creare:</div><div class="data-value">${formatDate(w.creation_date)}</div></div>` : ''}
${w.age_days !== null && w.age_days !== undefined ? `<div class="data-row"><div class="data-label">Vârsta:</div><div class="data-value"><strong>${w.age_days} zile</strong> (${Math.floor(w.age_days/365)} ani)</div></div>` : ''}
${w.expiration_date ? `<div class="data-row"><div class="data-label">Expirare:</div><div class="data-value">${formatDate(w.expiration_date)}</div></div>` : ''}
${w.registrar ? `<div class="data-row"><div class="data-label">Registrar:</div><div class="data-value">${w.registrar}</div></div>` : ''}
${w.dnssec ? `<div class="data-row"><div class="data-label">DNSSEC:</div><div class="data-value">${w.dnssec}</div></div>` : ''}
${statusArray.length > 0 ? `<div class="data-row"><div class="data-label">Status:</div><div class="data-value">${statusArray.map(s => `<span class="badge info">${s}</span>`).join('')}</div></div>` : ''}
${nsArray.length > 0 ? `<div class="data-row"><div class="data-label">Name Servers:</div><div class="data-value">${nsArray.map(ns => `<span class="badge neutral">${ns}</span>`).join('')}</div></div>` : ''}
</div>
</div>`;
}
function renderDnsCard(dns) {
return `
<div class="card">
<div class="card-header"><h3>🌐 DNS Records</h3><span class="source">DNS</span></div>
<div class="card-body">
${dns.a_records?.length ? `<div class="data-row"><div class="data-label">A (IPv4):</div><div class="data-value">${dns.a_records.map(r => `<span class="badge info">${r}</span>`).join('')}</div></div>` : ''}
${dns.aaaa_records?.length ? `<div class="data-row"><div class="data-label">AAAA (IPv6):</div><div class="data-value">${dns.aaaa_records.map(r => `<span class="badge info">${r}</span>`).join('')}</div></div>` : ''}
${dns.mx_records?.length ? `<div class="data-row"><div class="data-label">MX:</div><div class="data-value">${dns.mx_records.map(r => `<span class="badge neutral">${r.priority} ${r.host}</span>`).join('')}</div></div>` : ''}
${dns.ns_records?.length ? `<div class="data-row"><div class="data-label">NS:</div><div class="data-value">${dns.ns_records.map(r => `<span class="badge neutral">${r}</span>`).join('')}</div></div>` : ''}
<div class="data-row"><div class="data-label">SPF:</div><div class="data-value"><span class="badge ${dns.has_spf ? 'success' : 'danger'}">${dns.has_spf ? '✓' : '✗'} SPF</span> <span style="color:#888;font-size:0.8rem">(DKIM/DMARC: vezi cardul Mail Intelligence)</span></div></div>
</div>
</div>`;
}
function renderSslCard(ssl) {
if (!ssl.has_ssl) {
return `<div class="card"><div class="card-header"><h3>🔒 SSL/TLS</h3><span class="source">SSL</span></div><div class="card-body"><div class="error">❌ Nu are certificat SSL</div></div></div>`;
}
return `
<div class="card">
<div class="card-header"><h3>🔒 SSL/TLS</h3><span class="source">SSL</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">Status:</div><div class="data-value">
<span class="badge ${ssl.is_valid ? 'success' : 'danger'}">${ssl.is_valid ? '✓ Valid' : '✗ Invalid'}</span>
${ssl.is_expired ? '<span class="badge danger">Expirat</span>' : ''}
${ssl.is_wildcard ? '<span class="badge info">Wildcard</span>' : ''}
</div></div>
${ssl.issuer ? `<div class="data-row"><div class="data-label">Issuer:</div><div class="data-value">${ssl.issuer}</div></div>` : ''}
${ssl.valid_until ? `<div class="data-row"><div class="data-label">Valid Until:</div><div class="data-value">${formatDate(ssl.valid_until)}</div></div>` : ''}
${ssl.days_until_expiry !== null ? `<div class="data-row"><div class="data-label">Expiră în:</div><div class="data-value"><span class="badge ${ssl.days_until_expiry < 30 ? 'warning' : 'success'}">${ssl.days_until_expiry} zile</span></div></div>` : ''}
</div>
</div>`;
}
function renderIpCard(ip) {
return `
<div class="card">
<div class="card-header"><h3>🌍 IP Intelligence</h3><span class="source">ipinfo.io</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">IP:</div><div class="data-value"><strong>${ip.ip}</strong></div></div>
${ip.reverse_dns ? `<div class="data-row"><div class="data-label">Reverse DNS:</div><div class="data-value">${ip.reverse_dns}</div></div>` : ''}
${ip.country ? `<div class="data-row"><div class="data-label">Locație:</div><div class="data-value">${ip.city || ''} ${ip.region ? ', ' + ip.region : ''}, ${ip.country}</div></div>` : ''}
${ip.asn ? `<div class="data-row"><div class="data-label">ASN:</div><div class="data-value">${ip.asn}</div></div>` : ''}
${ip.isp ? `<div class="data-row"><div class="data-label">ISP:</div><div class="data-value">${ip.isp}</div></div>` : ''}
<div class="data-row"><div class="data-label">Tip:</div><div class="data-value"><span class="badge ${ip.is_datacenter ? 'info' : 'success'}">${ip.is_datacenter ? 'Datacenter' : 'Rezidențial'}</span></div></div>
${ip.hosting_score ? `<div class="data-row"><div class="data-label">Hosting Score:</div><div class="data-value"><span class="badge ${ip.hosting_score.score <= 30 ? 'success' : ip.hosting_score.score <= 50 ? 'warning' : 'danger'}">${ip.hosting_score.score}/100</span></div></div>` : ''}
</div>
</div>`;
}
function renderHttpCard(http) {
const secHeaders = http.security_headers || {};
let headersHtml = '';
['Strict-Transport-Security', 'X-Frame-Options', 'X-Content-Type-Options', 'Content-Security-Policy'].forEach(h => {
headersHtml += `<div class="security-header"><span>${h}</span><span class="${secHeaders[h] ? 'header-present' : 'header-missing'}">${secHeaders[h] ? '✓' : '✗'}</span></div>`;
});
return `
<div class="card">
<div class="card-header"><h3>🌐 HTTP Analysis</h3><span class="source">HTTP</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">HTTPS:</div><div class="data-value">
<span class="badge ${http.has_https ? 'success' : 'danger'}">${http.has_https ? '✓' : '✗'} HTTPS</span>
${http.http_to_https_redirect ? '<span class="badge success">Auto-redirect</span>' : ''}
</div></div>
${http.server ? `<div class="data-row"><div class="data-label">Server:</div><div class="data-value">${http.server}</div></div>` : ''}
${http.cms ? `<div class="data-row"><div class="data-label">CMS:</div><div class="data-value"><span class="badge info">${http.cms}</span></div></div>` : ''}
${http.technologies?.length ? `<div class="data-row"><div class="data-label">Tech:</div><div class="data-value"><div class="tech-tags">${http.technologies.slice(0,8).map(t => `<span class="tech-tag">${t}</span>`).join('')}</div></div></div>` : ''}
${http.response_time_ms ? `<div class="data-row"><div class="data-label">Response:</div><div class="data-value">${http.response_time_ms}ms</div></div>` : ''}
<div style="margin-top: 15px; font-weight: 500; margin-bottom: 10px;">Security Headers:</div>
${headersHtml}
</div>
</div>`;
}
function renderBlacklistCard(bl) {
let checksHtml = '';
if (bl.ip_check) {
const clean = bl.ip_check.clean_lists?.slice(0,4) || [];
const listed = bl.ip_check.listings || [];
checksHtml += `<div style="margin-bottom: 10px;"><strong>IP (${bl.ip_check.total_checked}):</strong> ${listed.map(l => `<span class="badge danger">${l.list_name}</span>`).join('')} ${clean.map(l => `<span class="badge success">${l}</span>`).join('')}</div>`;
}
if (bl.domain_check) {
const clean = bl.domain_check.clean_lists?.slice(0,4) || [];
const listed = bl.domain_check.listings || [];
checksHtml += `<div><strong>Domain (${bl.domain_check.total_checked}):</strong> ${listed.map(l => `<span class="badge danger">${l.list_name}</span>`).join('')} ${clean.map(l => `<span class="badge success">${l}</span>`).join('')}</div>`;
}
return `
<div class="card">
<div class="card-header"><h3>🛡️ Blacklists</h3><span class="source">DNSBL</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">Status:</div><div class="data-value"><span class="badge ${bl.is_blacklisted ? 'danger' : 'success'}">${bl.is_blacklisted ? '❌ BLACKLISTED' : '✓ CLEAN'}</span></div></div>
<div class="data-row"><div class="data-label">Reputation:</div><div class="data-value"><span class="badge ${bl.reputation_score >= 80 ? 'success' : bl.reputation_score >= 60 ? 'warning' : 'danger'}">${bl.reputation_score}/100</span></div></div>
${checksHtml}
</div>
</div>`;
}
function renderPortCard(ports) {
const openPorts = ports.open_ports || [];
const dangerous = ports.dangerous_open || [];
const summary = ports.scan_summary || {};
let portsHtml = '<div class="port-list">';
openPorts.forEach(p => {
const isDanger = dangerous.some(d => d.port === p.port);
portsHtml += `<span class="port-item ${isDanger ? 'danger' : 'safe'}">${p.port} ${p.service}</span>`;
});
portsHtml += '</div>';
return `
<div class="card">
<div class="card-header"><h3>🔌 Port Scan</h3><span class="source">TCP</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">Rezumat:</div><div class="data-value">
<span class="badge info">${summary.open_count || 0} deschise</span>
${summary.dangerous_count > 0 ? `<span class="badge danger">${summary.dangerous_count} periculoase</span>` : ''}
</div></div>
<div class="data-row"><div class="data-label">Porturi:</div><div class="data-value">${portsHtml}</div></div>
</div>
</div>`;
}
function renderSubdomainsCard(subs) {
const subList = subs.subdomains || [];
const src = subs.sources || {};
const srcCounts = [
['CT', (src.certificate_transparency || []).length],
['Brute', (src.dns_bruteforce || []).length],
['AXFR', (src.zone_transfer || []).length],
['DNS', (src.dns_records || []).length],
['Manual', (src.user_provided || []).length],
].filter(([, n]) => n > 0).map(([k, n]) => `<span class="badge neutral">${k}: ${n}</span>`).join(' ');
return `
<div class="card">
<div class="card-header"><h3>🔎 Subdomenii</h3><span class="source">CT+DNS+Brute</span></div>
<div class="card-body">
<div class="data-row"><div class="data-label">Total:</div><div class="data-value"><strong>${subs.total_found}</strong> ${srcCounts}</div></div>
<div class="data-row"><div class="data-label">Lista:</div><div class="data-value"><div class="tech-tags">${subList.slice(0, 20).map(s => `<span class="tech-tag">${s}</span>`).join('')}${subList.length > 20 ? `<span class="badge neutral">+${subList.length - 20}</span>` : ''}</div></div></div>
${subs.has_wildcard_cert ? `<div class="data-row"><div class="data-label">⚠️ Wildcard:</div><div class="data-value"><span class="badge warning">cert *.${subs.domain}</span></div></div>` : ''}
${subs.coverage_note ? `<div style="margin-top:8px;font-size:0.78rem;color:#b8860b;line-height:1.4"> ${subs.coverage_note}</div>` : ''}
</div>
</div>`;
}
function formatFactorName(factor) {
const names = {'domain_age': '📅 Vârsta Domeniu', 'ssl': '🔒 SSL/TLS', 'dns': '🌐 DNS', 'email_security': '📧 Email Security', 'whois': '📋 WHOIS', 'ip_reputation': '🌍 IP Reputation', 'http_security': '🔐 HTTP Security', 'blacklist': '🛡️ Blacklists', 'port_security': '🔌 Porturi'};
return names[factor] || factor;
}
function formatDate(dateStr) {
if (!dateStr) return '-';
try { return new Date(dateStr).toLocaleDateString('ro-RO', { year: 'numeric', month: 'long', day: 'numeric' }); }
catch { return dateStr; }
}
</script>
</body>
</html>