106 lines
8.1 KiB
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>
|