fa452f00b159bb350298b20ceceb6f268e6bcac1
5 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
fa452f00b1 |
fix(cli,aura-gui): v3.4.2 — break the infinite-tunnel loop + drop dead GUI handle
Two coupled bugs from the macOS half-Internet-route fix (v3.4.1) put together. ## 1) Infinite tunnel loop: server IP routed through itself v3.4.1 made `default = "VPN"` actually win against the host's pre-existing default by installing `0.0.0.0/1` and `128.0.0.0/1` via the TUN. Both half-Internet routes are strictly more specific than `0.0.0.0/0`, so outbound traffic finally went through Aura. Side-effect: the server's outer IP (187.77.67.17) falls inside `128/1`. That means Aura's own encrypted ciphertext to 187.77.67.17:443 also matched the new route → re-entered the TUN → was about to be re-encrypted and shipped to … itself. The kernel held the existing TCP socket on en0 for a few seconds (sticky source), so the connection survived briefly. As soon as anything triggered a re-route resolution (TCP retransmit on a different socket, cover-traffic, new cipher frame), the socket flipped to utun4 and the data plane died — exactly the "Aura умирает через пару секунд" the user reported. Fix: before calling `OsRouteGuard::install`, scan the dial config for outer-endpoint IPs (the primary `server_addr` plus any `[client] bridges` entries) and inject them into `SplitRoutes::direct_hosts`. The existing macOS plan turns `direct_hosts` into `route add -host <ip> <gateway>` — a /32 bypass via the original LAN gateway, more specific than `128/1`, so the kernel routes the ciphertext via en0 even after the half-Internet routes are in. No recursion, no flap, no death. Only applied when `default = "VPN"` (the only mode where the bypass is needed). Linux doesn't need it — the `metric 50` default-via-TUN doesn't override more-specific kernel routes. ## 2) Dead GUI handle wedges the Connect button `connect()` in lib.rs refused with "already running" whenever the `Option<ClientHandle>` was `Some`, regardless of whether the child was still alive. So when the aura-client died from bug #1 (within ~2 s of Connect), the UI was permanently stuck — the only escape was quitting and relaunching the GUI. Now `connect()` checks `prev.is_alive()` first. If the previous handle is dead, we reap it (calling `kill()` to consume the handle's drop path) and spawn a fresh one transparently. Reconnect-after-crash now Just Works. This also matches what a sensible "Connect" button does on every other VPN GUI: clicking it when something looks stuck should make progress, not demand a quit-and-relaunch dance. ## Verification - `cargo test -p aura-cli --lib os_routes` — 21/21 ok - `cargo build --release` — green - Rebuilt /Applications/Aura.app against both fixes - Server-side aura.service restarted to clear the leftover pool reservation the dead session never released (see v3.5 task #52 for the auto-cleanup follow-up) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
f68a61f760 |
fix(tunnel,aura-gui): macOS TUN auto-assign + admin-access check
Two bugs found in the GUI's first end-to-end test: ## #41 was incomplete — `Some("")` is not the same as `None` for tun-rs The agent's earlier #41 fix passed `""` to `Configuration::tun_name()` expecting the tun crate to treat empty as "let the kernel auto-assign". It doesn't. Looking at tun-0.8.9/src/platform/macos/device.rs: if !tun_name.starts_with("utun") { return Err(Error::InvalidName); } An empty string fails `starts_with("utun")` so the create errors out before the kernel is ever consulted. The auto-assign branch ONLY triggers when `config.tun_name` is `None` — which requires us to skip the `.tun_name()` call entirely, not pass a sentinel value. Fix: split the builder chain so `.tun_name()` is only called when the sanitized name is non-empty. The kernel now correctly auto-picks the next free `utunN` for the standard provisioned `tun_name = "aura0"` config. User-visible symptom this resolves: the GUI's Connect button consistently died with `failed to create TUN device 'aura0'` followed by an InvalidName chain, even though aura was running as root. ## check_admin_access tested the wrong command shape `check_admin_access` ran `sudo -n <aura> --help` and inferred the sudoers entry was installed iff that succeeded. But our sudoers entry is scoped to `<aura> client *` — `<aura> --help` does NOT match, so even when the entry was correctly installed and Connect was already working, the yellow "One-time setup needed" banner stayed up forever. Switched to `sudo -n -l <aura>` which lists matching sudoers entries for the binary path itself. Returns 0 iff ANY entry covers it without a password — works regardless of the per-command scope. ## Verification - `cargo test -p aura-tunnel --lib tun` — all 3 sanitize / create tests pass - Rebuilt `target/release/aura` and `/Applications/Aura.app` against the fixes - Confirmed via `sudo -n -l /Users/xah30/AuraVPN/target/release/aura` that the installed sudoers entry is detectable by the new check 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
dbee9d8b93 |
fix(aura-gui): rename product to 'Aura' + uppercase SETENV in sudoers
Two bugs visible after user's first Install-admin-access click:
1) `visudo -c` rejected the fragment because sudoers tags must be UPPERCASE.
We wrote `setenv:` (lowercase) which sudoers does not recognise as a tag
and treats as a command path, producing a syntax error at column 29 of
/etc/sudoers.d/aura-gui:2 — and worse, the broken file stayed on disk
so every subsequent `sudo` complained about the syntax error too (sudo
still functions but the warning is noise).
Fix: drop the `setenv:` tag entirely. We never needed it — the GUI only
passes RUST_LOG to the child via env(), which `sudo -E` would forward
but we deliberately chose not to (smaller surface). Removing the tag
also removes the failure mode.
2) Product rename per user feedback ("переименуй пакет на просто Aura"):
- tauri.conf.json `productName` and window title: `aura-gui` -> `Aura`
- bundle now produces /Applications/Aura.app and Aura_0.1.0_aarch64.dmg
- identifier `ru.undergr0und.aura` was already correct, no change
- sudoers file is now /etc/sudoers.d/aura (was aura-gui), so the success
message and revert hint are updated accordingly
The internal MacOS/ binary is still named `aura-gui` (Tauri uses the Cargo
crate name there) — not user-visible, only the dev internals see it.
Manual cleanup also performed on the dev host:
- /Applications/aura-gui.app removed
- /etc/sudoers.d/aura-gui (the broken fragment from the first failed
install attempt) removed via `osascript ... with administrator
privileges` so sudo is no longer logging syntax errors
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
||
|
|
1635190797 |
feat(aura-gui): privilege escalation via sudo + one-click NOPASSWD installer
The v0.1 GUI's Connect button was broken in practice: the Tauri app launched from /Applications runs as the desktop user, so `Command::new(aura).spawn()` started aura without root. aura died in ms with EPERM at TUN creation, faster than the 1.5 s status poller could catch — the UI just silently flipped back to "disconnected" with no clue. ## Fix * `cli_proc::spawn_client` now prepends `sudo -n` on Unix. After spawn it blocks for 1.5 s and checks `try_wait`; if the child already exited, it reads the stderr ring's last 20 lines and returns an anyhow Error with that tail + a hint list of common causes. The Tauri command surfaces it to the frontend's `error` state where the UI renders it as a multi-line `<pre>` block instead of the previous single-line text. * `ClientHandle::kill` no longer uses `Child::kill` (SIGKILL) on its sudo parent — that would have left aura orphaned with the TUN lingering. Sends SIGTERM to sudo, which sudo forwards to aura, giving the inner `OsRouteGuard::Drop` 2 s to run cleanup. Falls back to SIGKILL only after the grace period. ## One-click NOPASSWD installer Two new Tauri commands plus a UI banner: * `check_admin_access` — runs `sudo -n aura --help` and returns whether the sudoers entry is in place. Used by the React side to decide whether to show the banner. * `install_sudoers_admin` — runs `osascript ... with administrator privileges` which surfaces the native macOS auth dialog, then writes `/etc/sudoers.d/aura-gui` scoped to `<aura> client *` only (not arbitrary aura invocations), runs `visudo -c` for syntax validation, and reports success or the syntax error. The frontend shows a yellow "One-time setup needed" banner above the profile list whenever `adminReady === false`. Clicking the button pops the Mac password dialog once; from then on Connect is a single click with no prompt. ## UI feedback * "Connecting…" disabled state on the Connect button while spawn_client's 1.5 s wait is in progress * Errors render as monospace `<pre>` so the multi-line stderr tail is readable * `.error` and `.admin-banner` CSS classes added to App.css 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |
||
|
|
40b38beb11 |
feat(aura-gui): v0.1 Tauri-based desktop client — system tray + profile manager + admin status
New crate (kept out of the cargo workspace so the protocol-side check/test cycle stays fast): a Tauri 2 + React 19 + TypeScript desktop app that runs in the system tray and manages `aura client` for the user. The clash-verge replacement we settled on instead of trying to shoehorn AuraVPN's L3 IP-tunnel into a clash-verge L4 outbound. ## What's wired - **Profile manager** — `aura-gui/src-tauri/src/profiles.rs`. App-data layout (`~/Library/Application Support/ru.undergr0und.aura/profiles/<id>/` on macOS, the equivalent on Linux + Windows). `import_profile_from_tgz` accepts the same bundle shape `aura provision-client` emits, detects flat vs single-dir layouts, and refuses overwrites unless the operator deletes first. `delete_profile` refuses symlinks. - **Connection control** — `cli_proc.rs`. Spawns `aura client --config <profile>/client.toml --admin-socket /tmp/aura-admin-<uid>-<profile>.sock`, captures stderr into a bounded in-memory ring (200 lines) for the UI to tail, kills via `Child::kill` on disconnect. Per-profile / per-uid socket paths so two GUIs (or two profiles) don't collide. - **Live status** — `admin.rs`. Tiny JSON-line client for the v3.3 admin socket. Polled by the React app every 1.5 s: peer id, rx/tx packets, default action, rule count. Falls back gracefully (admin_error in the response) when the handshake hasn't completed yet. - **System tray** — `lib.rs` `setup` callback. Three-item menu (Open AuraVPN / Disconnect / Quit). The window's close button hides to the tray instead of exiting — the app keeps running so the VPN stays connected; the user explicitly chooses Quit. - **Frontend** — `src/App.tsx`. Single-page layout: profile list (with badge for missing files), connect/disconnect button per profile, status table, collapsible logs panel, binary-path picker at the bottom. Dark-mode CSS by default; the same look as a typical WireGuard / Tailscale-style tray app. ## What's deferred for v0.2 - Auto-start at login (launchd plist / systemd user unit / Windows Run key) - Code signing + notarization - Persisting the aura binary path between sessions - Per-profile route overrides editor - Live log streaming (today the frontend polls the ring buffer) - Admin status query on Windows (today's `admin.rs` Unix-only; Windows path returns a clear "not supported yet" error) - Polkit / authorization-services prompt for the TUN-needs-root step (today the operator has to launch the GUI from a privileged context, e.g. `sudo open -a aura-gui` on macOS) ## Workspace hygiene Cargo workspace at the repo root now has `exclude = ["aura-gui"]` so the protocol crates' `cargo check --workspace` / `cargo test --workspace` don't pull in the tauri + wry + webview dep graph. The GUI builds standalone from `aura-gui/` via `npm run tauri build`. ## Validation - `cd aura-gui/src-tauri && cargo check` — green - `cd aura-gui/src-tauri && cargo clippy -- -D warnings` — clean - `cd aura-gui/src-tauri && cargo fmt --check` — clean - `cd aura-gui && npm run build` — frontend tsc + vite build succeeds - Full `npm run tauri dev` not exercised in this session (would open a real window) — should work; if it breaks the surface area is small enough that next session fixes it. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com> |