Files
weval-consulting/security-dashboard.html

106 lines
8.1 KiB
HTML

<!DOCTYPE html><html lang="en"><head>
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1">
<title>WEVAL Security Scanner — Secret Detection</title>
<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@400;500;700&family=JetBrains+Mono:wght@400;500&display=swap" rel="stylesheet">
<style>
:root{--bg:#0a0e1a;--card:#111827;--border:#1e293b;--red:#ef4444;--green:#10b981;--yellow:#f59e0b;--blue:#3b82f6;--text:#e2e8f0;--muted:#64748b;--mono:'JetBrains Mono',monospace;--font:'DM Sans',sans-serif}
*{margin:0;padding:0;box-sizing:border-box}body{background:var(--bg);color:var(--text);font-family:var(--font)}
.top{display:flex;align-items:center;justify-content:space-between;padding:16px 24px;background:rgba(17,24,39,.95);border-bottom:1px solid var(--border);position:sticky;top:0;z-index:100}
.logo{font-size:18px;font-weight:700;color:var(--red)}.logo span{color:var(--text);font-weight:400}
.kpis{display:grid;grid-template-columns:repeat(auto-fit,minmax(160px,1fr));gap:12px;padding:20px 24px}
.kpi{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:18px;text-align:center}
.kpi .v{font-size:32px;font-weight:700;font-family:var(--mono)}.kpi .l{font-size:11px;color:var(--muted);text-transform:uppercase;letter-spacing:1px;margin-top:4px}
.main{display:grid;grid-template-columns:1fr 1fr;gap:16px;padding:0 24px 24px}
.full{grid-column:1/-1}.card{background:var(--card);border:1px solid var(--border);border-radius:12px;padding:20px;animation:fadeIn .3s}
.card h3{font-size:14px;font-weight:600;margin-bottom:12px;display:flex;align-items:center;gap:8px}
.badge{font-size:10px;padding:2px 8px;border-radius:99px;font-weight:500}
.bg{background:rgba(16,185,129,.2);color:var(--green)}.br{background:rgba(239,68,68,.2);color:var(--red)}.by{background:rgba(245,158,11,.2);color:var(--yellow)}.bb{background:rgba(59,130,246,.2);color:var(--blue)}
.tool{display:flex;align-items:center;gap:12px;padding:12px;border-bottom:1px solid var(--border)}
.tool:last-child{border:none}.tool .dot{width:10px;height:10px;border-radius:50%}.tool .name{font-weight:600;font-size:13px}.tool .desc{font-size:11px;color:var(--muted)}
.finding{padding:10px 12px;border-left:3px solid var(--yellow);background:rgba(245,158,11,.05);margin-bottom:6px;border-radius:0 6px 6px 0;font-size:12px}
.key{display:flex;justify-content:space-between;align-items:center;padding:8px 12px;border-bottom:1px solid var(--border);font-size:12px}
.key .kn{font-weight:600;font-family:var(--mono)}.key .kv{color:var(--green);font-size:10px}
.btn{padding:10px 20px;border-radius:8px;border:none;cursor:pointer;font-weight:700;font-size:13px;transition:.2s}
.btn:hover{transform:translateY(-1px)}
.btn-red{background:var(--red);color:white}.btn-green{background:var(--green);color:white}.btn-blue{background:var(--blue);color:white}
#status{font-family:var(--mono);font-size:12px;padding:4px 12px;border-radius:6px}
@keyframes fadeIn{from{opacity:0;transform:translateY(8px)}to{opacity:1;transform:translateY(0)}}
@keyframes pulse{0%,100%{opacity:1}50%{opacity:.5}}
.scanning{animation:pulse 1s infinite}
@media(max-width:768px){.main{grid-template-columns:1fr}}
</style></head><body>
<div class="top">
<div class="logo">🔐 WEVAL <span>Security Scanner</span></div>
<div style="display:flex;gap:8px;align-items:center">
<span id="status" class="bg">● IDLE</span>
<button class="btn btn-red" onclick="runScan()">🔍 Scan Now</button>
<button class="btn btn-blue" onclick="syncKeys()">🔄 Sync Keys</button>
</div>
</div>
<div class="kpis" id="kpis"></div>
<div class="main">
<div class="card"><h3>🛠️ Scanner Tools <span class="badge bb" id="tools-count">5</span></h3><div id="tools-list"></div></div>
<div class="card"><h3>⚠️ Findings <span class="badge by" id="findings-count">0</span></h3><div id="findings-list"></div></div>
<div class="card"><h3>🔑 Tracked Keys <span class="badge bg" id="keys-count">0</span></h3><div id="keys-list" style="max-height:400px;overflow-y:auto"></div></div>
<div class="card"><h3>📁 Sensitive Files <span class="badge br" id="files-count">0</span></h3><div id="files-list" style="max-height:400px;overflow-y:auto"></div></div>
<div class="card full"><h3>📋 Scan History</h3><div id="history" style="font-family:var(--mono);font-size:12px;color:var(--muted)">Loading...</div></div>
</div>
<script>
const API='/api/secret-scanner-api.php';
async function load(){
try{
const r=await fetch(API+'?action=results');
const d=await r.json();
if(d.error){document.getElementById('history').textContent='No scan yet. Click Scan Now.';return}
// KPIs
const s=d.summary||{};
const kpis=[
{v:s.findings||0,l:'Findings',c:s.findings>5?'var(--red)':'var(--green)'},
{v:s.tools||5,l:'Tools Active',c:'var(--blue)'},
{v:(d.tools?.keyhacks?.tracked||0),l:'Keys Tracked',c:'var(--yellow)'},
{v:s.risk||'LOW',l:'Risk Level',c:s.risk==='HIGH'?'var(--red)':s.risk==='MEDIUM'?'var(--yellow)':'var(--green)'},
{v:d.repos||0,l:'Repos Scanned',c:'var(--blue)'},
{v:d.timestamp?.split('T')[1]?.substring(0,5)||'-',l:'Last Scan',c:'var(--muted)'}
];
document.getElementById('kpis').innerHTML=kpis.map(k=>'<div class="kpi"><div class="v" style="color:'+k.c+'">'+k.v+'</div><div class="l">'+k.l+'</div></div>').join('');
// Tools
const tools=[
{name:'TruffleHog',desc:'Git repo entropy + regex scanner',icon:'🐷',ok:d.tools?.trufflehog?.ok},
{name:'detect-secrets',desc:'Yelp secret detection engine',icon:'🔍',ok:d.tools?.['detect-secrets']?.ok!==false},
{name:'GitHub Dorking',desc:'Regex pattern search (AWS,Stripe,GitHub)',icon:'🕵️',ok:d.tools?.dorking?.ok},
{name:'KeyHacks',desc:'API key validation reference',icon:'🔑',ok:d.tools?.keyhacks?.ok},
{name:'shhgit Patterns',desc:'Sensitive file detection',icon:'🤫',ok:d.tools?.shhgit?.ok}
];
document.getElementById('tools-list').innerHTML=tools.map(t=>'<div class="tool"><div class="dot" style="background:'+(t.ok?'var(--green)':'var(--red)')+'"></div><div><div class="name">'+t.icon+' '+t.name+'</div><div class="desc">'+t.desc+'</div></div></div>').join('');
document.getElementById('tools-count').textContent=tools.filter(t=>t.ok).length+'/'+tools.length;
// Findings
const findings=d.findings||[];
document.getElementById('findings-count').textContent=findings.length;
document.getElementById('findings-list').innerHTML=findings.length?findings.map(f=>'<div class="finding"><strong>'+f.file+'</strong> — '+f.matches+' match(es)</div>').join(''):'<div style="color:var(--green);padding:20px;text-align:center">✅ No exposed secrets found</div>';
// Keys
const keys=d.tools?.keyhacks?.keys||[];
document.getElementById('keys-count').textContent=keys.length;
document.getElementById('keys-list').innerHTML=keys.map(k=>'<div class="key"><span class="kn">'+k+'</span><span class="kv">● tracked</span></div>').join('');
// Files
const files=d.tools?.shhgit?.files||[];
document.getElementById('files-count').textContent=files.length;
document.getElementById('files-list').innerHTML=files.map(f=>'<div style="padding:4px 8px;font-size:11px;font-family:var(--mono);border-bottom:1px solid var(--border)">📄 '+f+'</div>').join('')||'<div style="padding:20px;text-align:center;color:var(--muted)">No sensitive files outside secrets.env</div>';
// History
document.getElementById('history').textContent='Last scan: '+d.timestamp+' | Repos: '+d.repos+' | Risk: '+s.risk;
}catch(e){document.getElementById('history').textContent='Error: '+e.message}
}
async function runScan(){
document.getElementById('status').className='badge br scanning';
document.getElementById('status').textContent='● SCANNING...';
await fetch(API+'?action=scan');
setTimeout(()=>{document.getElementById('status').className='badge bg';document.getElementById('status').textContent='● DONE';load()},15000);
}
async function syncKeys(){
document.getElementById('status').textContent='● SYNCING...';
// Trigger key sync cron
await fetch(API+'?action=scan');
setTimeout(load,10000);
}
load();setInterval(load,60000);
</script></body></html>