LOT 1 - Optimizare script build -Instalare mono comanda
This commit is contained in:
parent
5380c3fc63
commit
42ff22bf85
127 changed files with 16163 additions and 532 deletions
637
ai_platform/modules/domain_check/api/app/static/index.html
Normal file
637
ai_platform/modules/domain_check/api/app/static/index.html
Normal 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>
|
||||
Loading…
Add table
Add a link
Reference in a new issue