feat(ui): ataques (Evil Twin, regras/máscara, WPS), captura mais robusta

- app.js/app.css/index.html: telas novas para Evil Twin (PSK e
  Enterprise), regras de mutação/máscara na quebra de senha, WPS,
  indicador de modo (monitor/gerenciado) movido para baixo do seletor de
  interface, e aviso específico quando a placa não entrega captura de
  verdade (ver bug de ScanSnapshot.warning no engine).
- Lista de redes/BSSIDs não reordena mais a cada poll: ordem de chegada
  como critério de desempate e sinal arredondado em buckets de 4 dBm,
  porque reordenar pelo sinal instantâneo fazia as linhas flutuarem de
  posição debaixo do cursor a cada atualização.
- "Forçar handshake" religa a captura sozinho se ela tiver sido parada
  (esperando o AP reaparecer no canal certo antes de disparar o job, e
  travando o alvo numa variável local pra não perder o BSSID se o diálogo
  fechar no meio da espera).
- Grid da aba Ataques trocado de CSS grid pra colunas (alvenaria): cards
  com alturas muito diferentes na mesma linha deixavam buracos vazios
  enormes com align-items:start.
- check-ui-i18n.mjs: ajustes de cobertura para as novas telas.
This commit is contained in:
Lucas Rayan committed 2026-10-24 14:54:49 -03:00
1 parent a3ca73e610
commit 6e0cd7cf10
5 files changed
+3077 -76

No files matched your search

