Tráfego de Redes
Atualizado em
28/08/2025 18h34
realistic-network-analyzer.html
— 104 KB
Conteúdo do arquivo
<!DOCTYPE html>
<html lang="pt-BR">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Analisador de Tráfego de Rede Realístico</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Consolas', 'Monaco', 'Courier New', monospace;
background: #1a1a1a;
color: #fff;
overflow-x: hidden;
}
.header {
background: #000;
padding: 10px 20px;
border-bottom: 1px solid #333;
display: flex;
justify-content: space-between;
align-items: center;
}
.header h1 {
color: #fff;
font-size: 1.5rem;
font-weight: bold;
}
.header .status {
display: flex;
gap: 20px;
font-size: 0.9rem;
}
.status-item {
color: #888;
}
.status-item.active {
color: #fff;
}
.main-container {
display: grid;
grid-template-columns: 1fr 350px;
height: calc(100vh - 60px);
gap: 1px;
background: #333;
}
.packet-capture {
background: #1a1a1a;
overflow: hidden;
display: flex;
flex-direction: column;
}
.capture-controls {
background: #2a2a2a;
padding: 10px 15px;
border-bottom: 1px solid #444;
display: flex;
gap: 10px;
align-items: center;
}
.btn {
background: #333;
color: #fff;
border: 1px solid #555;
padding: 5px 12px;
cursor: pointer;
font-family: inherit;
font-size: 0.8rem;
}
.btn:hover {
background: #444;
border-color: #fff;
}
.btn.active {
background: #fff;
color: #000;
}
.btn.danger {
color: #ff4444;
border-color: #ff4444;
}
.btn.danger:hover {
background: #ff4444;
color: #fff;
}
.filter-input {
background: #1a1a1a;
color: #fff;
border: 1px solid #555;
padding: 4px 8px;
font-family: inherit;
font-size: 0.8rem;
width: 200px;
}
.filter-input:focus {
outline: none;
border-color: #fff;
}
.packet-list {
flex: 1;
overflow-y: auto;
background: #000;
}
.packet-header {
background: #2a2a2a;
padding: 5px;
font-size: 0.7rem;
font-weight: bold;
color: #ccc;
display: grid;
grid-template-columns: 60px 100px 120px 120px 80px 80px 1fr;
gap: 10px;
border-bottom: 1px solid #444;
}
.packet-row {
display: grid;
grid-template-columns: 60px 100px 120px 120px 80px 80px 1fr;
gap: 10px;
padding: 3px 5px;
font-size: 0.75rem;
border-bottom: 1px solid #222;
cursor: pointer;
transition: background 0.1s;
}
.packet-row:hover {
background: #2a2a2a;
}
.packet-row.selected {
background: #003300;
border: 1px solid #fff;
}
.packet-row.suspicious {
background: #331100;
color: #ffaa00;
}
.packet-row.malicious {
background: #330000;
color: #ff4444;
}
.packet-row.resolved {
background: #001133;
color: #4488ff;
}
.packet-analysis {
background: #1a1a1a;
overflow-y: auto;
display: flex;
flex-direction: column;
}
.analysis-tabs {
display: flex;
background: #2a2a2a;
border-bottom: 1px solid #444;
}
.tab {
padding: 8px 15px;
cursor: pointer;
font-size: 0.8rem;
color: #888;
border-right: 1px solid #444;
}
.tab.active {
background: #1a1a1a;
color: #fff;
border-bottom: 2px solid #fff;
}
.analysis-content {
flex: 1;
padding: 15px;
overflow-y: auto;
}
.hex-view {
font-family: 'Consolas', monospace;
font-size: 0.7rem;
line-height: 1.4;
background: #0a0a0a;
padding: 10px;
border: 1px solid #333;
overflow-x: auto;
white-space: pre;
}
.protocol-tree {
font-size: 0.8rem;
}
.protocol-layer {
margin: 5px 0;
border-left: 2px solid #444;
padding-left: 10px;
}
.protocol-layer.expandable {
cursor: pointer;
}
.protocol-layer.expanded {
border-left-color: #fff;
}
.protocol-header {
color: #00aaff;
font-weight: bold;
margin-bottom: 5px;
}
.protocol-details {
color: #ccc;
font-size: 0.75rem;
margin-left: 15px;
}
.threat-indicators {
background: #2a0000;
border: 1px solid #ff4444;
padding: 10px;
margin: 10px 0;
border-radius: 3px;
}
.threat-indicators h4 {
color: #ff4444;
margin-bottom: 10px;
}
.indicator-list {
list-style: none;
}
.indicator-list li {
color: #ffaa00;
margin: 3px 0;
font-size: 0.8rem;
}
.indicator-list li:before {
content: "⚠ ";
color: #ff4444;
}
.stats-panel {
background: #0a0a0a;
border: 1px solid #333;
padding: 10px;
margin: 10px 0;
font-size: 0.8rem;
}
.stats-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
}
.stat-item {
display: flex;
justify-content: space-between;
}
.timeline-view {
font-size: 0.8rem;
}
.timeline-entry {
display: flex;
margin: 5px 0;
padding: 5px 0;
border-bottom: 1px solid #222;
}
.timeline-time {
color: #00aaff;
width: 100px;
flex-shrink: 0;
}
.timeline-event {
color: #ccc;
}
.real-time-indicator {
display: inline-block;
width: 8px;
height: 8px;
background: #fff;
border-radius: 50%;
animation: pulse 1s infinite;
margin-right: 5px;
}
@keyframes pulse {
0% { opacity: 1; }
50% { opacity: 0.3; }
100% { opacity: 1; }
}
.traffic-volume {
background: #0a0a0a;
height: 40px;
border: 1px solid #333;
margin: 10px 0;
position: relative;
overflow: hidden;
}
.volume-bar {
height: 100%;
background: linear-gradient(90deg, #004400, #fff);
width: 0%;
transition: width 0.5s ease;
}
.volume-label {
position: absolute;
top: 50%;
left: 10px;
transform: translateY(-50%);
font-size: 0.7rem;
color: #888;
}
.alert-panel {
background: #330000;
border: 1px solid #ff4444;
padding: 10px;
margin: 10px 0;
border-radius: 3px;
display: none;
}
.alert-panel.show {
display: block;
animation: alertBlink 0.5s ease;
}
.investigation-panel {
background: #002200;
border: 1px solid #00aa00;
padding: 15px;
margin: 10px 0;
border-radius: 5px;
display: none;
}
.investigation-panel.show {
display: block;
}
.investigation-actions {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin: 10px 0;
}
.action-btn {
background: #003300;
color: #fff;
border: 1px solid #00aa00;
padding: 8px 12px;
cursor: pointer;
border-radius: 3px;
font-size: 0.8rem;
transition: all 0.2s;
}
.action-btn:hover {
background: #00aa00;
color: #000;
}
.action-btn:disabled {
opacity: 0.5;
cursor: not-allowed;
}
.score-panel {
position: fixed;
top: 140px;
right: 370px;
background: #1a1a1a;
border: 1px solid #fff;
padding: 15px;
border-radius: 5px;
min-width: 200px;
z-index: 100;
}
.score-item {
display: flex;
justify-content: space-between;
margin: 5px 0;
font-size: 0.9rem;
}
.score-value {
color: #fff;
font-weight: bold;
}
.investigation-log {
background: #0a0a0a;
border: 1px solid #333;
padding: 10px;
margin: 10px 0;
max-height: 200px;
overflow-y: auto;
font-size: 0.8rem;
}
.log-entry {
margin: 3px 0;
padding: 2px 0;
border-bottom: 1px solid #222;
}
.log-success {
color: #fff;
}
.log-warning {
color: #ffaa00;
}
.log-error {
color: #ff4444;
}
.challenge-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: none;
align-items: center;
justify-content: center;
z-index: 1000;
}
.modal-content {
background: #1a1a1a;
border: 2px solid #fff;
padding: 20px;
border-radius: 10px;
max-width: 600px;
max-height: 80vh;
overflow-y: auto;
}
.modal-header {
color: #fff;
font-size: 1.2rem;
margin-bottom: 15px;
text-align: center;
}
.challenge-options {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 10px;
margin: 15px 0;
}
.option-btn {
background: #2a2a2a;
color: #ccc;
border: 1px solid #555;
padding: 10px;
cursor: pointer;
border-radius: 5px;
text-align: left;
transition: all 0.2s;
}
.option-btn:hover {
border-color: #fff;
background: #333;
}
.option-btn.correct {
border-color: #fff;
background: #002200;
color: #fff;
}
.option-btn.incorrect {
border-color: #ff4444;
background: #330000;
color: #ff4444;
}
@keyframes alertBlink {
0% { background: #330000; }
50% { background: #550000; }
100% { background: #330000; }
}
.network-map {
background: #0a0a0a;
border: 1px solid #333;
padding: 15px;
margin: 10px 0;
min-height: 200px;
position: relative;
}
.network-node {
position: absolute;
width: 40px;
height: 40px;
border: 2px solid #fff;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.7rem;
background: #1a1a1a;
cursor: pointer;
}
.network-node.suspicious {
border-color: #ffaa00;
background: #332200;
}
.network-node.malicious {
border-color: #ff4444;
background: #330000;
}
.connection-line {
position: absolute;
height: 2px;
background: #444;
transform-origin: left center;
}
.connection-line.active {
background: #fff;
animation: dataFlow 1s linear infinite;
}
@keyframes dataFlow {
0% { box-shadow: 0 0 0 #fff; }
100% { box-shadow: 100px 0 0 #fff; }
}
.instructions-overlay {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.9);
border: 2px solid #fff;
border-radius: 10px;
padding: 20px;
max-width: 500px;
z-index: 50;
color: #fff;
font-size: 0.9rem;
text-align: center;
line-height: 1.5;
}
.instructions-overlay h3 {
color: #fff;
margin-bottom: 15px;
font-size: 1.1rem;
}
.instructions-overlay ol {
text-align: left;
margin: 15px 0;
padding-left: 20px;
}
.instructions-overlay li {
margin: 8px 0;
color: #ccc;
}
.instructions-overlay .highlight {
color: #fff;
font-weight: bold;
}
.close-instructions {
background: #333;
color: #fff;
border: 1px solid #555;
padding: 8px 15px;
cursor: pointer;
border-radius: 5px;
margin-top: 15px;
}
.close-instructions:hover {
background: #555;
}
.game-over-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.9);
display: none;
align-items: center;
justify-content: center;
z-index: 2000;
}
.game-over-content {
background: #1a1a1a;
border: 3px solid;
padding: 30px;
border-radius: 15px;
max-width: 600px;
text-align: center;
}
.success-modal .game-over-content {
border-color: #00ff00;
}
.failure-modal .game-over-content {
border-color: #ff4444;
}
.game-over-title {
font-size: 2rem;
margin-bottom: 20px;
font-weight: bold;
}
.success-modal .game-over-title {
color: #00ff00;
}
.failure-modal .game-over-title {
color: #ff4444;
}
.game-stats {
margin: 20px 0;
padding: 20px;
background: #0a0a0a;
border: 1px solid #333;
border-radius: 5px;
}
.stat-line {
display: flex;
justify-content: space-between;
margin: 10px 0;
font-size: 1.1rem;
}
.restart-btn {
background: #003366;
color: #fff;
border: 2px solid #0066cc;
padding: 15px 30px;
cursor: pointer;
border-radius: 8px;
font-size: 1.1rem;
margin-top: 20px;
}
.restart-btn:hover {
background: #0066cc;
}
.scrollbar::-webkit-scrollbar {
width: 8px;
}
.scrollbar::-webkit-scrollbar-track {
background: #1a1a1a;
}
.scrollbar::-webkit-scrollbar-thumb {
background: #444;
border-radius: 4px;
}
.scrollbar::-webkit-scrollbar-thumb:hover {
background: #555;
}
</style>
</head>
<body>
<div class="header">
<h1>Analisador de Tráfego v2.1</h1>
<div class="status">
<div class="status-item">
<span class="real-time-indicator" style="background: #666;"></span>PARADO
</div>
<div class="status-item">Interface: eth0</div>
<div class="status-item">Taxa: <span id="packetRate">0</span> pkt/s</div>
<div class="status-item">Capturados: <span id="totalPackets">0</span></div>
<div class="status-item">Ameaças: <span id="threatsFound">0</span></div>
</div>
</div>
<div class="main-container">
<div class="packet-capture" style="position: relative;">
<!-- Instructions Overlay -->
<div class="instructions-overlay" id="instructionsOverlay">
<h3>🎯 Como Jogar - Analisador de Tráfego</h3>
<p><strong>Controles do Jogo:</strong></p>
<p>• <span class="highlight">Iniciar</span> = Começar captura de pacotes<br>
• <span class="highlight">Parar</span> = Pausar captura<br>
• <span class="highlight">Limpar</span> = Apagar todos os pacotes</p>
<p><strong>Como Investigar Ameaças:</strong></p>
<ol>
<li>Procure pacotes <span class="highlight">VERMELHOS/LARANJAS</span> com 🚨</li>
<li>Faça um filtro e <span class="highlight">Clique</span> no pacote suspeito</li>
<li>Use as <span class="highlight">Ferramentas de Investigação</span> no painel direito</li>
<li>Clique <span class="highlight">"Iniciar Desafio"</span> para resolver a ameaça</li>
</ol>
<button class="close-instructions" onclick="analyzer.closeInstructions()">Entendi, Começar Jogo!</button>
</div>
<div class="capture-controls">
<button class="btn" id="startCapture">Iniciar</button>
<button class="btn" id="stopCapture">Parar</button>
<button class="btn danger" id="clearCapture">Limpar</button>
<input type="text" class="filter-input" id="filterInput" placeholder="Filtro (ex: tcp, udp, http, ip.src==192.168.1.1)">
<button class="btn" id="applyFilter">Aplicar</button>
<button class="btn" id="exportPcap">Exportar PCAP</button>
</div>
<div class="packet-header">
<div>Nº</div>
<div>Tempo</div>
<div>Origem</div>
<div>Destino</div>
<div>Protocolo</div>
<div>Tamanho</div>
<div>Info</div>
</div>
<div class="packet-list scrollbar" id="packetList">
<!-- Packets will be populated here -->
</div>
</div>
<div class="packet-analysis">
<div class="analysis-tabs">
<div class="tab active" data-tab="details">Detalhes</div>
<div class="tab" data-tab="hex">Dump Hex</div>
<div class="tab" data-tab="protocols">Protocolos</div>
<div class="tab" data-tab="timeline">Linha do Tempo</div>
<div class="tab" data-tab="network">Rede</div>
</div>
<div class="analysis-content scrollbar" id="analysisContent">
<div id="detailsTab">
<h3 style="color: #00aaff; margin-bottom: 15px;">Análise de Pacote</h3>
<p style="color: #888; font-size: 0.9rem;">Selecione um pacote para ver análise detalhada</p>
<div class="traffic-volume">
<div class="volume-bar" id="volumeBar"></div>
<div class="volume-label">Volume de Tráfego da Rede</div>
</div>
<div class="stats-panel">
<h4 style="color: #00aaff; margin-bottom: 10px;">Estatísticas da Sessão</h4>
<div class="stats-grid">
<div class="stat-item">
<span>Total de Pacotes:</span>
<span id="statsPackets">0</span>
</div>
<div class="stat-item">
<span>Volume de Dados:</span>
<span id="statsVolume">0 KB</span>
</div>
<div class="stat-item">
<span>Pacotes TCP:</span>
<span id="statsTCP">0</span>
</div>
<div class="stat-item">
<span>Pacotes UDP:</span>
<span id="statsUDP">0</span>
</div>
<div class="stat-item">
<span>Requisições HTTP:</span>
<span id="statsHTTP">0</span>
</div>
<div class="stat-item">
<span>Consultas DNS:</span>
<span id="statsDNS">0</span>
</div>
</div>
</div>
<div class="alert-panel" id="alertPanel">
<h4 style="color: #ff4444; margin-bottom: 10px;">🚨 Alerta de Segurança</h4>
<div id="alertContent"></div>
</div>
<div class="investigation-panel" id="investigationPanel">
<h4 style="color: #00aa00; margin-bottom: 10px;">🔍 Análise de Ameaça</h4>
<div class="investigation-actions">
<button class="action-btn" onclick="analyzer.startChallenge()" style="background: #003366; border-color: #0066cc;">Iniciar Desafio</button>
</div>
<!-- Hidden investigation options - shown only during challenge -->
<div class="investigation-actions" id="hiddenInvestigationOptions" style="display: none; margin-top: 15px;">
<p style="color: #00aa00; margin-bottom: 10px;">Escolha a melhor ação para esta ameaça:</p>
<button class="action-btn" onclick="analyzer.selectAction('blockIP')">Bloquear IP</button>
<button class="action-btn" onclick="analyzer.selectAction('quarantineHost')">Quarentena Host</button>
<button class="action-btn" onclick="analyzer.selectAction('deepPacketInspection')">Inspeção Profunda</button>
<button class="action-btn" onclick="analyzer.selectAction('traceRoute')">Rastrear Rota</button>
<button class="action-btn" onclick="analyzer.selectAction('whoisLookup')">Consulta WHOIS</button>
<button class="action-btn" onclick="analyzer.selectAction('createFirewallRule')">Criar Regra</button>
<button class="action-btn" onclick="analyzer.selectAction('reportIncident')">Reportar Incidente</button>
<button class="action-btn" onclick="analyzer.selectAction('collectEvidence')">Coletar Evidências</button>
</div>
<div class="investigation-log" id="investigationLog">
<div class="log-entry log-success">📋 INSTRUÇÕES:</div>
<div class="log-entry log-success">1. Procure pacotes VERMELHOS/LARANJAS (ameaças)</div>
<div class="log-entry log-success">2. Clique no pacote suspeito</div>
<div class="log-entry log-success">3. Clique "Iniciar Desafio"</div>
<div class="log-entry log-success">4. Escolha a ação correta para resolver</div>
<div class="log-entry log-success">--- Ferramentas prontas ---</div>
</div>
</div>
</div>
<div id="hexTab" style="display: none;">
<div class="hex-view" id="hexDump">
Selecione um pacote para visualizar o dump hex
</div>
</div>
<div id="protocolsTab" style="display: none;">
<div class="protocol-tree" id="protocolTree">
Selecione um pacote para ver a análise de protocolos
</div>
</div>
<div id="timelineTab" style="display: none;">
<h3 style="color: #00aaff; margin-bottom: 15px;">Linha do Tempo da Conexão</h3>
<div class="timeline-view" id="timelineView">
Selecione um pacote para ver a linha do tempo da conexão
</div>
</div>
<div id="networkTab" style="display: none;">
<h3 style="color: #00aaff; margin-bottom: 15px;">Topologia da Rede</h3>
<div class="network-map" id="networkMap">
<!-- Network nodes will be populated here -->
</div>
</div>
</div>
</div>
</div>
<!-- Score Panel -->
<div class="score-panel">
<h3 style="color: #fff; margin-bottom: 10px;">🎯 Pontuação</h3>
<div class="score-item">
<span>Pontos:</span>
<span class="score-value" id="totalScore">0</span>
</div>
<div class="score-item">
<span>Ameaças Encontradas:</span>
<span class="score-value" id="threatsIdentified">0</span>
</div>
<div class="score-item">
<span>Ações Tomadas:</span>
<span class="score-value" id="actionsTaken">0</span>
</div>
<div class="score-item">
<span>Precisão:</span>
<span class="score-value" id="accuracy">100%</span>
</div>
</div>
<!-- Challenge Modal -->
<div class="challenge-modal" id="challengeModal">
<div class="modal-content">
<div class="modal-header" id="challengeTitle">Desafio de Segurança</div>
<div id="challengeDescription"></div>
<div class="challenge-options" id="challengeOptions"></div>
<div style="text-align: center; margin-top: 15px;">
<button class="btn" onclick="analyzer.closeChallenge()">Fechar</button>
</div>
</div>
</div>
<!-- Success Modal -->
<div class="game-over-modal success-modal" id="successModal">
<div class="game-over-content">
<div class="game-over-title">🏆 PARABÉNS! MISSÃO CUMPRIDA!</div>
<p style="color: #00ff00; font-size: 1.2rem; margin: 15px 0;">
Você demonstrou excelência em análise de segurança de redes!
</p>
<div class="game-stats" id="successStats">
<!-- Stats will be populated here -->
</div>
<p style="color: #ccc; margin: 15px 0;">
Você identificou e neutralizou ameaças com precisão profissional!
</p>
<button class="restart-btn" onclick="analyzer.restartGame()">🔄 Jogar Novamente</button>
</div>
</div>
<!-- Failure Modal -->
<div class="game-over-modal failure-modal" id="failureModal">
<div class="game-over-content">
<div class="game-over-title">💥 GAME OVER!</div>
<p style="color: #ff4444; font-size: 1.2rem; margin: 15px 0;">
A rede foi comprometida! Muitas ameaças passaram despercebidas.
</p>
<div class="game-stats" id="failureStats">
<!-- Stats will be populated here -->
</div>
<p style="color: #ccc; margin: 15px 0;">
Pratique mais para se tornar um expert em segurança de redes!
</p>
<button class="restart-btn" onclick="analyzer.restartGame()">🔄 Tentar Novamente</button>
</div>
</div>
<script>
class RealisticNetworkAnalyzer {
constructor() {
this.capturing = false;
this.packets = [];
this.selectedPacket = null;
this.packetCounter = 0;
this.currentFilter = '';
this.activeTab = 'details';
this.networkNodes = new Map();
this.connections = new Set();
this.stats = {
totalPackets: 0,
dataVolume: 0,
tcpPackets: 0,
udpPackets: 0,
httpRequests: 0,
dnsQueries: 0,
threatsDetected: 0
};
// Game mechanics
this.gameScore = {
totalScore: 0,
threatsIdentified: 0,
actionsTaken: 0,
correctActions: 0,
incorrectActions: 0
};
this.activeIncident = null;
this.blockedIPs = new Set();
this.quarantinedHosts = new Set();
this.investigationHistory = [];
this.resolvedPackets = new Set();
this.usedActions = new Map(); // Track actions used per packet
this.completedChallenges = new Set(); // Track packets that already had challenges completed
// Game rules
this.gameRules = {
maxThreats: 10, // Maximum threats to win
minCorrectRate: 70, // Minimum 70% correct rate to win
maxIncorrect: 3 // Game over after 3 wrong answers
};
this.gameActive = true;
// Make analyzer globally accessible for onclick handlers
window.analyzer = this;
this.init();
// Don't start automatically - wait for user to click Start
}
init() {
this.setupEventListeners();
this.updateStats();
this.generateInitialNetworkTopology();
}
setupEventListeners() {
document.getElementById('startCapture').addEventListener('click', () => this.startRealtimeCapture());
document.getElementById('stopCapture').addEventListener('click', () => this.stopCapture());
document.getElementById('clearCapture').addEventListener('click', () => this.clearCapture());
document.getElementById('applyFilter').addEventListener('click', () => this.applyFilter());
document.getElementById('exportPcap').addEventListener('click', () => this.exportPcap());
// Tab switching
document.querySelectorAll('.tab').forEach(tab => {
tab.addEventListener('click', (e) => {
this.switchTab(e.target.dataset.tab);
});
});
// Filter on Enter key
document.getElementById('filterInput').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
this.applyFilter();
}
});
}
startCapture() {
this.capturing = true;
document.getElementById('startCapture').classList.add('active');
document.getElementById('stopCapture').classList.remove('active');
// Update status indicator
const statusItem = document.querySelector('.status-item');
const indicator = statusItem.querySelector('.real-time-indicator');
statusItem.classList.add('active');
statusItem.innerHTML = '<span class="real-time-indicator"></span>CAPTURANDO';
// Simulate real-time packet capture
this.captureInterval = setInterval(() => {
if (this.capturing) {
this.generateRealisticPacket();
}
}, Math.random() * 800 + 200); // Random interval between 200ms to 1000ms (slower, more readable)
}
stopCapture() {
this.capturing = false;
document.getElementById('startCapture').classList.remove('active');
document.getElementById('stopCapture').classList.add('active');
// Update status indicator
const statusItem = document.querySelector('.status-item');
statusItem.classList.remove('active');
statusItem.innerHTML = '<span class="real-time-indicator" style="background: #666;"></span>PAUSADO';
if (this.captureInterval) {
clearInterval(this.captureInterval);
}
}
clearCapture() {
this.packets = [];
this.packetCounter = 0;
this.selectedPacket = null;
this.networkNodes.clear();
this.connections.clear();
this.resolvedPackets.clear();
this.usedActions.clear();
this.completedChallenges.clear();
this.stats = {
totalPackets: 0,
dataVolume: 0,
tcpPackets: 0,
udpPackets: 0,
httpRequests: 0,
dnsQueries: 0,
threatsDetected: 0
};
document.getElementById('packetList').innerHTML = '';
this.updateStats();
this.generateInitialNetworkTopology();
this.clearAnalysis();
}
generateRealisticPacket() {
if (!this.gameActive) return; // Stop generating packets when game ends
const now = new Date();
const packetTypes = [
this.createTCPPacket,
this.createHTTPPacket,
this.createHTTPSPacket,
this.createDNSPacket,
this.createUDPPacket,
this.createICMPPacket,
this.createARPPacket,
// Malicious packets (less frequent)
...(Math.random() < 0.1 ? [this.createMaliciousPacket] : [])
];
const packetGenerator = packetTypes[Math.floor(Math.random() * packetTypes.length)];
const packet = packetGenerator.call(this, now);
this.addPacket(packet);
}
createTCPPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = Math.random() > 0.7 ? this.getRandomExternalIP() : this.getRandomInternalIP();
const srcPort = Math.floor(Math.random() * 65535) + 1024;
const dstPort = [80, 443, 22, 21, 25, 53, 110, 143, 993, 995][Math.floor(Math.random() * 10)];
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'TCP',
length: Math.floor(Math.random() * 1460) + 60,
info: `${srcPort} → ${dstPort} [${this.getTCPFlags()}] Seq=${Math.floor(Math.random() * 4294967295)} Ack=${Math.floor(Math.random() * 4294967295)}`,
rawData: this.generateRawData('TCP', srcIP, dstIP, srcPort, dstPort),
isThreat: false,
category: 'normal'
};
}
createHTTPPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = this.getRandomExternalIP();
const methods = ['GET', 'POST', 'PUT', 'DELETE', 'HEAD'];
const method = methods[Math.floor(Math.random() * methods.length)];
const paths = ['/', '/api/users', '/login', '/images/logo.png', '/css/style.css', '/js/app.js'];
const path = paths[Math.floor(Math.random() * paths.length)];
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'HTTP',
length: Math.floor(Math.random() * 2000) + 200,
info: `${method} ${path} HTTP/1.1`,
rawData: this.generateHTTPRawData(method, path, srcIP, dstIP),
isThreat: false,
category: 'normal'
};
}
createHTTPSPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = this.getRandomExternalIP();
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'TLSv1.2',
length: Math.floor(Math.random() * 1400) + 100,
info: `Application Data`,
rawData: this.generateTLSRawData(srcIP, dstIP),
isThreat: false,
category: 'normal'
};
}
createDNSPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = Math.random() > 0.5 ? '8.8.8.8' : '1.1.1.1';
const domains = ['google.com', 'facebook.com', 'microsoft.com', 'github.com', 'stackoverflow.com', 'amazon.com'];
const domain = domains[Math.floor(Math.random() * domains.length)];
const queryType = Math.random() > 0.8 ? 'AAAA' : 'A';
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'DNS',
length: Math.floor(Math.random() * 200) + 50,
info: `Standard query 0x${Math.floor(Math.random() * 65535).toString(16)} ${queryType} ${domain}`,
rawData: this.generateDNSRawData(domain, queryType, srcIP, dstIP),
isThreat: false,
category: 'normal'
};
}
createUDPPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = this.getRandomInternalIP();
const srcPort = Math.floor(Math.random() * 65535) + 1024;
const dstPort = Math.floor(Math.random() * 65535) + 1024;
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'UDP',
length: Math.floor(Math.random() * 500) + 50,
info: `Source port: ${srcPort} Destination port: ${dstPort}`,
rawData: this.generateRawData('UDP', srcIP, dstIP, srcPort, dstPort),
isThreat: false,
category: 'normal'
};
}
createICMPPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = this.getRandomExternalIP();
const types = ['Echo (ping) request', 'Echo (ping) reply', 'Destination unreachable'];
const type = types[Math.floor(Math.random() * types.length)];
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'ICMP',
length: Math.floor(Math.random() * 100) + 28,
info: type,
rawData: this.generateICMPRawData(type, srcIP, dstIP),
isThreat: false,
category: 'normal'
};
}
createARPPacket(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = this.getRandomInternalIP();
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'ARP',
length: 42,
info: `Who has ${dstIP}? Tell ${srcIP}`,
rawData: this.generateARPRawData(srcIP, dstIP),
isThreat: false,
category: 'normal'
};
}
createMaliciousPacket(timestamp) {
const threats = [
this.createPortScanPacket,
this.createSQLInjectionPacket,
this.createDDoSPacket,
this.createMalwareC2Packet,
this.createBruteForcePacket
];
const threatGenerator = threats[Math.floor(Math.random() * threats.length)];
return threatGenerator.call(this, timestamp);
}
createPortScanPacket(timestamp) {
const srcIP = this.getRandomExternalIP();
const dstIP = this.getRandomInternalIP();
const dstPort = Math.floor(Math.random() * 65535);
this.stats.threatsDetected++;
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'TCP',
length: 60,
info: `${Math.floor(Math.random() * 65535)} → ${dstPort} [SYN] Seq=${Math.floor(Math.random() * 4294967295)}`,
rawData: this.generateRawData('TCP', srcIP, dstIP, Math.floor(Math.random() * 65535), dstPort),
isThreat: true,
category: 'malicious',
threatType: 'Port Scan',
indicators: ['Sequential port targeting', 'External source', 'SYN scan pattern']
};
}
createSQLInjectionPacket(timestamp) {
const srcIP = this.getRandomExternalIP();
const dstIP = this.getRandomInternalIP();
const payload = "GET /login.php?user=admin' OR '1'='1' --&pass=test HTTP/1.1";
this.stats.threatsDetected++;
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'HTTP',
length: payload.length + 200,
info: payload.substring(0, 60) + '...',
rawData: this.generateSQLInjectionRawData(payload, srcIP, dstIP),
isThreat: true,
category: 'malicious',
threatType: 'SQL Injection',
indicators: ['SQL metacharacters', 'OR condition injection', 'Comment injection']
};
}
createDDoSPacket(timestamp) {
const srcIP = this.getRandomExternalIP();
const dstIP = this.getRandomInternalIP();
this.stats.threatsDetected++;
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'TCP',
length: Math.floor(Math.random() * 100) + 60,
info: `${Math.floor(Math.random() * 65535)} → 80 [SYN] Seq=${Math.floor(Math.random() * 4294967295)}`,
rawData: this.generateRawData('TCP', srcIP, dstIP, Math.floor(Math.random() * 65535), 80),
isThreat: true,
category: 'malicious',
threatType: 'DDoS Attack',
indicators: ['High connection rate', 'Multiple sources', 'SYN flood pattern']
};
}
createMalwareC2Packet(timestamp) {
const srcIP = this.getRandomInternalIP();
const dstIP = this.getRandomExternalIP();
const suspiciousDomains = ['malware-c2.darknet.com', 'command-server.onion.to', 'bot.suspicious-domain.tk'];
const domain = suspiciousDomains[Math.floor(Math.random() * suspiciousDomains.length)];
this.stats.threatsDetected++;
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'HTTPS',
length: Math.floor(Math.random() * 500) + 200,
info: `TLS Application Data`,
rawData: this.generateMalwareC2RawData(domain, srcIP, dstIP),
isThreat: true,
category: 'malicious',
threatType: 'Malware C2',
indicators: ['Suspicious domain', 'Encrypted C2 communication', 'Periodic beaconing']
};
}
createBruteForcePacket(timestamp) {
const srcIP = this.getRandomExternalIP();
const dstIP = this.getRandomInternalIP();
this.stats.threatsDetected++;
return {
id: ++this.packetCounter,
timestamp: timestamp,
time: this.formatTime(timestamp),
src: srcIP,
dst: dstIP,
protocol: 'SSH',
length: Math.floor(Math.random() * 200) + 100,
info: `SSH login attempt - user: admin (failed)`,
rawData: this.generateBruteForceRawData(srcIP, dstIP),
isThreat: true,
category: 'malicious',
threatType: 'Brute Force Attack',
indicators: ['Multiple failed logins', 'Dictionary attack pattern', 'External source']
};
}
addPacket(packet) {
if (!packet || typeof packet !== 'object') {
console.error('Invalid packet data:', packet);
return;
}
try {
this.packets.push(packet);
this.updateStats();
if (this.matchesFilter(packet)) {
this.displayPacket(packet);
}
this.updateNetworkTopology(packet);
this.updateTrafficVolume();
if (packet.isThreat) {
this.showThreatAlert(packet);
}
// Auto-scroll to latest packet
const packetList = document.getElementById('packetList');
if (packetList) {
packetList.scrollTop = packetList.scrollHeight;
}
} catch (error) {
console.error('Error adding packet:', error, packet);
}
}
displayPacket(packet) {
const packetList = document.getElementById('packetList');
const row = document.createElement('div');
row.className = `packet-row ${packet.category}`;
row.dataset.packetId = packet.id;
const threatIndicator = packet.isThreat ? '🚨 ' : '';
row.innerHTML = `
<div>${packet.id}</div>
<div>${packet.time}</div>
<div>${packet.src}</div>
<div>${packet.dst}</div>
<div>${packet.protocol}</div>
<div>${packet.length}</div>
<div>${threatIndicator}${packet.info}</div>
`;
row.addEventListener('click', () => this.selectPacket(packet));
packetList.appendChild(row);
// Keep only last 1000 packets in view for performance
if (packetList.children.length > 1000) {
packetList.removeChild(packetList.firstChild);
}
}
selectPacket(packet) {
// Remove previous selection
document.querySelectorAll('.packet-row').forEach(row => {
row.classList.remove('selected');
});
// Add selection to clicked packet
const selectedRow = document.querySelector(`[data-packet-id="${packet.id}"]`);
if (selectedRow) {
selectedRow.classList.add('selected');
}
this.selectedPacket = packet;
this.updateAnalysis();
// Show investigation panel if this is a threat packet
if (packet.isThreat) {
this.activeIncident = packet;
document.getElementById('investigationPanel').classList.add('show');
}
}
updateAnalysis() {
if (!this.selectedPacket) return;
const packet = this.selectedPacket;
this.updateDetailsTab(packet);
this.updateHexTab(packet);
this.updateProtocolsTab(packet);
this.updateTimelineTab(packet);
this.updateNetworkTab(packet);
}
updateDetailsTab(packet) {
// This is handled by the general analysis display
}
updateHexTab(packet) {
const hexDump = document.getElementById('hexDump');
hexDump.textContent = packet.rawData;
}
updateProtocolsTab(packet) {
const protocolTree = document.getElementById('protocolTree');
let protocolHTML = '';
// Generate protocol stack based on packet type
if (packet.protocol === 'TCP' || packet.protocol === 'HTTP' || packet.protocol === 'HTTPS') {
protocolHTML = `
<div class="protocol-layer expandable expanded">
<div class="protocol-header">▼ Ethernet II</div>
<div class="protocol-details">
Destination: ${this.generateMAC()}<br>
Source: ${this.generateMAC()}<br>
Tipo: IPv4 (0x0800)
</div>
</div>
<div class="protocol-layer expandable expanded">
<div class="protocol-header">▼ Internet Protocol Version 4</div>
<div class="protocol-details">
Version: 4<br>
Header Length: 20 bytes<br>
Total Length: ${packet.length}<br>
Identification: 0x${Math.floor(Math.random() * 65536).toString(16).padStart(4, '0')}<br>
Flags: 0x4000 (Don't Fragment)<br>
Time to Live: ${Math.floor(Math.random() * 64) + 64}<br>
Protocol: ${packet.protocol === 'TCP' ? 'TCP (6)' : 'UDP (17)'}<br>
Source: ${packet.src}<br>
Destination: ${packet.dst}
</div>
</div>
`;
if (packet.protocol === 'TCP' || packet.protocol === 'HTTP') {
protocolHTML += `
<div class="protocol-layer expandable expanded">
<div class="protocol-header">▼ Transmission Control Protocol</div>
<div class="protocol-details">
Source Port: ${Math.floor(Math.random() * 65535)}<br>
Destination Port: ${packet.info.includes('80') ? '80' : '443'}<br>
Sequence Number: ${Math.floor(Math.random() * 4294967295)}<br>
Acknowledgment Number: ${Math.floor(Math.random() * 4294967295)}<br>
Window Size: ${Math.floor(Math.random() * 65536)}<br>
Flags: ${this.getTCPFlags()}
</div>
</div>
`;
}
if (packet.protocol === 'HTTP') {
protocolHTML += `
<div class="protocol-layer expandable expanded">
<div class="protocol-header">▼ Hypertext Transfer Protocol</div>
<div class="protocol-details">
${packet.info}<br>
Host: example.com<br>
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64)<br>
Accept: text/html,application/xhtml+xml
</div>
</div>
`;
}
}
protocolTree.innerHTML = protocolHTML;
// Add click handlers for expandable sections
document.querySelectorAll('.protocol-layer.expandable').forEach(layer => {
layer.addEventListener('click', (e) => {
if (e.target.classList.contains('protocol-header')) {
layer.classList.toggle('expanded');
const details = layer.querySelector('.protocol-details');
details.style.display = layer.classList.contains('expanded') ? 'block' : 'none';
e.target.textContent = layer.classList.contains('expanded') ?
e.target.textContent.replace('▶', '▼') :
e.target.textContent.replace('▼', '▶');
}
});
});
}
updateTimelineTab(packet) {
const timelineView = document.getElementById('timelineView');
const baseTime = new Date(packet.timestamp);
let timelineHTML = '';
// Generate connection timeline
for (let i = -2; i <= 2; i++) {
const eventTime = new Date(baseTime.getTime() + (i * 1000));
const eventType = i === 0 ? 'Current Packet' :
i < 0 ? 'Previous Activity' : 'Subsequent Activity';
timelineHTML += `
<div class="timeline-entry">
<div class="timeline-time">${this.formatTime(eventTime)}</div>
<div class="timeline-event">${eventType} - ${packet.protocol} ${packet.src} → ${packet.dst}</div>
</div>
`;
}
timelineView.innerHTML = timelineHTML;
}
updateNetworkTab(packet) {
// Network tab is updated via updateNetworkTopology
}
updateStats() {
this.stats.totalPackets = this.packets.length;
this.stats.dataVolume = this.packets.reduce((total, p) => total + (p.length || 0), 0);
this.stats.tcpPackets = this.packets.filter(p => p.protocol === 'TCP').length;
this.stats.udpPackets = this.packets.filter(p => p.protocol === 'UDP').length;
this.stats.httpRequests = this.packets.filter(p => p.protocol === 'HTTP').length;
this.stats.dnsQueries = this.packets.filter(p => p.protocol === 'DNS').length;
// Safely update DOM elements
const totalPacketsEl = document.getElementById('totalPackets');
const packetRateEl = document.getElementById('packetRate');
const threatsFoundEl = document.getElementById('threatsFound');
if (totalPacketsEl) totalPacketsEl.textContent = this.stats.totalPackets;
if (packetRateEl) {
// Calculate packet rate (packets in last 10 seconds)
const now = Date.now();
const recentPackets = this.packets.filter(p => now - (p.timestamp || 0) < 10000);
const packetRate = Math.floor(recentPackets.length / 10);
packetRateEl.textContent = packetRate;
}
if (threatsFoundEl) threatsFoundEl.textContent = this.stats.threatsDetected;
// Update detailed stats
const statsElements = {
'statsPackets': this.stats.totalPackets,
'statsVolume': Math.round(this.stats.dataVolume / 1024) + ' KB',
'statsTCP': this.stats.tcpPackets,
'statsUDP': this.stats.udpPackets,
'statsHTTP': this.stats.httpRequests,
'statsDNS': this.stats.dnsQueries
};
Object.entries(statsElements).forEach(([id, value]) => {
const element = document.getElementById(id);
if (element) element.textContent = value;
});
}
updateTrafficVolume() {
const volumeBar = document.getElementById('volumeBar');
if (!volumeBar) return;
const now = Date.now();
const recentPackets = this.packets.filter(p => now - (p.timestamp || 0) < 10000).length;
const maxWidth = Math.min(100, (recentPackets / 50) * 100);
volumeBar.style.width = maxWidth + '%';
}
showThreatAlert(packet) {
const alertPanel = document.getElementById('alertPanel');
const alertContent = document.getElementById('alertContent');
const investigationPanel = document.getElementById('investigationPanel');
alertContent.innerHTML = `
<strong>${packet.threatType}</strong><br>
Source: ${packet.src} → Destination: ${packet.dst}<br>
<strong>Indicators:</strong><br>
${packet.indicators.map(i => `• ${i}`).join('<br>')}
`;
alertPanel.classList.add('show');
// Set active incident for investigation (but don't show panel automatically)
this.activeIncident = packet;
// Keep alert visible longer (15 seconds)
setTimeout(() => {
alertPanel.classList.remove('show');
}, 15000);
}
updateNetworkTopology(packet) {
const networkMap = document.getElementById('networkMap');
// Add nodes for source and destination
if (!this.networkNodes.has(packet.src)) {
this.addNetworkNode(packet.src, packet.category);
}
if (!this.networkNodes.has(packet.dst)) {
this.addNetworkNode(packet.dst, packet.category);
}
// Add connection
const connectionKey = `${packet.src}-${packet.dst}`;
this.connections.add(connectionKey);
// Update node colors based on threat level
if (packet.isThreat) {
const srcNode = networkMap.querySelector(`[data-ip="${packet.src}"]`);
const dstNode = networkMap.querySelector(`[data-ip="${packet.dst}"]`);
if (srcNode && !srcNode.classList.contains('malicious')) {
srcNode.classList.add('suspicious');
}
if (dstNode && !dstNode.classList.contains('malicious')) {
dstNode.classList.add('suspicious');
}
}
}
addNetworkNode(ip, category) {
const networkMap = document.getElementById('networkMap');
const node = document.createElement('div');
node.className = `network-node ${category}`;
node.dataset.ip = ip;
node.textContent = ip.split('.')[3]; // Show last octet
node.title = ip;
// Position randomly within the map
const mapWidth = networkMap.offsetWidth || 300;
const mapHeight = networkMap.offsetHeight || 200;
const x = Math.random() * Math.max(50, mapWidth - 50);
const y = Math.random() * Math.max(50, mapHeight - 50);
node.style.left = x + 'px';
node.style.top = y + 'px';
networkMap.appendChild(node);
this.networkNodes.set(ip, { element: node, x, y });
}
generateInitialNetworkTopology() {
const networkMap = document.getElementById('networkMap');
networkMap.innerHTML = '';
// Add some initial network nodes
const initialIPs = ['192.168.1.1', '192.168.1.100', '10.0.0.1', '172.16.0.1'];
initialIPs.forEach(ip => {
this.addNetworkNode(ip, 'normal');
});
}
applyFilter() {
const filter = document.getElementById('filterInput').value.toLowerCase();
this.currentFilter = filter;
// Clear current display
document.getElementById('packetList').innerHTML = '';
// Re-display filtered packets
this.packets.forEach(packet => {
if (this.matchesFilter(packet)) {
this.displayPacket(packet);
}
});
}
matchesFilter(packet) {
if (!this.currentFilter) return true;
const filter = this.currentFilter.toLowerCase();
// Simple filter matching
return packet.protocol.toLowerCase().includes(filter) ||
packet.src.includes(filter) ||
packet.dst.includes(filter) ||
packet.info.toLowerCase().includes(filter);
}
switchTab(tabName) {
// Update tab buttons
document.querySelectorAll('.tab').forEach(tab => {
tab.classList.remove('active');
});
document.querySelector(`[data-tab="${tabName}"]`).classList.add('active');
// Update tab content
document.querySelectorAll('#analysisContent > div').forEach(content => {
content.style.display = 'none';
});
document.getElementById(`${tabName}Tab`).style.display = 'block';
this.activeTab = tabName;
if (this.selectedPacket) {
this.updateAnalysis();
}
}
exportPcap() {
// Simulate PCAP export
const data = this.packets.map(p => ({
timestamp: p.timestamp,
src: p.src,
dst: p.dst,
protocol: p.protocol,
length: p.length,
data: p.rawData
}));
const blob = new Blob([JSON.stringify(data, null, 2)], {
type: 'application/json'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `network_capture_${Date.now()}.json`;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
URL.revokeObjectURL(url);
}
clearAnalysis() {
document.getElementById('hexDump').textContent = 'Selecione um pacote para visualizar o dump hex';
document.getElementById('protocolTree').textContent = 'Selecione um pacote para ver a análise de protocolos';
document.getElementById('timelineView').innerHTML = 'Selecione um pacote para ver a linha do tempo da conexão';
document.getElementById('alertPanel').classList.remove('show');
}
// Utility methods
formatTime(date) {
const timeString = date.toLocaleTimeString('pt-BR', { hour12: false });
const milliseconds = date.getMilliseconds().toString().padStart(3, '0');
const microseconds = Math.floor(Math.random() * 1000).toString().padStart(3, '0');
return `${timeString}.${milliseconds}${microseconds}`;
}
getRandomInternalIP() {
const subnets = ['192.168.1', '192.168.0', '10.0.0', '172.16.0'];
const subnet = subnets[Math.floor(Math.random() * subnets.length)];
return `${subnet}.${Math.floor(Math.random() * 254) + 1}`;
}
getRandomExternalIP() {
return `${Math.floor(Math.random() * 223) + 1}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 255)}.${Math.floor(Math.random() * 254) + 1}`;
}
getTCPFlags() {
const flags = ['SYN', 'ACK', 'FIN', 'RST', 'PSH', 'URG'];
const activeFlags = flags.filter(() => Math.random() > 0.7);
return activeFlags.length > 0 ? activeFlags.join(', ') : 'ACK';
}
generateMAC() {
return Array.from({length: 6}, () =>
Math.floor(Math.random() * 256).toString(16).padStart(2, '0')
).join(':');
}
generateRawData(protocol, srcIP, dstIP, srcPort, dstPort) {
// Generate realistic hex dump
let hex = '';
const lines = 16;
for (let i = 0; i < lines; i++) {
const offset = (i * 16).toString(16).padStart(8, '0').toUpperCase();
let hexLine = '';
let asciiLine = '';
for (let j = 0; j < 16; j++) {
const byte = Math.floor(Math.random() * 256);
hexLine += byte.toString(16).padStart(2, '0').toUpperCase() + ' ';
asciiLine += (byte >= 32 && byte <= 126) ? String.fromCharCode(byte) : '.';
}
hex += `${offset}: ${hexLine} |${asciiLine}|\n`;
}
return hex;
}
generateHTTPRawData(method, path, srcIP, dstIP) {
return `0000: 45 00 00 3c 1c 46 40 00 40 06 b1 e6 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: 80 50 1f 90 d6 7c 90 e4 a8 c0 90 5c 80 18 00 e5
0020: ${method} ${path} HTTP/1.1\\r\\n
0030: Host: example.com\\r\\n
0040: User-Agent: Mozilla/5.0\\r\\n
0050: Accept: text/html,application/xhtml+xml\\r\\n
0060: \\r\\n`;
}
generateTLSRawData(srcIP, dstIP) {
return `0000: 16 03 01 00 40 01 00 00 3c 03 03 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: [Encrypted TLS Application Data]
0020: ${Math.random().toString(16).substring(2, 10)} ${Math.random().toString(16).substring(2, 10)}
0030: [Certificate verification data]
0040: [Encrypted payload continues...]`;
}
generateDNSRawData(domain, queryType, srcIP, dstIP) {
return `0000: 45 00 00 3c 1c 46 40 00 40 11 b1 e6 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: 00 35 d6 7c 00 28 fe 7c ab cd 01 00 00 01 00 00
0020: 00 00 00 00 ${this.stringToHex(domain)} 00 00 01 00 01
0030: [DNS Query: ${domain} Type ${queryType}]`;
}
generateICMPRawData(type, srcIP, dstIP) {
return `0000: 45 00 00 3c 1c 46 40 00 40 01 b1 e6 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: 08 00 f7 fc 00 00 00 00 61 62 63 64 65 66 67 68
0020: 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 61
0030: [ICMP ${type}]`;
}
generateARPRawData(srcIP, dstIP) {
return `0000: ff ff ff ff ff ff ${this.generateMAC()} 08 06 00 01
0010: 08 00 06 04 00 01 ${this.generateMAC()} ${this.ipToHex(srcIP)}
0020: 00 00 00 00 00 00 ${this.ipToHex(dstIP)}
0030: [ARP Request: Who has ${dstIP}?]`;
}
generateSQLInjectionRawData(payload, srcIP, dstIP) {
return `0000: 45 00 00 3c 1c 46 40 00 40 06 b1 e6 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: ${payload.substring(0, 32)}
0020: [SQL Injection payload detected]
0030: ' OR '1'='1' --
0040: [Malicious SQL metacharacters found]`;
}
generateMalwareC2RawData(domain, srcIP, dstIP) {
return `0000: 16 03 01 00 40 01 00 00 3c 03 03 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: [Encrypted C2 Communication to ${domain}]
0020: [Suspicious TLS handshake patterns]
0030: [Potential botnet traffic]
0040: [Encrypted command payload]`;
}
generateBruteForceRawData(srcIP, dstIP) {
return `0000: 45 00 00 3c 1c 46 40 00 40 06 b1 e6 ${this.ipToHex(srcIP)} ${this.ipToHex(dstIP)}
0010: SSH-2.0-OpenSSH_7.4\\r\\n
0020: [Authentication attempt]
0030: username: admin
0040: [Failed login attempt detected]`;
}
ipToHex(ip) {
return ip.split('.').map(octet =>
parseInt(octet).toString(16).padStart(2, '0')
).join(' ');
}
stringToHex(str) {
return str.split('').map(char =>
char.charCodeAt(0).toString(16).padStart(2, '0')
).join(' ');
}
startRealtimeCapture() {
// This method is now only called when user clicks Start button
this.startCapture();
}
// Validation helper for investigation tools
validateThreatSelected(toolName, actionKey = null) {
if (!this.activeIncident) {
this.addInvestigationLog(`❌ Nenhum pacote selecionado para ${toolName}. Clique em um pacote primeiro.`, 'error');
return false;
}
if (!this.activeIncident.isThreat || !this.activeIncident.threatType) {
this.addInvestigationLog(`⚠️ Este é um pacote normal. Para usar ${toolName}, selecione um pacote VERMELHO/LARANJA (ameaça).`, 'warning');
return false;
}
// Check if action was already used on this packet
if (actionKey && this.usedActions.has(actionKey)) {
this.addInvestigationLog(`⚠️ Você já usou "${toolName}" neste pacote!`, 'warning');
return false;
}
return true;
}
// Investigation Tools
blockIP() {
const packetId = this.activeIncident?.id;
const actionKey = `${packetId}-blockIP`;
if (!this.validateThreatSelected('Bloquear IP', actionKey)) {
return;
}
const ip = this.activeIncident.src;
const threatType = this.activeIncident.threatType;
if (this.blockedIPs.has(ip)) {
this.addInvestigationLog(`IP ${ip} já está bloqueado`, 'warning');
return;
}
this.blockedIPs.add(ip);
this.usedActions.set(actionKey, true);
this.gameScore.actionsTaken++;
// Check if this was the correct action
const isCorrect = threatType === 'Port Scan' ||
threatType === 'DDoS Attack' ||
threatType === 'Brute Force Attack';
if (isCorrect) {
this.gameScore.correctActions++;
this.gameScore.totalScore += 50;
this.addInvestigationLog(`✓ IP ${ip} bloqueado com sucesso`, 'success');
this.addInvestigationLog(`🎯 Ação correta para ${threatType}! +50 pontos`, 'success');
} else {
this.gameScore.incorrectActions++;
this.gameScore.totalScore -= 10;
this.addInvestigationLog(`⚠ IP ${ip} bloqueado (pode não ser ideal para ${threatType})`, 'warning');
this.addInvestigationLog(`📝 Para ${threatType}, considere outras ações. -10 pontos`, 'warning');
}
this.updateScoreDisplay();
}
quarantineHost() {
const packetId = this.activeIncident?.id;
const actionKey = `${packetId}-quarantine`;
if (!this.validateThreatSelected('Quarentena Host', actionKey)) {
return;
}
const host = this.activeIncident.dst;
const threatType = this.activeIncident.threatType;
if (this.quarantinedHosts.has(host)) {
this.addInvestigationLog(`Host ${host} já está em quarentena`, 'warning');
return;
}
this.quarantinedHosts.add(host);
this.usedActions.set(actionKey, true);
this.gameScore.actionsTaken++;
const isCorrect = threatType === 'Malware C2' ||
threatType === 'SQL Injection';
if (isCorrect) {
this.gameScore.correctActions++;
this.gameScore.totalScore += 75;
this.addInvestigationLog(`✓ Host ${host} colocado em quarentena com sucesso`, 'success');
this.addInvestigationLog(`🎯 Excelente resposta para ${threatType}! +75 pontos`, 'success');
} else {
this.gameScore.incorrectActions++;
this.gameScore.totalScore -= 15;
this.addInvestigationLog(`⚠ Host ${host} em quarentena (pode ser excessivo para ${threatType})`, 'warning');
this.addInvestigationLog(`📝 Para ${threatType}, quarentena pode ser desnecessária. -15 pontos`, 'warning');
}
this.updateScoreDisplay();
}
deepPacketInspection() {
if (!this.activeIncident) {
this.addInvestigationLog('❌ Nenhum pacote selecionado. Clique em um pacote primeiro.', 'error');
return;
}
if (!this.activeIncident.isThreat) {
this.addInvestigationLog('⚠️ Este é um pacote normal. Selecione um pacote VERMELHO/LARANJA (ameaça).', 'warning');
return;
}
this.gameScore.actionsTaken++;
this.gameScore.correctActions++; // Always correct to investigate
this.gameScore.totalScore += 25;
const findings = this.generateInspectionFindings(this.activeIncident);
this.addInvestigationLog(`🔍 Inspeção profunda concluída:`, 'success');
findings.forEach(finding => {
this.addInvestigationLog(` • ${finding}`, 'success');
});
this.updateScoreDisplay();
}
traceRoute() {
if (!this.validateThreatSelected('Rastrear Rota')) {
return;
}
this.gameScore.actionsTaken++;
this.gameScore.correctActions++;
this.gameScore.totalScore += 20;
const route = this.generateTraceRoute(this.activeIncident.src);
this.addInvestigationLog(`📍 Rastreamento de rota para ${this.activeIncident.src}:`, 'success');
route.forEach((hop, index) => {
this.addInvestigationLog(` ${index + 1}. ${hop}`, 'success');
});
this.updateScoreDisplay();
}
whoisLookup() {
if (!this.validateThreatSelected('Consulta WHOIS')) {
return;
}
this.gameScore.actionsTaken++;
this.gameScore.correctActions++;
this.gameScore.totalScore += 30;
const whoisData = this.generateWhoisData(this.activeIncident.src);
this.addInvestigationLog(`🌐 Consulta WHOIS para ${this.activeIncident.src}:`, 'success');
Object.entries(whoisData).forEach(([key, value]) => {
this.addInvestigationLog(` ${key}: ${value}`, 'success');
});
this.updateScoreDisplay();
}
createFirewallRule() {
if (!this.validateThreatSelected('Criar Regra')) {
return;
}
this.gameScore.actionsTaken++;
this.gameScore.correctActions++;
this.gameScore.totalScore += 40;
const rule = this.generateFirewallRule(this.activeIncident);
this.addInvestigationLog(`🛡️ Regra de firewall criada:`, 'success');
this.addInvestigationLog(` ${rule}`, 'success');
this.updateScoreDisplay();
}
reportIncident() {
if (!this.validateThreatSelected('Reportar Incidente')) {
return;
}
this.gameScore.actionsTaken++;
this.gameScore.correctActions++;
this.gameScore.totalScore += 35;
const reportId = `INC-${Date.now().toString().slice(-6)}`;
this.addInvestigationLog(`📋 Incidente de segurança reportado (ID: ${reportId})`, 'success');
this.addInvestigationLog(` Tipo: ${this.activeIncident.threatType}`, 'success');
this.addInvestigationLog(` Severidade: ALTA`, 'success');
this.updateScoreDisplay();
}
collectEvidence() {
if (!this.validateThreatSelected('Coletar Evidências')) {
return;
}
this.gameScore.actionsTaken++;
this.gameScore.correctActions++;
this.gameScore.totalScore += 60;
this.addInvestigationLog(`📦 Evidências coletadas:`, 'success');
this.addInvestigationLog(` • Captura de pacotes salva`, 'success');
this.addInvestigationLog(` • Logs de rede arquivados`, 'success');
this.addInvestigationLog(` • Linha do tempo documentada`, 'success');
this.addInvestigationLog(` • Hash forense calculado`, 'success');
this.updateScoreDisplay();
}
presentSecurityChallenge(packet) {
const challenges = this.getChallenges(packet.threatType);
const challenge = challenges[Math.floor(Math.random() * challenges.length)];
document.getElementById('challengeTitle').textContent = `${packet.threatType} - Security Challenge`;
document.getElementById('challengeDescription').innerHTML = `
<p style="color: #ccc; margin-bottom: 15px;">${challenge.question}</p>
<div style="background: #0a0a0a; padding: 10px; border: 1px solid #333; margin: 10px 0; font-family: monospace; font-size: 0.8rem;">
${challenge.evidence}
</div>
`;
const optionsContainer = document.getElementById('challengeOptions');
optionsContainer.innerHTML = '';
challenge.options.forEach((option, index) => {
const btn = document.createElement('button');
btn.className = 'option-btn';
btn.textContent = option.text;
btn.onclick = () => this.selectChallengeOption(index, option.correct, challenge);
optionsContainer.appendChild(btn);
});
document.getElementById('challengeModal').style.display = 'flex';
}
selectChallengeOption(selectedIndex, isCorrect, challenge) {
const options = document.querySelectorAll('.option-btn');
options[selectedIndex].classList.add(isCorrect ? 'correct' : 'incorrect');
if (isCorrect) {
this.gameScore.totalScore += 100;
this.gameScore.threatsIdentified++;
this.addInvestigationLog(`✓ Correto! ${challenge.explanation}`, 'success');
this.addInvestigationLog(`🎉 PARABÉNS! Ameaça ${this.activeIncident.threatType} resolvida!`, 'success');
this.addInvestigationLog(`🔵 Pacote marcado como RESOLVIDO (azul)`, 'success');
// Mark the packet as resolved
this.resolvedPackets.add(this.activeIncident.id);
this.updatePacketColor(this.activeIncident.id, 'resolved');
} else {
this.gameScore.totalScore -= 25;
// Show correct answer
challenge.options.forEach((option, index) => {
if (option.correct) {
options[index].classList.add('correct');
}
});
this.addInvestigationLog(`✗ Incorreto. ${challenge.explanation}`, 'error');
}
this.updateScoreDisplay();
// Disable all options
options.forEach(btn => btn.disabled = true);
// Auto-close after 4 seconds (more time to read the success message)
setTimeout(() => {
this.closeChallenge();
}, 4000);
}
closeChallenge() {
document.getElementById('challengeModal').style.display = 'none';
this.activeIncident = null;
document.getElementById('investigationPanel').classList.remove('show');
}
updatePacketColor(packetId, newClass) {
const packetRow = document.querySelector(`[data-packet-id="${packetId}"]`);
if (packetRow) {
// Remove old threat classes
packetRow.classList.remove('suspicious', 'malicious');
// Add new class
packetRow.classList.add(newClass);
}
}
getChallenges(threatType) {
const challengeBank = {
'Port Scan': [
{
question: 'Qual é a intenção mais provável desta atividade de port scan?',
evidence: 'Múltiplos pacotes SYN para portas sequenciais: 21, 22, 23, 25, 53, 80, 110, 143, 443',
options: [
{ text: 'Diagnósticos normais de rede', correct: false },
{ text: 'Reconhecimento para serviços vulneráveis', correct: true },
{ text: 'Teste de balanceamento de carga', correct: false },
{ text: 'Problema de resolução DNS', correct: false }
],
explanation: 'Port scanning sequencial indica reconhecimento para identificar serviços abertos e potenciais vetores de ataque.'
}
],
'SQL Injection': [
{
question: 'Qual parte desta requisição contém o payload de SQL injection?',
evidence: "GET /login.php?user=admin' OR '1'='1' --&pass=test HTTP/1.1",
options: [
{ text: 'O método HTTP', correct: false },
{ text: "O parâmetro user com ' OR '1'='1' --", correct: true },
{ text: 'O parâmetro pass', correct: false },
{ text: 'A versão HTTP', correct: false }
],
explanation: "O payload ' OR '1'='1' -- tenta burlar a autenticação fazendo a cláusula WHERE sempre verdadeira."
}
],
'DDoS Attack': [
{
question: 'Que tipo de ataque DDoS este provavelmente é?',
evidence: 'Alto volume de pacotes SYN de múltiplas fontes direcionados à porta 80',
options: [
{ text: 'Flood UDP', correct: false },
{ text: 'Ataque SYN flood', correct: true },
{ text: 'Amplificação DNS', correct: false },
{ text: 'Flood HTTP GET', correct: false }
],
explanation: 'Ataques SYN flood sobrecarregam o alvo enviando muitos pacotes SYN sem completar o handshake TCP.'
}
],
'Malware C2': [
{
question: 'O que indica que isto é provavelmente tráfego C2 (Command and Control)?',
evidence: 'Tráfego HTTPS criptografado para malware-c2.darknet.com a cada 300 segundos',
options: [
{ text: 'A criptografia HTTPS', correct: false },
{ text: 'Padrão de beacon regular e domínio suspeito', correct: true },
{ text: 'O número da porta usada', correct: false },
{ text: 'O tamanho do pacote', correct: false }
],
explanation: 'Beaconing regular para domínios suspeitos indica malware se comunicando com servidores C2 para instruções.'
}
],
'Brute Force Attack': [
{
question: 'Qual é a melhor resposta imediata para este ataque de força bruta?',
evidence: 'Múltiplas tentativas de login SSH falharam de 203.0.113.42 direcionadas ao usuário "admin"',
options: [
{ text: 'Ignorar como falso positivo', correct: false },
{ text: 'Bloquear o IP de origem imediatamente', correct: true },
{ text: 'Apenas mudar a porta SSH', correct: false },
{ text: 'Monitorar sem ação', correct: false }
],
explanation: 'Bloquear o IP atacante previne tentativas contínuas de força bruta e protege o sistema.'
}
]
};
return challengeBank[threatType] || [];
}
addInvestigationLog(message, type = 'success') {
const log = document.getElementById('investigationLog');
const entry = document.createElement('div');
entry.className = `log-entry log-${type}`;
entry.innerHTML = `${new Date().toLocaleTimeString()}: ${message}`;
log.appendChild(entry);
log.scrollTop = log.scrollHeight;
// Keep only last 20 entries
if (log.children.length > 20) {
log.removeChild(log.firstChild);
}
}
updateScoreDisplay() {
const accuracy = this.gameScore.actionsTaken > 0
? Math.round((this.gameScore.correctActions / this.gameScore.actionsTaken) * 100)
: 100;
document.getElementById('totalScore').textContent = this.gameScore.totalScore;
document.getElementById('threatsIdentified').textContent = this.gameScore.threatsIdentified;
document.getElementById('actionsTaken').textContent = this.gameScore.actionsTaken;
document.getElementById('accuracy').textContent = accuracy + '%';
}
generateInspectionFindings(packet) {
const findings = {
'Port Scan': [
'TCP flags indicate SYN scan pattern',
'Sequential port targeting detected',
'No application data payload',
'Source shows scanning behavior'
],
'SQL Injection': [
'SQL metacharacters detected in parameters',
'Potential authentication bypass attempt',
'Suspicious query structure identified',
'Web application vulnerability exploit'
],
'DDoS Attack': [
'Abnormally high connection rate',
'SYN flood pattern identified',
'Multiple source coordination',
'Resource exhaustion attempt'
],
'Malware C2': [
'Encrypted communication channel',
'Regular beaconing intervals',
'Suspicious domain reputation',
'Potential data exfiltration'
],
'Brute Force Attack': [
'Multiple authentication failures',
'Dictionary attack pattern',
'Credential guessing attempt',
'Account lockout recommended'
]
};
return findings[packet.threatType] || ['Unknown threat pattern'];
}
generateTraceRoute(targetIP) {
return [
'192.168.1.1 (router.local)',
'10.0.0.1 (gateway)',
'203.0.113.1 (isp-router)',
'198.51.100.1 (backbone)',
targetIP + ' (target)'
];
}
generateWhoisData(ip) {
return {
'IP Address': ip,
'Country': ['US', 'CN', 'RU', 'BR', 'IN'][Math.floor(Math.random() * 5)],
'Organization': 'Suspicious Hosting Ltd',
'ASN': 'AS' + Math.floor(Math.random() * 65535),
'Reputation': 'BLACKLISTED'
};
}
generateFirewallRule(packet) {
return `iptables -A INPUT -s ${packet.src} -j DROP # Block ${packet.threatType}`;
}
startChallenge() {
if (!this.activeIncident) {
this.addInvestigationLog('❌ Nenhum pacote selecionado. Clique em um pacote primeiro.', 'error');
return;
}
if (!this.activeIncident.isThreat || !this.activeIncident.threatType) {
this.addInvestigationLog('⚠️ Este é um pacote normal. Selecione um pacote VERMELHO/LARANJA (ameaça) com 🚨', 'warning');
return;
}
// Check if this packet already had a challenge completed
if (this.completedChallenges.has(this.activeIncident.id)) {
this.addInvestigationLog('✅ Este pacote já foi analisado! Procure por outras ameaças.', 'warning');
return;
}
this.addInvestigationLog(`🎯 Desafio iniciado: ${this.activeIncident.threatType}`, 'success');
this.addInvestigationLog(`🤔 Escolha a melhor ação para resolver esta ameaça:`, 'success');
// Show investigation options
const hiddenOptions = document.getElementById('hiddenInvestigationOptions');
if (hiddenOptions) {
hiddenOptions.style.display = 'block';
console.log('Showing hidden options');
} else {
console.error('Hidden options element not found!');
}
// Hide the start challenge button
const startBtn = document.querySelector('[onclick="analyzer.startChallenge()"]');
if (startBtn) {
startBtn.style.display = 'none';
}
}
selectAction(action) {
console.log('selectAction called with:', action);
console.log('activeIncident:', this.activeIncident);
if (!this.activeIncident) {
this.addInvestigationLog('❌ Nenhum incidente ativo!', 'error');
return;
}
const correctActions = {
'Port Scan': ['blockIP', 'createFirewallRule'],
'DDoS Attack': ['blockIP', 'createFirewallRule'],
'Brute Force Attack': ['blockIP', 'createFirewallRule'],
'Malware C2': ['quarantineHost', 'collectEvidence'],
'SQL Injection': ['quarantineHost', 'reportIncident']
};
const threatType = this.activeIncident.threatType;
const isCorrect = correctActions[threatType] && correctActions[threatType].includes(action);
// Mark action as used
const packetId = this.activeIncident.id;
const actionKey = `${packetId}-${action}`;
this.usedActions.set(actionKey, true);
this.gameScore.actionsTaken++;
if (isCorrect) {
this.gameScore.correctActions++;
this.gameScore.totalScore += 100;
this.gameScore.threatsIdentified++;
// Mark packet as resolved (blue)
this.resolvedPackets.add(this.activeIncident.id);
this.updatePacketColor(this.activeIncident.id, 'resolved');
this.addInvestigationLog(`✅ CORRETO! ${this.getActionName(action)} foi a ação adequada!`, 'success');
this.addInvestigationLog(`🎉 Ameaça ${threatType} resolvida com sucesso!`, 'success');
this.addInvestigationLog(`🔵 Pacote marcado como RESOLVIDO (azul)`, 'success');
this.addInvestigationLog(`🏆 +100 pontos! Desafio concluído.`, 'success');
} else {
this.gameScore.incorrectActions++;
this.gameScore.totalScore -= 25;
const correctActionNames = correctActions[threatType].map(a => this.getActionName(a)).join(' ou ');
this.addInvestigationLog(`❌ INCORRETO! ${this.getActionName(action)} não é ideal para ${threatType}`, 'error');
this.addInvestigationLog(`💡 A ação correta seria: ${correctActionNames}`, 'warning');
this.addInvestigationLog(`🔴 Pacote permanece como ameaça não resolvida`, 'error');
this.addInvestigationLog(`📉 -25 pontos. Tente outro pacote!`, 'error');
}
// Mark this packet as having completed a challenge
this.completedChallenges.add(this.activeIncident.id);
this.updateScoreDisplay();
this.completeChallenge();
}
getActionName(action) {
const names = {
'blockIP': 'Bloquear IP',
'quarantineHost': 'Quarentena Host',
'deepPacketInspection': 'Inspeção Profunda',
'traceRoute': 'Rastrear Rota',
'whoisLookup': 'Consulta WHOIS',
'createFirewallRule': 'Criar Regra',
'reportIncident': 'Reportar Incidente',
'collectEvidence': 'Coletar Evidências'
};
return names[action] || action;
}
completeChallenge() {
// Hide investigation options
document.getElementById('hiddenInvestigationOptions').style.display = 'none';
// Show start challenge button again for next packet
const startBtn = document.querySelector('[onclick="analyzer.startChallenge()"]');
startBtn.style.display = 'block';
// DON'T clear active incident or hide panel - let player see the result
// this.activeIncident = null;
// document.getElementById('investigationPanel').classList.remove('show');
this.addInvestigationLog(`✨ Desafio finalizado para este pacote!`, 'success');
this.addInvestigationLog(`🔍 Procure por mais ameaças para continuar`, 'success');
// Check game end conditions
this.checkGameEnd();
}
checkGameEnd() {
if (!this.gameActive) return;
const totalChallenges = this.gameScore.actionsTaken;
const correctRate = totalChallenges > 0 ? (this.gameScore.correctActions / totalChallenges) * 100 : 0;
// Check win conditions
if (this.gameScore.threatsIdentified >= this.gameRules.maxThreats && correctRate >= this.gameRules.minCorrectRate) {
this.endGame(true); // Win
return;
}
// Check lose condition
if (this.gameScore.incorrectActions >= this.gameRules.maxIncorrect) {
this.endGame(false); // Lose
return;
}
// Show progress
const remaining = this.gameRules.maxThreats - this.gameScore.threatsIdentified;
if (remaining > 0 && remaining <= 3) {
this.addInvestigationLog(`⚡ Faltam apenas ${remaining} ameaças para completar a missão!`, 'warning');
}
if (this.gameScore.incorrectActions === 2) {
this.addInvestigationLog(`⚠️ ATENÇÃO: Mais 1 erro e você perde o jogo!`, 'error');
}
}
endGame(success) {
this.gameActive = false;
this.stopCapture();
const totalChallenges = this.gameScore.actionsTaken;
const correctRate = totalChallenges > 0 ? Math.round((this.gameScore.correctActions / totalChallenges) * 100) : 0;
const statsHTML = `
<div class="stat-line"><span>Pontuação Final:</span><span style="color: #00ff00;">${this.gameScore.totalScore}</span></div>
<div class="stat-line"><span>Ameaças Resolvidas:</span><span>${this.gameScore.threatsIdentified}/${this.gameRules.maxThreats}</span></div>
<div class="stat-line"><span>Ações Corretas:</span><span>${this.gameScore.correctActions}</span></div>
<div class="stat-line"><span>Ações Incorretas:</span><span>${this.gameScore.incorrectActions}</span></div>
<div class="stat-line"><span>Taxa de Acerto:</span><span>${correctRate}%</span></div>
`;
if (success) {
document.getElementById('successStats').innerHTML = statsHTML;
document.getElementById('successModal').style.display = 'flex';
} else {
document.getElementById('failureStats').innerHTML = statsHTML;
document.getElementById('failureModal').style.display = 'flex';
}
}
restartGame() {
// Hide modals
document.getElementById('successModal').style.display = 'none';
document.getElementById('failureModal').style.display = 'none';
// Reset everything
this.gameActive = true;
this.clearCapture();
this.gameScore = {
totalScore: 0,
threatsIdentified: 0,
actionsTaken: 0,
correctActions: 0,
incorrectActions: 0
};
this.updateScoreDisplay();
// Clear investigation panel
this.activeIncident = null;
document.getElementById('investigationPanel').classList.remove('show');
this.addInvestigationLog(`🎮 Novo jogo iniciado! Boa sorte!`, 'success');
}
closeInstructions() {
document.getElementById('instructionsOverlay').style.display = 'none';
}
}
// Initialize the realistic network analyzer
document.addEventListener('DOMContentLoaded', function() {
try {
const analyzer = new RealisticNetworkAnalyzer();
console.log('Analisador de Rede inicializado com sucesso');
} catch (error) {
console.error('Erro ao inicializar o Analisador de Rede:', error);
// Show error message to user
const errorDiv = document.createElement('div');
errorDiv.style.cssText = `
position: fixed;
top: 20px;
left: 20px;
background: #330000;
color: #ff4444;
padding: 20px;
border: 1px solid #ff4444;
border-radius: 5px;
z-index: 9999;
font-family: monospace;
`;
errorDiv.innerHTML = `
<h3>Erro de Inicialização</h3>
<p>Falha ao iniciar o Analisador de Rede: ${error.message}</p>
<p>Por favor, atualize a página para tentar novamente.</p>
`;
document.body.appendChild(errorDiv);
}
});
</script>
</body>
</html>