283 lines
12 KiB
HTML
283 lines
12 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
<title>AASD — Security Simulation</title>
|
|
<script src="https://cdn.tailwindcss.com/"></script>
|
|
<script>
|
|
tailwind.config = {
|
|
theme: {
|
|
extend: {
|
|
colors: {
|
|
aasd: { dark: '#0f172a', card: '#1e293b', border: '#334155', blue: '#3b82f6', purple: '#8b5cf6', text: '#f1f5f9', muted: '#94a3b8', dim: '#64748b' }
|
|
}
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
<style>
|
|
* { -webkit-tap-highlight-color: transparent; }
|
|
body { overscroll-behavior: none; }
|
|
.step-indicator { transition: all 0.5s ease; }
|
|
@keyframes pulse-dot { 0%, 100% { opacity: 1; } 50% { opacity: 0.4; } }
|
|
.pulsing::after { content: ''; display: inline-block; width: 8px; height: 8px; background: #3b82f6; border-radius: 50%; margin-left: 8px; animation: pulse-dot 1.5s infinite; }
|
|
</style>
|
|
</head>
|
|
<body class="bg-slate-900 text-slate-100 min-h-screen">
|
|
<div class="container mx-auto px-4 py-6 max-w-lg">
|
|
|
|
<!-- Header -->
|
|
<div class="text-center mb-6">
|
|
<h1 class="text-2xl font-bold bg-gradient-to-r from-blue-400 to-purple-400 bg-clip-text text-transparent">AASD</h1>
|
|
<p class="text-sm text-slate-400">API Attack Surface Discovery</p>
|
|
<div class="mt-3 inline-block bg-slate-800 border-2 border-slate-600 rounded-full px-4 py-1.5 text-sm text-blue-400 font-mono" id="domainBadge">domain.com</div>
|
|
</div>
|
|
|
|
<!-- Progress Bar -->
|
|
<div class="w-full h-2 bg-slate-800 rounded-full mb-6 overflow-hidden">
|
|
<div class="h-full bg-gradient-to-r from-blue-500 to-purple-500 rounded-full transition-all duration-700 ease-out" id="progressFill" style="width: 0%"></div>
|
|
</div>
|
|
|
|
<!-- Step Sequencer (5 steps for new workflow) -->
|
|
<div class="bg-slate-800 rounded-2xl p-5 border border-slate-700 mb-4">
|
|
<h2 class="text-sm font-semibold text-slate-400 uppercase tracking-wider mb-4">Discovery Pipeline</h2>
|
|
<div class="space-y-3">
|
|
<!-- Step 1: Email Validation -->
|
|
<div class="step-indicator flex items-center gap-3 p-3 rounded-xl bg-slate-900 border border-slate-700" id="step1">
|
|
<div class="w-8 h-8 rounded-full bg-slate-700 text-slate-400 text-sm font-bold flex items-center justify-center shrink-0" id="icon1">1</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="text-sm font-semibold text-slate-200" id="title1">Email Validation</div>
|
|
<div class="text-xs text-slate-500" id="desc1">Verifying email and extracting domain</div>
|
|
</div>
|
|
<div class="text-xs text-slate-600 shrink-0" id="time1">0-2s</div>
|
|
</div>
|
|
|
|
<!-- Step 2: Domain Discovery -->
|
|
<div class="step-indicator flex items-center gap-3 p-3 rounded-xl bg-slate-900 border border-slate-700" id="step2">
|
|
<div class="w-8 h-8 rounded-full bg-slate-700 text-slate-400 text-sm font-bold flex items-center justify-center shrink-0" id="icon2">2</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="text-sm font-semibold text-slate-200" id="title2">Domain Discovery</div>
|
|
<div class="text-xs text-slate-500" id="desc2">Scanning subdomains with passive enumeration</div>
|
|
</div>
|
|
<div class="text-xs text-slate-600 shrink-0" id="time2">2-10s</div>
|
|
</div>
|
|
|
|
<!-- Step 3: Filter & Target Selection -->
|
|
<div class="step-indicator flex items-center gap-3 p-3 rounded-xl bg-slate-900 border border-slate-700" id="step3">
|
|
<div class="w-8 h-8 rounded-full bg-slate-700 text-slate-400 text-sm font-bold flex items-center justify-center shrink-0" id="icon3">3</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="text-sm font-semibold text-slate-200" id="title3">Target Selection</div>
|
|
<div class="text-xs text-slate-500" id="desc3">Identifying the most critical endpoint</div>
|
|
</div>
|
|
<div class="text-xs text-slate-600 shrink-0" id="time3">2-5s</div>
|
|
</div>
|
|
|
|
<!-- Step 4: GoTestWAF Scan -->
|
|
<div class="step-indicator flex items-center gap-3 p-3 rounded-xl bg-slate-900 border border-slate-700" id="step4">
|
|
<div class="w-8 h-8 rounded-full bg-slate-700 text-slate-400 text-sm font-bold flex items-center justify-center shrink-0" id="icon4">4</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="text-sm font-semibold text-slate-200" id="title4">WAF Penetration Test</div>
|
|
<div class="text-xs text-slate-500" id="desc4">GoTestWAF scanning against Wallarm endpoint</div>
|
|
</div>
|
|
<div class="text-xs text-slate-600 shrink-0" id="time4">10-120s</div>
|
|
</div>
|
|
|
|
<!-- Step 5: AI Report Generation -->
|
|
<div class="step-indicator flex items-center gap-3 p-3 rounded-xl bg-slate-900 border border-slate-700" id="step5">
|
|
<div class="w-8 h-8 rounded-full bg-slate-700 text-slate-400 text-sm font-bold flex items-center justify-center shrink-0" id="icon5">5</div>
|
|
<div class="flex-1 min-w-0">
|
|
<div class="text-sm font-semibold text-slate-200" id="title5">AI Resilience Narrative</div>
|
|
<div class="text-xs text-slate-500" id="desc5">DeepSeek AI generating your report</div>
|
|
</div>
|
|
<div class="text-xs text-slate-600 shrink-0" id="time5">5-15s</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Status -->
|
|
<div class="bg-slate-800 rounded-2xl p-5 border border-slate-700 text-center mb-4">
|
|
<div class="text-sm text-slate-400 mb-1">Status</div>
|
|
<div class="text-lg font-bold text-slate-200" id="statusDisplay">
|
|
<span class="inline-flex items-center gap-2">
|
|
<span class="w-2.5 h-2.5 rounded-full bg-slate-500" id="statusDot"></span>
|
|
<span id="statusText">Pending</span>
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Result Panel (shown on completion) -->
|
|
<div id="resultPanel" class="hidden bg-slate-800 rounded-2xl p-5 border border-slate-700 text-center mb-4">
|
|
<h2 class="text-lg font-bold text-slate-100 mb-3">Discovery Complete</h2>
|
|
<div class="grid grid-cols-2 gap-3 mb-4">
|
|
<div class="bg-slate-900 rounded-xl p-3">
|
|
<div class="text-2xl font-bold text-blue-400" id="subdomainCount">0</div>
|
|
<div class="text-xs text-slate-400">Subdomains Found</div>
|
|
</div>
|
|
<div class="bg-slate-900 rounded-xl p-3">
|
|
<div class="text-2xl font-bold text-green-400" id="wafStatus">Ready</div>
|
|
<div class="text-xs text-slate-400">WAF Tested</div>
|
|
</div>
|
|
</div>
|
|
<a id="reportLink" href="#"
|
|
class="btn-primary block w-full text-white font-bold py-4 px-6 rounded-xl text-lg shadow-lg hover:shadow-blue-500/25 active:scale-[0.97] transition-all"
|
|
style="background: linear-gradient(90deg, #3b82f6, #8b5cf6);">
|
|
View Your Resilience Report
|
|
</a>
|
|
<p class="text-xs text-slate-500 mt-3">Show this code to <strong class="text-blue-400">Sechpoint Aftica Team</strong></p>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="text-center text-xs text-slate-600 mt-6">
|
|
GITEX 2026 — sechpoint.app | <a href="/admin-dashboard" class="text-blue-500 hover:underline">Consultant Dashboard</a>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// Get token from URL
|
|
const urlParams = new URLSearchParams(window.location.search);
|
|
const token = urlParams.get('token');
|
|
const domainParam = urlParams.get('domain');
|
|
|
|
// Determine what identifier to use for polling
|
|
const pollId = token || domainParam || 'unknown';
|
|
|
|
// Show domain if available, or mask for token
|
|
if (domainParam) {
|
|
document.getElementById('domainBadge').textContent = domainParam;
|
|
} else if (token) {
|
|
document.getElementById('domainBadge').textContent = 'Scan: ' + token.substring(0, 8) + '...';
|
|
}
|
|
|
|
const steps = ['step1', 'step2', 'step3', 'step4', 'step5'];
|
|
let currentStep = -1;
|
|
const statusText = document.getElementById('statusText');
|
|
const statusDot = document.getElementById('statusDot');
|
|
const progressFill = document.getElementById('progressFill');
|
|
const resultPanel = document.getElementById('resultPanel');
|
|
const statusDisplay = document.getElementById('statusDisplay');
|
|
|
|
// Map API statuses to step indices
|
|
const statusStepMap = {
|
|
'pending': -1,
|
|
'discovering': 0, // step 1-2
|
|
'scanning': 2, // step 3-4
|
|
'generating': 4, // step 5
|
|
'completed': 5,
|
|
'failed': -2
|
|
};
|
|
|
|
function setActive(stepIndex) {
|
|
// Reset all steps
|
|
steps.forEach((id, idx) => {
|
|
const el = document.getElementById(id);
|
|
const icon = document.getElementById('icon' + (idx + 1));
|
|
el.classList.remove('border-blue-500', 'bg-blue-500/10', 'border-green-500', 'bg-green-500/10');
|
|
el.classList.add('border-slate-700');
|
|
el.classList.remove('pulsing');
|
|
if (idx < stepIndex) {
|
|
// Completed
|
|
el.classList.add('border-green-500', 'bg-green-500/10');
|
|
icon.textContent = '✓';
|
|
icon.className = 'w-8 h-8 rounded-full bg-green-600 text-white text-sm font-bold flex items-center justify-center shrink-0';
|
|
} else if (idx === stepIndex) {
|
|
// Active
|
|
el.classList.add('border-blue-500', 'bg-blue-500/10');
|
|
icon.textContent = idx + 1;
|
|
icon.className = 'w-8 h-8 rounded-full bg-blue-600 text-white text-sm font-bold flex items-center justify-center shrink-0';
|
|
} else {
|
|
// Pending
|
|
icon.textContent = idx + 1;
|
|
icon.className = 'w-8 h-8 rounded-full bg-slate-700 text-slate-400 text-sm font-bold flex items-center justify-center shrink-0';
|
|
}
|
|
});
|
|
if (stepIndex >= 0 && stepIndex < steps.length) {
|
|
const maxSteps = steps.length;
|
|
const pct = Math.min(100, Math.round(((stepIndex + 1) / maxSteps) * 100));
|
|
progressFill.style.width = pct + '%';
|
|
}
|
|
}
|
|
|
|
function setStatus(label, color) {
|
|
statusText.textContent = label;
|
|
statusDot.className = 'w-2.5 h-2.5 rounded-full ' + color;
|
|
}
|
|
|
|
function showResults(data) {
|
|
resultPanel.classList.remove('hidden');
|
|
document.getElementById('subdomainCount').textContent = data.subdomains_discovered || 'N/A';
|
|
document.getElementById('wafStatus').textContent = data.status === 'completed' ? 'Passed' : 'N/A';
|
|
document.getElementById('reportLink').href = data.report || ('/reports/' + token + '.html');
|
|
|
|
// Mark step 5 complete
|
|
setActive(5);
|
|
progressFill.style.width = '100%';
|
|
setStatus('Completed', 'bg-green-500');
|
|
statusDisplay.className = 'bg-slate-800 rounded-2xl p-5 border border-green-500/50 text-center mb-4';
|
|
}
|
|
|
|
function showFailed() {
|
|
setStatus('Failed', 'bg-red-500');
|
|
statusDisplay.className = 'bg-slate-800 rounded-2xl p-5 border border-red-500/50 text-center mb-4';
|
|
}
|
|
|
|
// Poll scan status
|
|
async function pollStatus() {
|
|
try {
|
|
const resp = await fetch('/scan-status/' + encodeURIComponent(pollId));
|
|
if (!resp.ok) return;
|
|
const data = await resp.json();
|
|
const apiStatus = data.status || '';
|
|
|
|
// Map status to step
|
|
if (apiStatus === 'completed') {
|
|
showResults(data);
|
|
return;
|
|
}
|
|
if (apiStatus === 'failed') {
|
|
showFailed();
|
|
return;
|
|
}
|
|
|
|
const stepIndex = statusStepMap[apiStatus] !== undefined ? statusStepMap[apiStatus] : -1;
|
|
if (stepIndex === -2) {
|
|
showFailed();
|
|
return;
|
|
}
|
|
|
|
if (stepIndex >= 0) {
|
|
setActive(stepIndex);
|
|
}
|
|
|
|
// Update status display
|
|
switch (apiStatus) {
|
|
case 'pending':
|
|
setStatus('Pending', 'bg-slate-500');
|
|
break;
|
|
case 'discovering':
|
|
setStatus('Discovering Subdomains', 'bg-blue-500');
|
|
break;
|
|
case 'scanning':
|
|
setStatus('Scanning WAF Endpoint', 'bg-purple-500');
|
|
break;
|
|
case 'generating':
|
|
setStatus('Generating AI Report', 'bg-yellow-500');
|
|
break;
|
|
default:
|
|
setStatus(apiStatus, 'bg-slate-500');
|
|
}
|
|
} catch (err) {
|
|
console.error('Poll error:', err);
|
|
}
|
|
}
|
|
|
|
// Start polling
|
|
pollStatus();
|
|
setInterval(pollStatus, 3000);
|
|
|
|
// Activate first step initially
|
|
setActive(0);
|
|
setStatus('Starting Pipeline', 'bg-blue-500');
|
|
</script>
|
|
</body>
|
|
</html>
|