Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c7638a2f4e | ||
|
|
d885d92643 | ||
|
|
0e31d28342 | ||
|
|
9bcdd6c139 |
No files matched your search
@@ -4,9 +4,9 @@ on:
|
||||
# Mudança só de documentação não precisa de 6 jobs em 3 sistemas.
|
||||
push:
|
||||
branches: [main]
|
||||
paths-ignore: ['**.md', 'docs/**', 'LICENSE*', '.gitignore', '.githooks/**']
|
||||
paths-ignore: ['**.md', 'docs/**', 'LICENSE*', '.gitignore', '.githooks/**', '.wolf/**', '.claude/**', 'scripts/release-notes.sh', '.gitea/workflows/release.yml']
|
||||
pull_request:
|
||||
paths-ignore: ['**.md', 'docs/**', 'LICENSE*', '.gitignore', '.githooks/**']
|
||||
paths-ignore: ['**.md', 'docs/**', 'LICENSE*', '.gitignore', '.githooks/**', '.wolf/**', '.claude/**', 'scripts/release-notes.sh', '.gitea/workflows/release.yml']
|
||||
|
||||
concurrency:
|
||||
group: ci-${{ github.ref }}
|
||||
@@ -15,17 +15,24 @@ concurrency:
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
RUSTFLAGS: -D warnings
|
||||
# O runner mantém /opt/hostedtoolcache num volume que sobrevive entre jobs:
|
||||
# a toolchain do rustup, o registry do cargo e o diretório target ficam ali,
|
||||
# então nada disso é baixado ou recompilado do zero a cada execução. Cada job
|
||||
# usa o seu próprio target (flags diferentes invalidariam o de outro job).
|
||||
CARGO_HOME: /opt/hostedtoolcache/cargo
|
||||
RUSTUP_HOME: /opt/hostedtoolcache/rustup
|
||||
|
||||
jobs:
|
||||
lint:
|
||||
name: Formatação e clippy
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/sabia-lint
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
components: rustfmt, clippy
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 22
|
||||
@@ -34,37 +41,39 @@ jobs:
|
||||
- run: cargo fmt --all -- --check
|
||||
- run: cargo clippy --workspace --all-targets
|
||||
|
||||
# Windows e macOS saem: o Gitea aqui tem um único runner, Linux arm64.
|
||||
test:
|
||||
name: Testes (${{ matrix.os }})
|
||||
runs-on: ${{ matrix.os }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os: [ubuntu-24.04, windows-latest, macos-latest]
|
||||
name: Testes (Linux)
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/sabia-test
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
- run: cargo test --workspace
|
||||
|
||||
audit:
|
||||
name: Auditoria de dependências
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: rustsec/audit-check@v2
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
# rustsec/audit-check depends on GitHub's checks API. cargo-audit itself
|
||||
# needs nothing but the advisory database, and installing it once into the
|
||||
# persistent CARGO_HOME makes every later run skip the compile.
|
||||
- name: cargo audit
|
||||
run: |
|
||||
command -v cargo-audit >/dev/null || cargo install cargo-audit --locked
|
||||
cargo audit
|
||||
|
||||
gui:
|
||||
name: Compila o app desktop (Linux)
|
||||
runs-on: ubuntu-24.04
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/sabia-gui
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: Swatinem/rust-cache@v2
|
||||
with:
|
||||
workspaces: apps/gui/src-tauri
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 22
|
||||
@@ -0,0 +1,106 @@
|
||||
name: Release
|
||||
|
||||
# Quando uma tag v* é enviada: cria a entrada em "Releases" com as notas do
|
||||
# CHANGELOG.md e anexa o CLI compilado (scripts/package-cli.sh), com um .sha256 ao
|
||||
# lado de cada pacote. É o que o atualizador (`sabia update`) baixa.
|
||||
#
|
||||
# O CLI é só para Linux (x86_64 e aarch64), compilado no runner Linux; o x86_64
|
||||
# por compilação cruzada. Windows e macOS têm só o app desktop.
|
||||
on:
|
||||
push:
|
||||
tags: ['v*']
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
# Toolchain e registry do cargo ficam no volume que sobrevive entre jobs.
|
||||
CARGO_HOME: /opt/hostedtoolcache/cargo
|
||||
RUSTUP_HOME: /opt/hostedtoolcache/rustup
|
||||
|
||||
jobs:
|
||||
release:
|
||||
name: Cria a release
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Release
|
||||
env:
|
||||
TAG: ${{ gitea.ref_name }}
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: |
|
||||
# Uma execução repetida não recria a release.
|
||||
if curl -fsS -H "Authorization: token $TOKEN" "$API/releases/tags/$TAG" >/dev/null 2>&1; then
|
||||
echo "a release $TAG já existe"; exit 0
|
||||
fi
|
||||
scripts/release-notes.sh "$TAG" > notes.md
|
||||
pre=false; case "$TAG" in *-*) pre=true ;; esac
|
||||
jq -n --arg tag "$TAG" --arg name "Sabiá ${TAG#v}" --rawfile body notes.md --argjson pre "$pre" \
|
||||
'{tag_name:$tag, name:$name, body:$body, prerelease:$pre}' > release.json
|
||||
curl -fsS -X POST "$API/releases" -H "Authorization: token $TOKEN" \
|
||||
-H 'Content-Type: application/json' -d @release.json >/dev/null
|
||||
|
||||
cli:
|
||||
name: CLI (${{ matrix.platform }})
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/sabia-release
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
include:
|
||||
- { platform: linux-aarch64, target: aarch64-unknown-linux-gnu, apt: "" }
|
||||
- { platform: linux-x86_64, target: x86_64-unknown-linux-gnu, apt: "gcc-x86-64-linux-gnu" }
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
with:
|
||||
targets: ${{ matrix.target }}
|
||||
- name: Linker e ferramentas desta plataforma
|
||||
if: ${{ matrix.apt != '' }}
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq ${{ matrix.apt }}
|
||||
- name: Compila e empacota
|
||||
run: scripts/package-cli.sh "${{ gitea.ref_name }}" "${{ matrix.platform }}" "${{ matrix.target }}" | tee packages.txt
|
||||
- name: Anexa à release
|
||||
env:
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: scripts/release-upload.sh "${{ gitea.ref_name }}" $(cat packages.txt)
|
||||
|
||||
gui:
|
||||
name: App desktop (${{ matrix.platform }})
|
||||
needs: release
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
CARGO_TARGET_DIR: /opt/hostedtoolcache/cargo-target/sabia-release-gui
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
platform: [linux, windows]
|
||||
steps:
|
||||
- uses: actions/checkout@v7
|
||||
- uses: dtolnay/rust-toolchain@stable
|
||||
- uses: actions/setup-node@v7
|
||||
with:
|
||||
node-version: 22
|
||||
- name: Dependências do Tauri (Linux)
|
||||
if: matrix.platform == 'linux'
|
||||
timeout-minutes: 25
|
||||
run: scripts/apt-install.sh ~/apt-cache libwebkit2gtk-4.1-dev libayatana-appindicator3-dev librsvg2-dev patchelf
|
||||
- name: Ferramentas para compilação cruzada (Windows)
|
||||
if: matrix.platform == 'windows'
|
||||
run: |
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq nsis lld llvm clang
|
||||
command -v cargo-xwin >/dev/null || cargo install cargo-xwin --locked
|
||||
- name: Compila e empacota
|
||||
run: scripts/build-gui.sh "${{ matrix.platform }}"
|
||||
- name: Anexa à release
|
||||
env:
|
||||
TOKEN: ${{ gitea.token }}
|
||||
API: ${{ gitea.server_url }}/api/v1/repos/${{ gitea.repository }}
|
||||
run: scripts/release-upload.sh "${{ gitea.ref_name }}" dist-gui/*
|
||||
@@ -18,3 +18,7 @@ apps/gui/src-tauri/target
|
||||
CLAUDE.md
|
||||
AGENTS.md
|
||||
GEMINI.md
|
||||
|
||||
# Pacotes gerados por scripts/package-cli.sh
|
||||
/sabia-v*
|
||||
/dist-gui
|
||||
@@ -4,6 +4,27 @@
|
||||
|
||||
Format based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); versions follow SemVer.
|
||||
|
||||
## [1.0.1] - 2026-10-30
|
||||
|
||||
The project moved from GitHub to Gitea, and the update check followed it.
|
||||
|
||||
### Changed
|
||||
- **Updates now come from Gitea.** `sabia update` and the desktop app's "Update now"
|
||||
read the latest release from `git.lucasrguerra.dev.br` instead of the GitHub API.
|
||||
Versions up to 1.0.0 still look at GitHub, which is no longer reachable, so they
|
||||
cannot find this release: download 1.0.1 once, and later updates are automatic.
|
||||
- Release packages: the CLI for Linux x86_64 and aarch64 (built by the Gitea CI when
|
||||
a `v*` tag is pushed, with a `.sha256` next to each package), and the desktop app
|
||||
for Linux (`.AppImage`, `.deb`) and Windows (NSIS `.exe` installer, cross-compiled
|
||||
from Linux by `scripts/build-gui.sh`). **There is no Windows CLI and no macOS build
|
||||
any more**: the CLI is Linux-only, and macOS needs Apple's SDK and code signing,
|
||||
which this project's CI cannot provide.
|
||||
|
||||
### Fixed
|
||||
- `sabia update` refuses to run from the desktop app's executable (`sabia-gui`).
|
||||
The release package contains the CLI, and replacing the app with it would have
|
||||
broken the app; the app now points to the downloads page instead.
|
||||
|
||||
## [1.0.0] - 2026-10-24
|
||||
|
||||
First stable release: real-hardware validation across the whole attack surface, a much more complete cracking pipeline, two new attacks (WPS, Evil Twin), a redesigned report, and several reliability fixes found only by testing against live Wi-Fi networks.
|
||||
|
||||
@@ -4,6 +4,27 @@
|
||||
|
||||
Formato baseado em [Keep a Changelog](https://keepachangelog.com/pt-BR/1.1.0/); versões seguem SemVer.
|
||||
|
||||
## [1.0.1] - 2026-10-30
|
||||
|
||||
O projeto saiu do GitHub para o Gitea, e a verificação de atualização foi junto.
|
||||
|
||||
### Alterado
|
||||
- **As atualizações agora vêm do Gitea.** O `sabia update` e o "Atualizar agora" do app
|
||||
desktop leem a última release em `git.lucasrguerra.dev.br`, e não mais a API do
|
||||
GitHub. As versões até a 1.0.0 ainda olham o GitHub, que não responde mais, e por isso
|
||||
não enxergam esta release: baixe a 1.0.1 uma vez, e as próximas atualizações são automáticas.
|
||||
- Pacotes da release: o CLI para Linux x86_64 e aarch64 (compilado pelo CI do Gitea
|
||||
quando uma tag `v*` é enviada, com um `.sha256` ao lado de cada pacote) e o app desktop
|
||||
para Linux (`.AppImage`, `.deb`) e Windows (instalador NSIS `.exe`, compilado a partir
|
||||
do Linux pelo `scripts/build-gui.sh`). **Não há mais CLI para Windows nem build para
|
||||
macOS**: o CLI é só para Linux, e o macOS exige o SDK e a assinatura da Apple, que o CI
|
||||
deste projeto não tem.
|
||||
|
||||
### Corrigido
|
||||
- O `sabia update` se recusa a rodar a partir do executável do app desktop (`sabia-gui`).
|
||||
O pacote da release contém o CLI, e trocar o app por ele o quebraria; o app passa a
|
||||
apontar para a página de downloads.
|
||||
|
||||
## [1.0.0] - 2026-10-24
|
||||
|
||||
Primeira versão estável: validação em hardware real por toda a superfície de ataque, um pipeline de quebra bem mais completo, dois ataques novos (WPS, Evil Twin), relatório redesenhado e várias correções de confiabilidade que só apareceram testando contra redes Wi-Fi de verdade.
|
||||
|
||||
+2
-2
@@ -17,9 +17,9 @@ cargo test --workspace
|
||||
node scripts/check-ui-i18n.mjs # UI translation coverage
|
||||
```
|
||||
|
||||
CI runs on Linux, Windows and macOS; run these before pushing — almost everything that fails CI shows up here in seconds. Documentation-only changes (`*.md`, `docs/`) are light on CI.
|
||||
CI runs on Linux only (Gitea has one runner); run these before pushing — almost everything that fails CI shows up here in seconds. Documentation-only changes (`*.md`, `docs/`) are light on CI.
|
||||
|
||||
Live capture exists only on Linux (`AF_PACKET` + netlink); on Windows and macOS those paths compile but aren't exercised. Parsing and cracking tests run on all three, because they're offline.
|
||||
Live capture exists only on Linux (`AF_PACKET` + netlink); the code behind Windows and macOS paths still compiles and is covered by `cargo check`, but neither runs in CI nor is built for release.
|
||||
|
||||
## Where to work
|
||||
|
||||
|
||||
@@ -17,9 +17,9 @@ cargo test --workspace
|
||||
node scripts/check-ui-i18n.mjs # cobertura da tradução da interface
|
||||
```
|
||||
|
||||
O CI roda em Linux, Windows e macOS; rode esses comandos antes do push — quase tudo que faz o CI falhar aparece aqui em segundos. Mudanças só de documentação (`*.md`, `docs/`) são leves no CI.
|
||||
O CI roda só em Linux (o Gitea tem um único runner); rode esses comandos antes do push — quase tudo que faz o CI falhar aparece aqui em segundos. Mudanças só de documentação (`*.md`, `docs/`) são leves no CI.
|
||||
|
||||
A captura ao vivo só existe no Linux (`AF_PACKET` + netlink); em Windows e macOS esses caminhos são compilados mas não exercitados. Testes de parsing e de quebra rodam nas três plataformas, porque são offline.
|
||||
A captura ao vivo só existe no Linux (`AF_PACKET` + netlink); o código dos caminhos de Windows e macOS continua compilando e é coberto pelo `cargo check`, mas não roda no CI nem é compilado para release. são offline.
|
||||
|
||||
## Onde mexer
|
||||
|
||||
|
||||
Generated
+2
-2
@@ -440,7 +440,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sabia-cli"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"clap",
|
||||
"ctrlc",
|
||||
@@ -451,7 +451,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sabia-core"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"flate2",
|
||||
|
||||
+2
-2
@@ -3,10 +3,10 @@ resolver = "2"
|
||||
members = ["crates/sabia-core", "crates/sabia-cli"]
|
||||
|
||||
[workspace.package]
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/lucasrguerra/sabia"
|
||||
repository = "https://git.lucasrguerra.dev.br/lucasrguerra/sabia"
|
||||
authors = ["Sabiá contributors"]
|
||||
rust-version = "1.80"
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<p align="center"><img src="apps/gui/ui/sabia.png" width="300" alt="Sabiá"></p>
|
||||
<h1 align="center">Sabiá</h1>
|
||||
<p align="center">Free and open Wi-Fi auditing.<br>Terminal and desktop app · live capture on Linux, offline analysis on Windows, Linux and macOS · authorized use.</p>
|
||||
<p align="center">Free and open Wi-Fi auditing.<br>Terminal and desktop app · live capture on Linux, offline analysis on Windows too · authorized use.</p>
|
||||
|
||||
<p align="center"><a href="docs/cli.md">Terminal</a> · <a href="docs/interface.md">Interface</a> · <a href="docs/architecture.md">Architecture</a> · <a href="ROADMAP.md">Roadmap</a> · <a href="CHANGELOG.md">Changelog</a></p>
|
||||
|
||||
@@ -37,17 +37,18 @@ Download the package for your system from **[Releases](../../releases)**:
|
||||
|
||||
| | CLI | Desktop app |
|
||||
|---|---|---|
|
||||
| Windows | `sabia-*-windows-x86_64.zip` | `.msi` / `.exe` installer |
|
||||
| macOS | `sabia-*-macos-{aarch64,x86_64}.tar.gz` | `.dmg` |
|
||||
| Windows | — | `.exe` installer |
|
||||
| Linux | `sabia-*-linux-{x86_64,aarch64}.tar.gz` | `.AppImage` / `.deb` |
|
||||
|
||||
Each file has a `.sha256` next to it. Build from source: `cargo build --release -p sabia-cli` (Rust 1.80+).
|
||||
The CLI is Linux-only; the desktop app ships for Linux and Windows. Each CLI
|
||||
package has a `.sha256` next to it. Build from source: `cargo build --release
|
||||
-p sabia-cli` (Rust 1.80+, Linux).
|
||||
|
||||
**Updates:** the desktop app checks GitHub on startup; when a new version exists, a button offers **Update now**: it downloads the right binary for your platform, verifies the **SHA-256** and swaps the running executable — no manual download. The check is a single request to the releases API and sends nothing of yours.
|
||||
**Updates:** the desktop app checks Gitea on startup; when a new version exists, a button offers **Update now**. The CLI updates the same way (`sabia update`); it downloads the right binary for your platform, verifies the **SHA-256** and swaps the running executable — no manual download. The check is a single request to the releases API and sends nothing of yours.
|
||||
|
||||
> The binaries are **not signed yet**: Windows SmartScreen and macOS Gatekeeper will warn. Check the SHA-256.
|
||||
> The binaries are **not signed yet**: Windows SmartScreen will warn. Check the SHA-256.
|
||||
|
||||
**Capture and monitor mode require Linux and root** (`CAP_NET_ADMIN`/`CAP_NET_RAW`): raw capture uses `AF_PACKET` and interface control uses netlink. **Offline `.pcap` analysis and cracking** also run on Windows and macOS. The desktop app elevates to administrator on its own at startup.
|
||||
**Capture and monitor mode require Linux and root** — the only platform the CLI ships for (`CAP_NET_ADMIN`/`CAP_NET_RAW`): raw capture uses `AF_PACKET` and interface control uses netlink. **Offline `.pcap` analysis and cracking** also run on Windows and macOS. The desktop app elevates to administrator on its own at startup.
|
||||
|
||||
## Getting started
|
||||
|
||||
@@ -74,11 +75,11 @@ Desktop app (Tauri) with an interface sidebar, a capture panel with an animated
|
||||
|
||||
## Known limits
|
||||
|
||||
- **Capture is Linux-only**, with a card that supports **monitor mode** (and injection, for `deauth`). On Windows and macOS Sabiá only does `.pcap` analysis and offline cracking.
|
||||
- **Capture is Linux-only**, with a card that supports **monitor mode** (and injection, for `deauth`); the CLI is not built for other platforms. On Windows Sabiá's desktop app only does `.pcap` analysis and offline cracking.
|
||||
- **WPA3/SAE** does not fall to handshake dictionaries — cracking covers **WPA/WPA2-PSK** (4-way and PMKID).
|
||||
- **5 and 6 GHz** depend on the card and the regulatory domain; some channels stay passive (no probing).
|
||||
- **Evil Twin's self-signed certificate:** the Enterprise variant's TLS certificate isn't trusted by clients that validate the chain (common on updated corporate/MDM devices) — that's the correct defense working, not a bug.
|
||||
- **Windows and macOS:** the code compiles and is tested in CI, but live capture does not run on those platforms.
|
||||
- **Windows:** the code compiles and is tested in CI, but live capture does not run there; the desktop app does offline analysis only. There is no macOS build: Tauri needs the macOS SDK and code signing, both tied to Apple hardware and an Apple Developer account, which this project's CI (a single Linux runner) does not have.
|
||||
|
||||
## Where it's going
|
||||
|
||||
@@ -88,6 +89,7 @@ Summary of the [ROADMAP](ROADMAP.md):
|
||||
|---|---|
|
||||
| **Done** | Monitor mode via netlink (with NetworkManager recovery), 2.4/5/6 GHz scanning, 4-way and PMKID capture, CCMP decryption, dictionary/rules/mask cracking (WPA/WPA2-PSK), `.hc22000` export, `.pcap` read/write, authorized `deauth`/PMF/PMKID, WPS attack, Evil Twin (PSK + Enterprise), channel scoring and findings, paginated audit report, hash-chained audit trail, `doctor`, CLI + desktop app, one-click update |
|
||||
| **Next** | GPU acceleration for cracking, capture on Windows (Npcap) |
|
||||
| **Not planned** | A macOS build — see [Known limits](#known-limits) |
|
||||
| **Later** | WPA3/SAE downgrade, validation on varied hardware, signed release binaries |
|
||||
|
||||
## Development
|
||||
|
||||
+11
-9
@@ -1,6 +1,6 @@
|
||||
<p align="center"><img src="apps/gui/ui/sabia.png" width="300" alt="Sabiá"></p>
|
||||
<h1 align="center">Sabiá</h1>
|
||||
<p align="center">Auditoria de Wi-Fi livre e gratuita.<br>Terminal e interface gráfica · captura no Linux, análise offline em Windows, Linux e macOS · uso autorizado.</p>
|
||||
<p align="center">Auditoria de Wi-Fi livre e gratuita.<br>Terminal e interface gráfica · captura no Linux, análise offline também em Windows · uso autorizado.</p>
|
||||
|
||||
<p align="center"><a href="docs/pt-BR/cli.md">Terminal</a> · <a href="docs/pt-BR/interface.md">Interface</a> · <a href="docs/pt-BR/arquitetura.md">Arquitetura</a> · <a href="ROADMAP.pt-BR.md">Roadmap</a> · <a href="CHANGELOG.pt-BR.md">Changelog</a></p>
|
||||
|
||||
@@ -37,17 +37,18 @@ Baixe o pacote do seu sistema em **[Releases](../../releases)**:
|
||||
|
||||
| | CLI | App gráfico |
|
||||
|---|---|---|
|
||||
| Windows | `sabia-*-windows-x86_64.zip` | instalador `.msi` / `.exe` |
|
||||
| macOS | `sabia-*-macos-{aarch64,x86_64}.tar.gz` | `.dmg` |
|
||||
| Windows | — | instalador `.exe` |
|
||||
| Linux | `sabia-*-linux-{x86_64,aarch64}.tar.gz` | `.AppImage` / `.deb` |
|
||||
|
||||
Cada arquivo tem um `.sha256` ao lado. Compilar do código: `cargo build --release -p sabia-cli` (Rust 1.80+).
|
||||
O CLI é só para Linux; o app desktop sai para Linux e Windows. Cada pacote do
|
||||
CLI tem um `.sha256` ao lado. Compilar do código: `cargo build --release -p
|
||||
sabia-cli` (Rust 1.80+, Linux).
|
||||
|
||||
**Atualizações:** o app desktop consulta o GitHub ao abrir; havendo versão nova, um botão oferece **Atualizar agora**: ele baixa o binário certo para a plataforma, confere o **SHA-256** e troca o executável em uso — você não precisa baixar nada na mão. A consulta é uma única requisição à API de releases e nada seu é enviado.
|
||||
**Atualizações:** o app desktop consulta o Gitea ao abrir; havendo versão nova, um botão oferece **Atualizar agora**. O CLI atualiza do mesmo jeito (`sabia update`); ele baixa o binário certo para a plataforma, confere o **SHA-256** e troca o executável em uso — você não precisa baixar nada na mão. A consulta é uma única requisição à API de releases e nada seu é enviado.
|
||||
|
||||
> Os binários ainda **não são assinados**: o SmartScreen (Windows) e o Gatekeeper (macOS) vão avisar. Confira o SHA-256.
|
||||
> Os binários ainda **não são assinados**: o SmartScreen do Windows vai avisar. Confira o SHA-256.
|
||||
|
||||
**Captura e modo monitor exigem Linux e privilégio de root** (`CAP_NET_ADMIN`/`CAP_NET_RAW`): a captura crua usa `AF_PACKET` e o controle de interface usa netlink. A **análise de `.pcap` e a quebra offline** rodam também em Windows e macOS. O app desktop pede elevação de administrador sozinho ao abrir.
|
||||
**Captura e modo monitor exigem Linux e privilégio de root** — a única plataforma para a qual o CLI é compilado (`CAP_NET_ADMIN`/`CAP_NET_RAW`): a captura crua usa `AF_PACKET` e o controle de interface usa netlink. A **análise de `.pcap` e a quebra offline** rodam também em Windows e macOS. O app desktop pede elevação de administrador sozinho ao abrir.
|
||||
|
||||
## Começando
|
||||
|
||||
@@ -74,11 +75,11 @@ App desktop (Tauri) com sidebar de interfaces, painel de captura com linha de si
|
||||
|
||||
## Limites conhecidos
|
||||
|
||||
- **Captura só no Linux**, com placa que suporte **modo monitor** (e injeção, para `deauth`). Em Windows e macOS o Sabiá faz só análise de `.pcap` e quebra offline.
|
||||
- **Captura só no Linux**, com placa que suporte **modo monitor** (e injeção, para `deauth`); o CLI não é compilado para outras plataformas. Em Windows o app desktop do Sabiá faz só análise de `.pcap` e quebra offline.
|
||||
- **WPA3/SAE** não cai por dicionário de handshake — a quebra cobre **WPA/WPA2-PSK** (4-way e PMKID).
|
||||
- **5 e 6 GHz** dependem da placa e do _regulatory domain_; alguns canais ficam passivos (sem _probe_).
|
||||
- **Certificado autoassinado do Evil Twin Enterprise:** clientes que validam a cadeia de certificado da rede (comum em perfil corporativo/MDM atualizado) não confiam nele — é a defesa correta funcionando, não um bug.
|
||||
- **Windows e macOS:** o código compila e é testado em CI, mas a captura ao vivo não roda nessas plataformas.
|
||||
- **Windows:** o código compila e é testado em CI, mas a captura ao vivo não roda lá; o app desktop faz só análise offline. Não há build para macOS: o Tauri precisa do SDK do macOS e de assinatura, os dois presos a hardware Apple e a uma conta Apple Developer, que o CI deste projeto (um único runner Linux) não tem.
|
||||
|
||||
## Para onde vai
|
||||
|
||||
@@ -88,6 +89,7 @@ Resumo do [ROADMAP](ROADMAP.pt-BR.md):
|
||||
|---|---|
|
||||
| **Feito** | Modo monitor por netlink (com recuperação do NetworkManager), varredura 2.4/5/6 GHz, captura de 4-way e PMKID, decriptação CCMP, quebra por dicionário/regras/máscara (WPA/WPA2-PSK), exportação `.hc22000`, escrita e leitura de `.pcap`, `deauth`/PMF/PMKID autorizados, ataque WPS, Evil Twin (PSK + Enterprise), pontuação de canais e achados, relatório de auditoria paginado, trilha de auditoria por hash, `doctor`, CLI + app desktop, atualização em um clique |
|
||||
| **Próximo** | Aceleração por GPU na quebra, captura em Windows (Npcap) |
|
||||
| **Fora de plano** | Um build para macOS — veja [Limites conhecidos](#limites-conhecidos) |
|
||||
| **Depois** | WPA3/SAE _downgrade_, validação em hardware variado, binários de release assinados |
|
||||
|
||||
## Desenvolvimento
|
||||
|
||||
Generated
+2
-2
@@ -2538,7 +2538,7 @@ checksum = "cf54715a573b99ac80df0bc206da022bcd442c974952c7b9720069370852e21f"
|
||||
|
||||
[[package]]
|
||||
name = "sabia-core"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"aes",
|
||||
"flate2",
|
||||
@@ -2555,7 +2555,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sabia-gui"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"sabia-core",
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
[package]
|
||||
name = "sabia-gui"
|
||||
description = "Sabiá: interface gráfica de auditoria de Wi-Fi"
|
||||
version = "1.0.0"
|
||||
version = "1.0.1"
|
||||
edition = "2021"
|
||||
license = "MIT OR Apache-2.0"
|
||||
repository = "https://github.com/lucasrguerra/sabia"
|
||||
repository = "https://git.lucasrguerra.dev.br/lucasrguerra/sabia"
|
||||
rust-version = "1.80"
|
||||
|
||||
[workspace]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"$schema": "https://schema.tauri.app/config/2",
|
||||
"productName": "Sabia",
|
||||
"version": "1.0.0",
|
||||
"version": "1.0.1",
|
||||
"identifier": "dev.sabia.app",
|
||||
"build": {
|
||||
"frontendDist": "../ui"
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
//! Auto-atualização simples: verifica a última release no GitHub, baixa o
|
||||
//! Auto-atualização simples: verifica a última release no Gitea, baixa o
|
||||
//! binário certo para a plataforma atual, confere o checksum e troca o
|
||||
//! executável em uso — sem o usuário precisar baixar nada manualmente.
|
||||
//!
|
||||
@@ -12,7 +12,13 @@ use std::fs;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
|
||||
const REPO: &str = "lucasrguerra/sabia";
|
||||
/// A API do Gitea devolve o mesmo formato de `releases/latest` que o GitHub devolvia
|
||||
/// (`tag_name`, `assets[].name`, `assets[].browser_download_url`).
|
||||
const LATEST_RELEASE_URL: &str =
|
||||
"https://git.lucasrguerra.dev.br/api/v1/repos/lucasrguerra/sabia/releases/latest";
|
||||
|
||||
/// Página de downloads, para quem usa o app desktop.
|
||||
const RELEASES_PAGE_URL: &str = "https://git.lucasrguerra.dev.br/lucasrguerra/sabia/releases";
|
||||
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Release {
|
||||
@@ -92,8 +98,8 @@ fn asset_suffix_for_platform() -> String {
|
||||
/// Consulta a última release publicada e compara com a versão atual
|
||||
/// (`CARGO_PKG_VERSION` do binário chamador).
|
||||
pub fn check(current_version: &str) -> Result<UpdateStatus> {
|
||||
let url = format!("https://api.github.com/repos/{REPO}/releases/latest");
|
||||
let body = match curl_text(&url) {
|
||||
let url = LATEST_RELEASE_URL;
|
||||
let body = match curl_text(url) {
|
||||
Ok(b) => b,
|
||||
Err(_) => {
|
||||
// Sem rede, ou repositório ainda sem releases publicadas: não é
|
||||
@@ -118,8 +124,22 @@ pub fn check(current_version: &str) -> Result<UpdateStatus> {
|
||||
/// Baixa e aplica a atualização mais recente, substituindo o binário atual.
|
||||
/// Retorna a versão instalada.
|
||||
pub fn apply(current_exe: &PathBuf) -> Result<String> {
|
||||
let url = format!("https://api.github.com/repos/{REPO}/releases/latest");
|
||||
let body = curl_text(&url)?;
|
||||
// O pacote da release contém o CLI (`sabia`). Trocar por ele um executável que
|
||||
// não seja o CLI, como o `sabia-gui`, o deixaria como um CLI e quebraria o app
|
||||
// na próxima abertura. O app desktop se atualiza baixando o instalador.
|
||||
let is_cli = current_exe
|
||||
.file_stem()
|
||||
.map(|stem| stem == "sabia")
|
||||
.unwrap_or(false);
|
||||
if !is_cli {
|
||||
return Err(SabiaError::CommandFailed {
|
||||
cmd: "update".into(),
|
||||
detail: format!(
|
||||
"a atualização automática vale só para o CLI `sabia`; para o app desktop, baixe o instalador em {RELEASES_PAGE_URL}"
|
||||
),
|
||||
});
|
||||
}
|
||||
let body = curl_text(LATEST_RELEASE_URL)?;
|
||||
let release: Release = serde_json::from_str(&body)?;
|
||||
|
||||
let suffix = asset_suffix_for_platform();
|
||||
@@ -225,3 +245,17 @@ fn find_binary(dir: &PathBuf) -> Result<PathBuf> {
|
||||
detail: "binário não encontrado no pacote baixado".into(),
|
||||
})
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn apply_refuses_to_overwrite_the_desktop_app() {
|
||||
// Falha antes de qualquer acesso à rede: o nome do executável já não é o do CLI.
|
||||
let err = apply(&PathBuf::from("/opt/sabia/sabia-gui")).unwrap_err();
|
||||
assert!(err.to_string().contains("só para o CLI"), "{err}");
|
||||
let err = apply(&PathBuf::from("C:/Program Files/Sabia/sabia-gui.exe")).unwrap_err();
|
||||
assert!(err.to_string().contains(RELEASES_PAGE_URL), "{err}");
|
||||
}
|
||||
}
|
||||
Executable
+59
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Compila o app desktop (Tauri) e deixa os pacotes em dist-gui/, com os nomes
|
||||
# que a release usa.
|
||||
#
|
||||
# scripts/build-gui.sh linux # AppImage e .deb; precisa de uma máquina Linux com os pacotes do Tauri
|
||||
# scripts/build-gui.sh windows # instalador NSIS, compilado a partir do Linux
|
||||
#
|
||||
# O Windows usa cargo-xwin (SDK do Windows baixado na hora) e o NSIS, que o Tauri
|
||||
# documenta como compilação cruzada experimental. Precisa de: nsis, lld, llvm,
|
||||
# clang e `cargo install cargo-xwin`. O .msi não sai daqui (o WiX é só do Windows).
|
||||
# `scripts/build-gui.sh windows-docker` roda o mesmo num container, sem instalar nada.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
platform=${1:?uso: build-gui.sh <linux|windows|windows-docker>}
|
||||
tauri() { npx --yes @tauri-apps/cli@2 "$@"; }
|
||||
|
||||
if [ "$platform" = windows-docker ]; then
|
||||
docker volume create sabia-cargo >/dev/null
|
||||
docker volume create sabia-rustup >/dev/null
|
||||
mkdir -p dist-gui
|
||||
exec docker run --rm -v "$PWD":/src -v sabia-cargo:/root/.cargo -v sabia-rustup:/root/.rustup \
|
||||
-w /src -e HOST_UID="$(id -u)" -e HOST_GID="$(id -g)" ubuntu:24.04 bash -c '
|
||||
set -e
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
apt-get update -qq
|
||||
apt-get install -y -qq curl ca-certificates build-essential pkg-config nsis lld llvm clang nodejs npm unzip >/dev/null
|
||||
[ -x /root/.cargo/bin/rustup ] || curl -fsSL https://sh.rustup.rs | sh -s -- -y --profile minimal >/dev/null
|
||||
export PATH=/root/.cargo/bin:$PATH
|
||||
command -v cargo-xwin >/dev/null || cargo install cargo-xwin --locked
|
||||
scripts/build-gui.sh windows
|
||||
chown -R "$HOST_UID:$HOST_GID" dist-gui apps/gui/src-tauri/target 2>/dev/null || true'
|
||||
fi
|
||||
|
||||
mkdir -p dist-gui
|
||||
cd apps/gui/src-tauri
|
||||
|
||||
# Os ícones derivados do original não ficam todos no repositório.
|
||||
[ -f icons/icon.ico ] || tauri icon icons/source.png -o icons
|
||||
|
||||
case "$platform" in
|
||||
linux)
|
||||
tauri build --bundles appimage,deb
|
||||
bundle=target/release/bundle
|
||||
cp "$bundle"/appimage/*.AppImage "$bundle"/deb/*.deb ../../../dist-gui/
|
||||
# O atualizador do Tauri (quando o projeto usa) precisa do .sig ao lado.
|
||||
cp "$bundle"/appimage/*.AppImage.sig ../../../dist-gui/ 2>/dev/null || true
|
||||
;;
|
||||
windows)
|
||||
rustup target add x86_64-pc-windows-msvc >/dev/null
|
||||
tauri build --runner cargo-xwin --target x86_64-pc-windows-msvc --bundles nsis
|
||||
bundle=target/x86_64-pc-windows-msvc/release/bundle/nsis
|
||||
cp "$bundle"/*-setup.exe ../../../dist-gui/
|
||||
cp "$bundle"/*-setup.exe.sig ../../../dist-gui/ 2>/dev/null || true
|
||||
;;
|
||||
*) echo "plataforma desconhecida: $platform" >&2; exit 2 ;;
|
||||
esac
|
||||
|
||||
ls -1 ../../../dist-gui
|
||||
Executable
+39
@@ -0,0 +1,39 @@
|
||||
#!/usr/bin/env bash
|
||||
# Compila o CLI para uma plataforma e empacota como o atualizador espera:
|
||||
# sabia-<tag>-<plataforma>.tar.gz com um .sha256 ao lado.
|
||||
#
|
||||
# scripts/package-cli.sh v1.0.1 linux-x86_64 x86_64-unknown-linux-gnu
|
||||
#
|
||||
# Plataformas: linux-x86_64 e linux-aarch64. O alvo diferente da máquina de build
|
||||
# usa o linker cruzado correspondente (gcc-x86-64-linux-gnu). Escreve os arquivos
|
||||
# na raiz do repositório e imprime os nomes.
|
||||
set -euo pipefail
|
||||
|
||||
cd "$(dirname "$0")/.."
|
||||
|
||||
tag=${1:?uso: package-cli.sh <tag> <plataforma> <alvo-rust>}
|
||||
platform=${2:?uso: package-cli.sh <tag> <plataforma> <alvo-rust>}
|
||||
target=${3:?uso: package-cli.sh <tag> <plataforma> <alvo-rust>}
|
||||
|
||||
case "$target" in
|
||||
x86_64-unknown-linux-gnu)
|
||||
if [ "$(uname -m)" != x86_64 ]; then
|
||||
export CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=x86_64-linux-gnu-gcc
|
||||
export CC_x86_64_unknown_linux_gnu=x86_64-linux-gnu-gcc
|
||||
fi ;;
|
||||
esac
|
||||
|
||||
rustup target add "$target" >/dev/null 2>&1 || true
|
||||
cargo build --release --locked -p sabia-cli --target "$target"
|
||||
|
||||
name="sabia-${tag}-${platform}"
|
||||
rm -rf "$name"; mkdir "$name"
|
||||
cp "${CARGO_TARGET_DIR:-target}/${target}/release/sabia" "$name/"
|
||||
cp README.md LICENSE-MIT LICENSE-APACHE "$name/"
|
||||
|
||||
tar czf "$name.tar.gz" "$name"
|
||||
asset="$name.tar.gz"
|
||||
rm -rf "$name"
|
||||
sha256sum "$asset" > "$asset.sha256"
|
||||
echo "$asset"
|
||||
echo "$asset.sha256"
|
||||
Executable
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env bash
|
||||
# Imprime as notas de uma release: a seção do CHANGELOG.md daquela versão, ou o
|
||||
# log de commits desde a tag anterior quando o changelog não tem a seção.
|
||||
#
|
||||
# scripts/release-notes.sh v1.2.3
|
||||
set -euo pipefail
|
||||
|
||||
tag=${1:?uso: release-notes.sh <tag>}
|
||||
version=${tag#v}
|
||||
|
||||
section=""
|
||||
if [ -f CHANGELOG.md ]; then
|
||||
section=$(awk -v head="## [$version]" '
|
||||
index($0, head) == 1 { found = 1; next }
|
||||
found && /^## \[/ { exit }
|
||||
found && /^\[[^]]+\]: / { next }
|
||||
found { print }
|
||||
' CHANGELOG.md)
|
||||
fi
|
||||
|
||||
if [ -n "$(printf '%s' "$section" | tr -d '[:space:]')" ]; then
|
||||
printf '%s\n' "$section"
|
||||
else
|
||||
previous=$(git describe --tags --abbrev=0 "$tag^" 2>/dev/null || true)
|
||||
echo "## Mudanças${previous:+ desde $previous}"
|
||||
echo
|
||||
git log --no-merges --format='- %s (%h)' "${previous:+$previous..}$tag"
|
||||
fi
|
||||
Executable
+24
@@ -0,0 +1,24 @@
|
||||
#!/usr/bin/env bash
|
||||
# Anexa arquivos a uma release do Gitea, trocando os de mesmo nome (assim uma
|
||||
# execução repetida do CI não falha por anexo duplicado).
|
||||
#
|
||||
# API=https://git.exemplo.com/api/v1/repos/dono/repo TOKEN=... \
|
||||
# scripts/release-upload.sh v1.2.3 arquivo1 arquivo2
|
||||
set -euo pipefail
|
||||
|
||||
: "${API:?defina API (URL do repositório na API do Gitea)}"
|
||||
: "${TOKEN:?defina TOKEN}"
|
||||
tag=${1:?uso: release-upload.sh <tag> <arquivo>...}
|
||||
shift
|
||||
|
||||
auth=(-H "Authorization: token $TOKEN")
|
||||
id=$(curl -fsS "${auth[@]}" "$API/releases/tags/$tag" | jq -r .id)
|
||||
|
||||
for file in "$@"; do
|
||||
name=$(basename "$file")
|
||||
for old in $(curl -fsS "${auth[@]}" "$API/releases/$id/assets" | jq -r --arg n "$name" '.[] | select(.name == $n) | .id'); do
|
||||
curl -fsS -X DELETE "${auth[@]}" "$API/releases/$id/assets/$old"
|
||||
done
|
||||
curl -fsS -X POST "${auth[@]}" -F "attachment=@$file" "$API/releases/$id/assets?name=$name" >/dev/null
|
||||
echo "enviado: $name"
|
||||
done
|
||||
Reference in new issue
Block a user