- Logo oficial (sabia.png) e conjunto de ícones do app desktop. - Interface em português e inglês: tradutor por observação do DOM, seletor de idioma e checagem de cobertura de tradução no CI. - CI/CD com caches (rust-cache, .deb do Tauri em cache) e pipeline de release multiplataforma (CLI em 5 alvos + app desktop via tauri-action), templates de issue/PR. - Suíte de testes de integração do sabia-core (scan e2e, handshake/crack 4-way e PMKID, pcap, trilha de auditoria) — 46 testes verdes. - Documentação completa pt/en: README, ROADMAP, SECURITY, CONTRIBUTING, CHANGELOG e docs/ (cli, interface, arquitetura), com enquadramento de uso autorizado. - Correções de clippy (-D warnings) e formatação em toda a árvore. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
88 lines
3.1 KiB
Rust
88 lines
3.1 KiB
Rust
//! Integração: beacon + probe + handshake completo passando pelo caminho
|
|
//! público de agregação (`ScanTable`), verificando que AP, cliente e
|
|
//! handshake são detectados de ponta a ponta.
|
|
|
|
mod common;
|
|
|
|
use sabia_core::scan::ScanTable;
|
|
|
|
#[test]
|
|
fn detects_ap_client_and_handshake_end_to_end() {
|
|
let mut table = ScanTable::new();
|
|
|
|
// RSN com AKM PSK (2) para que a rede apareça como WPA2-PSK.
|
|
let beacon = common::beacon_frame(common::ap(), "RedeTeste", 6, &[2]);
|
|
table.ingest(&common::radiotap_wrap(&beacon, 2437, -35));
|
|
|
|
let probe = common::probe_request(common::sta(), "RedeTeste");
|
|
table.ingest(&common::radiotap_wrap(&probe, 2437, -50));
|
|
|
|
let (f1, f2) = common::handshake_radiotap_frames("RedeTeste", "senha-correta", 2, false);
|
|
let ev1 = table.ingest_at(&f1, 10);
|
|
assert!(ev1.eapol, "quadro msg1 deveria ser reconhecido como EAPOL");
|
|
let ev2 = table.ingest_at(&f2, 11);
|
|
assert!(ev2.eapol, "quadro msg2 deveria ser reconhecido como EAPOL");
|
|
assert!(
|
|
ev2.handshake_updated,
|
|
"msg2 deveria completar/atualizar o handshake"
|
|
);
|
|
|
|
let aps = table.access_points();
|
|
assert_eq!(aps.len(), 1);
|
|
let ap = &aps[0];
|
|
assert_eq!(ap.bssid, sabia_core::dot11::mac_to_string(&common::ap()));
|
|
assert_eq!(ap.ssid.as_deref(), Some("RedeTeste"));
|
|
assert_eq!(ap.channel, Some(6));
|
|
assert_eq!(ap.security.as_deref(), Some("WPA2"));
|
|
|
|
let clients = table.clients();
|
|
assert!(clients
|
|
.iter()
|
|
.any(|c| c.mac == sabia_core::dot11::mac_to_string(&common::sta())));
|
|
|
|
let handshakes = table.handshakes();
|
|
assert_eq!(handshakes.len(), 1);
|
|
let hs = &handshakes[0];
|
|
assert_eq!(hs.ssid.as_deref(), Some("RedeTeste"));
|
|
assert!(hs.complete, "handshake deveria estar completo (msg1+msg2)");
|
|
assert!(hs.crackable, "handshake deveria ser quebrável");
|
|
|
|
let stats = table.stats();
|
|
assert_eq!(stats.aps, 1);
|
|
assert_eq!(stats.clients, 1);
|
|
assert_eq!(stats.handshakes, 1);
|
|
assert!(stats.eapol_frames >= 2);
|
|
}
|
|
|
|
#[test]
|
|
fn hidden_ssid_beacon_is_marked_hidden() {
|
|
let mut table = ScanTable::new();
|
|
|
|
// SSID vazio = rede oculta.
|
|
let beacon = common::beacon_frame(common::ap(), "", 11, &[2]);
|
|
table.ingest(&common::radiotap_wrap(&beacon, 2462, -60));
|
|
|
|
let aps = table.access_points();
|
|
assert_eq!(aps.len(), 1);
|
|
assert!(aps[0].hidden);
|
|
}
|
|
|
|
#[test]
|
|
fn pmkid_only_handshake_is_detected_and_crackable() {
|
|
let mut table = ScanTable::new();
|
|
|
|
// Beacon com SSID visível, para que o handshake herde o SSID via hint.
|
|
let beacon = common::beacon_frame(common::ap(), "RedePmkid", 11, &[2]);
|
|
table.ingest_at(&common::radiotap_wrap(&beacon, 2462, -60), 1);
|
|
|
|
// Handshake via PMKID (só msg1, sem msg2/snonce).
|
|
let (m1, _m2) = common::handshake_frames("RedePmkid", "outra-senha", 2, true);
|
|
let f1 = common::frame_with_eapol(true, common::ap(), common::sta(), common::sta(), &m1);
|
|
let ev = table.ingest_at(&common::radiotap_wrap(&f1, 2462, -55), 20);
|
|
assert!(ev.eapol);
|
|
|
|
let handshakes = table.handshakes();
|
|
assert_eq!(handshakes.len(), 1);
|
|
assert!(handshakes[0].crackable, "PMKID isolado já é quebrável");
|
|
}
|