+101 -12
View File
@@ -18,17 +18,39 @@
</div>
</div>
<div class="side-title">Interfaces</div>
<ul class="list" id="ifaceList" data-empty="nenhuma interface Wi-Fi encontrada"></ul>
<div class="side-title">Interface</div>
<div class="iface-pick">
<select id="ifaceSelect" class="select" aria-label="Interface Wi-Fi" data-empty="nenhuma interface Wi-Fi encontrada"></select>
<span id="modePill" class="pill"><span class="dot"></span><span id="modeLabel">—</span></span>
</div>
<div class="side-title">Visualização</div>
<ul class="list" id="viewNav" role="group" aria-label="Visualização">
<li><button type="button" class="dev" data-view="nets" aria-pressed="true">
<span class="ico"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12.55a11 11 0 0 1 14.08 0"/><path d="M1.42 9a16 16 0 0 1 21.16 0"/><path d="M8.53 16.11a6 6 0 0 1 6.95 0"/><circle cx="12" cy="20" r="1"/></svg></span>
<span><span class="t">Redes</span><span class="s">APs, clientes e ataques</span></span>
</button></li>
<li><button type="button" class="dev" data-view="channels" aria-pressed="false">
<span class="ico"><svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"><line x1="5" y1="19" x2="5" y2="10"/><line x1="12" y1="19" x2="12" y2="5"/><line x1="19" y1="19" x2="19" y2="13"/></svg></span>
<span><span class="t">Canais</span><span class="s">espectro e saúde</span></span>
</button></li>
</ul>
<div class="side-foot">
<span id="verInfo" class="mono">—</span>
<select id="langSel" class="lang-sel" aria-label="Idioma" title="Idioma">
<option value="auto">Auto</option>
<option value="pt">Português</option>
<option value="en">English</option>
</select>
<button id="btnUpdate" type="button">checar atualização</button>
<div class="foot-row">
<button id="settingsBtn" class="icon-btn" type="button" title="Configurações" aria-label="Configurações">
<svg viewBox="0 0 24 24" width="17" height="17" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.7 1.7 0 0 0 .3 1.8l.1.1a2 2 0 1 1-2.8 2.8l-.1-.1a1.7 1.7 0 0 0-1.8-.3 1.7 1.7 0 0 0-1 1.5V21a2 2 0 1 1-4 0v-.1a1.7 1.7 0 0 0-1.1-1.5 1.7 1.7 0 0 0-1.8.3l-.1.1a2 2 0 1 1-2.8-2.8l.1-.1a1.7 1.7 0 0 0 .3-1.8 1.7 1.7 0 0 0-1.5-1H3a2 2 0 1 1 0-4h.1a1.7 1.7 0 0 0 1.5-1.1 1.7 1.7 0 0 0-.3-1.8l-.1-.1a2 2 0 1 1 2.8-2.8l.1.1a1.7 1.7 0 0 0 1.8.3H9a1.7 1.7 0 0 0 1-1.5V3a2 2 0 1 1 4 0v.1a1.7 1.7 0 0 0 1 1.5 1.7 1.7 0 0 0 1.8-.3l.1-.1a2 2 0 1 1 2.8 2.8l-.1.1a1.7 1.7 0 0 0-.3 1.8V9a1.7 1.7 0 0 0 1.5 1H21a2 2 0 1 1 0 4h-.1a1.7 1.7 0 0 0-1.5 1z"/></svg>
</button>
<div class="theme-switch" role="group" aria-label="Tema">
<button type="button" data-theme-pick="auto" aria-pressed="true">Auto</button>
<button type="button" data-theme-pick="light" aria-pressed="false">Claro</button>
<button type="button" data-theme-pick="dark" aria-pressed="false">Escuro</button>
</div>
</div>
<div class="foot-row">
<span id="verInfo" class="mono">—</span>
<button id="btnUpdate" type="button">checar atualização</button>
</div>
</div>
</aside>
@@ -39,7 +61,9 @@
<h1>Painel de captura</h1>
<div class="sub" id="ifaceSub">selecione uma interface</div>
</div>
<span id="modePill" class="pill"><span class="dot"></span><span id="modeLabel">—</span></span>
<div class="top-actions">
<button id="btnReport" class="btn" type="button" disabled>Relatório</button>
</div>
</div>
<svg class="wave" id="wave" viewBox="0 0 600 34" preserveAspectRatio="none">
@@ -68,14 +92,79 @@
</div>
<div class="result-head">
<strong>Redes vistas</strong>
<span id="count">0</span>
<div class="result-summary">
<strong id="resultTitle">Redes vistas</strong>
<span id="count">0</span>
</div>
<div class="result-tools">
<input id="searchInput" class="filter" type="search" placeholder="filtrar por SSID ou BSSID" aria-label="Filtrar redes" autocomplete="off" spellcheck="false">
<select id="sortSel" class="select compact" aria-label="Ordenar por">
<option value="signal">Sinal</option>
<option value="security">Segurança</option>
<option value="clients">Clientes</option>
<option value="name">Nome</option>
</select>
</div>
</div>
<div id="resultArea"></div>
</div>
</main>
</div>
<dialog id="targetDlg" class="target-dlg" aria-labelledby="targetTitle">
<div class="target-head">
<div class="target-id">
<h2 id="targetTitle">—</h2>
<div class="target-sub" id="targetSub"></div>
</div>
<button id="targetClose" class="icon-btn" type="button" aria-label="Fechar" title="Fechar">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
</button>
</div>
<div class="tabs" role="tablist" aria-label="Detalhes do alvo">
<button type="button" role="tab" data-tab="overview" aria-selected="true">Visão geral</button>
<button type="button" role="tab" data-tab="clients" aria-selected="false">Clientes <span class="tab-count" id="tabClientsCount">0</span></button>
<button type="button" role="tab" data-tab="attacks" aria-selected="false">Ataques</button>
</div>
<div class="tab-panel" id="tabPanel"></div>
</dialog>
<dialog id="reportDlg" class="report-dlg" aria-labelledby="reportTitle">
<div class="report-head">
<div>
<h2 id="reportTitle">Relatório de auditoria</h2>
<p class="hint" id="reportStatus">Pré-visualização paginada em A4.</p>
</div>
<div class="report-tools">
<button type="button" class="icon-btn" id="reportZoomOut" title="Diminuir zoom" aria-label="Diminuir zoom">−</button>
<span class="mono" id="reportZoomLabel">100%</span>
<button type="button" class="icon-btn" id="reportZoomIn" title="Aumentar zoom" aria-label="Aumentar zoom">+</button>
<button type="button" class="btn" id="reportPrint">Imprimir / PDF</button>
<button type="button" class="btn" id="reportDownload">Baixar HTML</button>
<button type="button" class="icon-btn" id="reportClose" title="Fechar" aria-label="Fechar">
<svg viewBox="0 0 24 24" width="18" height="18" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><path d="M6 6l12 12M18 6L6 18"/></svg>
</button>
</div>
</div>
<div class="report-view" id="reportView"><div class="report-canvas" id="reportCanvas"><iframe id="reportFrame" title="Relatório paginado"></iframe></div></div>
</dialog>
<dialog id="settingsDlg" aria-labelledby="settingsTitle">
<form method="dialog">
<h2 id="settingsTitle">Configurações</h2>
<div class="field">
<span class="field-label">Idioma</span>
<select id="langSel" class="select" name="lang" aria-label="Idioma">
<option value="auto">Auto</option>
<option value="pt">Português</option>
<option value="en">English</option>
</select>
</div>
<menu><button class="btn primary" value="close">Fechar</button></menu>
</form>
</dialog>
<script type="module" src="/app.js"></script>
</body>
</html>