diff --git a/.github/workflows/verify-ezvpn-commit.yml b/.github/workflows/verify-ezvpn-commit.yml index 52288a9..3c0bdb2 100644 --- a/.github/workflows/verify-ezvpn-commit.yml +++ b/.github/workflows/verify-ezvpn-commit.yml @@ -17,7 +17,7 @@ on: ezvpn_ref: description: "ezvpn git ref (commit SHA / branch / tag) to build against" required: true - default: "b41e190b130251cd20230d020bc79c6e7285b7a4" + default: "6f7d3475cb4032be31c7ededbb606faba60e3547" ezvpn_repo: description: "ezvpn repository (owner/name)" required: true diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..633b9f0 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,73 @@ +# ezvpn-windows — notes for Claude + +Native Windows GUI (WinUI 3, .NET) for the `ezvpn` VPN. Sibling of `ezvpn-apple`. +The Rust core + C FFI live in the `../ezvpn` repo (`src/ffi_windows.rs`, +`windows/ezvpn.h`, `build-windows.ps1`, `docs/Windows-App.md`). + +## Key facts + +- Strict no backward compatibility (0.0.x) or legacy code paths +- The transport is iroh (Rust-only) — never reimplement the protocol in .NET. + The app P/Invokes `ezvpn.dll` (`ezvpn_start` / `ezvpn_status` / `ezvpn_stop`). +- Single elevated process: app manifest requests Administrator; the tunnel runs + in-process (no service, no IPC). `wintun.dll` must be beside `ezvpn.dll`. +- `Ezvpn.Core` is `net8.0` and pure (unit-tested). `Ezvpn.App` is + `net10.0-windows…` WinUI 3, needs a RID to build (defaults to `win-x64`). +- Build the whole solution with `dotnet build ezvpn-windows.slnx` (no `-r` — the + app has a default RID; passing `-r` to a *solution* is rejected by the SDK). +- Native DLLs are runtime-only, so the app compiles/tests without them. They are + copied into output for running/packaging (from `native/`, or from + `..\ezvpn\dist\windows` when `EZVPN_LOCAL_DLL=1`). +- **To check a change on Windows, run `pwsh ci/windows/remote.ps1`.** From the + macOS dev box (where none of this builds) it ships the *working tree* — + uncommitted changes included — to the Hyper-V VM (`windows-ci-build`, shared + with `../wrustic`) and runs build, test, publish and MSI there. `remote.ps1 + doctor` reports the VM's toolchain, `remote.ps1 provision` (re)installs it. + See `docs/windows-vm-ci.md`. +- Do **not** reach for `.github/workflows/windows-ci.yml` to find out whether + something works: it needs a commit and a push to trigger, and it is slow even + warm, because a GitHub runner starts with a cold NuGet cache every time. It + runs itself on push/PR — read it after the fact, don't drive it. + `ci\windows\ci.ps1` is the same four steps on the VM, with a warm NuGet cache; + when the two disagree, the workflow is right and `ci.ps1` is stale. + +## Conventions + +- The `ezvpn_start` config JSON shape is defined in `../ezvpn/windows/ezvpn.h`; + `EzvpnConfig.Build` produces it. Keep them in sync. +- `ClientStatus` mirrors the Rust `ClientStatus` (snake_case) from + `../ezvpn/src/control.rs`. +- The client authenticates with an **ed25519 keypair**, not a pre-shared token: + the config's `auth_key` is the client's `ed25519-sec:…` secret, and its public + half goes on the server's `authorized_keys` file. Keys are generated and parsed + only through the FFI (`ezvpn_generate_client_key` / `ezvpn_client_public_key`, + wrapped by `Core/Interop/AuthKey`) — never reimplement the key format in .NET. +- Like the Apple and Android apps, the app keeps one shared list of **named** + keys (`AuthKeyStore`) that profiles reference by id (`TunnelProfile.AuthKeyId`); + saving a profile copies that key's secret into the profile's own credential, + which is what `ezvpn_start` is handed. So a key deleted from the list doesn't + break profiles already saved with it. +- All secrets live in Windows Credential Manager (`SecretStore`), never in the + profile JSON: `ezvpn-profile-key:` (the profile's auth key), + `ezvpn-relay:` (the optional relay token) and `ezvpn-key:` + (one record per named key — one credential each, because a credential blob caps + out at 2560 bytes). +- Installer uses **WiX v5** (v6/v7 require accepting the paid OSMF EULA). The MSI + is unsigned by design; code signing and MSIX/Store packaging are out of scope. +- Use classic `[DllImport]` (not `[LibraryImport]`) for the `advapi32` + Credential Manager calls — the `CREDENTIAL` struct isn't source-gen + marshallable. +- Icons: `assets\icon.svg` (the shield/keyhole glyph, shared with ezvpn-apple) is + the source of truth. `scripts\render-icons.ps1` renders it to the committed + `src\Ezvpn.App\Assets\ezvpn.ico` (teal, multi-size) plus a gray + `ezvpn-gray.ico` via GDI+ — re-run it (needs Windows PowerShell 5.1) only when + the SVG changes; CI just uses the committed `.ico`s. The teal `ezvpn.ico` is + the `.exe` icon (``) and the title-bar icon + (`AppWindow.SetIcon`); the tray shows `ezvpn-gray.ico` until the tunnel is + connected, then swaps to the teal one. +- The system tray (`Services\TrayIcon.cs`) is hand-rolled on `Shell_NotifyIcon` + (WinUI 3 has no tray API): it subclasses the window's WndProc for callbacks and + uses a native `TrackPopupMenuEx` menu. Closing the window hides to the tray; + only the tray's Quit exits the process. `SetConnected(bool)` swaps between the + teal (connected) and gray (not-connected) icons; `MainWindow` drives it from + the active tunnel's connection state. diff --git a/CLAUDE.md b/CLAUDE.md index 9c8c533..eef4bd2 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,59 +1 @@ -# ezvpn-windows — notes for Claude - -Native Windows GUI (WinUI 3, .NET) for the `ezvpn` VPN. Sibling of `ezvpn-apple`. -The Rust core + C FFI live in the `../ezvpn` repo (`src/ffi_windows.rs`, -`windows/ezvpn.h`, `build-windows.ps1`, `docs/Windows-App.md`). - -## Key facts - -- The transport is iroh (Rust-only) — never reimplement the protocol in .NET. - The app P/Invokes `ezvpn.dll` (`ezvpn_start` / `ezvpn_status` / `ezvpn_stop`). -- Single elevated process: app manifest requests Administrator; the tunnel runs - in-process (no service, no IPC). `wintun.dll` must be beside `ezvpn.dll`. -- `Ezvpn.Core` is `net8.0` and pure (unit-tested). `Ezvpn.App` is - `net10.0-windows…` WinUI 3, needs a RID to build (defaults to `win-x64`). -- Build the whole solution with `dotnet build ezvpn-windows.slnx` (no `-r` — the - app has a default RID; passing `-r` to a *solution* is rejected by the SDK). -- Native DLLs are runtime-only, so the app compiles/tests without them. They are - copied into output for running/packaging (from `native/`, or from - `..\ezvpn\dist\windows` when `EZVPN_LOCAL_DLL=1`). -- **To check a change on Windows, run `pwsh ci/windows/remote.ps1`.** From the - macOS dev box (where none of this builds) it ships the *working tree* — - uncommitted changes included — to the Hyper-V VM (`windows-ci-build`, shared - with `../wrustic`) and runs build, test, publish and MSI there. `remote.ps1 - doctor` reports the VM's toolchain, `remote.ps1 provision` (re)installs it. - See `docs/windows-vm-ci.md`. -- Do **not** reach for `.github/workflows/windows-ci.yml` to find out whether - something works: it needs a commit and a push to trigger, and it is slow even - warm, because a GitHub runner starts with a cold NuGet cache every time. It - runs itself on push/PR — read it after the fact, don't drive it. - `ci\windows\ci.ps1` is the same four steps on the VM, with a warm NuGet cache; - when the two disagree, the workflow is right and `ci.ps1` is stale. - -## Conventions - -- The `ezvpn_start` config JSON shape is defined in `../ezvpn/windows/ezvpn.h`; - `EzvpnConfig.Build` produces it. Keep them in sync. -- `ClientStatus` mirrors the Rust `ClientStatus` (snake_case) from - `../ezvpn/src/control.rs`. -- Auth tokens live in Windows Credential Manager (`TokenStore`), never in the - profile JSON. -- Installer uses **WiX v5** (v6/v7 require accepting the paid OSMF EULA). The MSI - is unsigned by design; code signing and MSIX/Store packaging are out of scope. -- Use classic `[DllImport]` (not `[LibraryImport]`) for the `advapi32` - Credential Manager calls — the `CREDENTIAL` struct isn't source-gen - marshallable. -- Icons: `assets\icon.svg` (the shield/keyhole glyph, shared with ezvpn-apple) is - the source of truth. `scripts\render-icons.ps1` renders it to the committed - `src\Ezvpn.App\Assets\ezvpn.ico` (teal, multi-size) plus a gray - `ezvpn-gray.ico` via GDI+ — re-run it (needs Windows PowerShell 5.1) only when - the SVG changes; CI just uses the committed `.ico`s. The teal `ezvpn.ico` is - the `.exe` icon (``) and the title-bar icon - (`AppWindow.SetIcon`); the tray shows `ezvpn-gray.ico` until the tunnel is - connected, then swaps to the teal one. -- The system tray (`Services\TrayIcon.cs`) is hand-rolled on `Shell_NotifyIcon` - (WinUI 3 has no tray API): it subclasses the window's WndProc for callbacks and - uses a native `TrackPopupMenuEx` menu. Closing the window hides to the tray; - only the tray's Quit exits the process. `SetConnected(bool)` swaps between the - teal (connected) and gray (not-connected) icons; `MainWindow` drives it from - the active tunnel's connection state. +@AGENTS.md \ No newline at end of file diff --git a/Directory.Build.props b/Directory.Build.props index 403e222..d726483 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -10,7 +10,7 @@ monotonically increasing build-timestamp value so MajorUpgrade keeps working (see installer/Ezvpn.Installer.wixproj and .github/workflows/release.yml). --> - 0.0.36 + 0.0.43 diff --git a/README.md b/README.md index 74c73a5..c58951b 100644 --- a/README.md +++ b/README.md @@ -37,7 +37,7 @@ See `docs/Windows-App.md` in the `ezvpn` repo for the FFI contract. | Project | What | |---|---| | `src/Ezvpn.Core` | Pure model + config JSON builder + validation + status DTOs + the `ezvpn.dll` P/Invoke wrapper (`EzvpnSession`). No WinUI; unit-tested. | -| `src/Ezvpn.App` | The WinUI 3 app: profile list/detail/edit, connect/disconnect, live status polling. Stores profiles under `%ProgramData%\ezvpn\profiles` and the auth token in Windows Credential Manager. | +| `src/Ezvpn.App` | The WinUI 3 app: profile list/detail/edit, the auth-key manager, connect/disconnect, live status polling. Stores profiles under `%ProgramData%\ezvpn\profiles` and every secret in Windows Credential Manager. | | `tests/Ezvpn.Core.Tests` | xUnit tests for the pure logic. | | `installer/` | WiX v5 MSI that bundles the published app + `ezvpn.dll` + `wintun.dll`. | @@ -164,8 +164,20 @@ involved. ## Usage 1. Launch ezvpn (accept the UAC prompt). -2. **+** to add a profile: give it a name, the server's iroh node id, the auth - token (required), and optional split-tunnel routes (`10.0.0.0/8`, `fd00::/8`, …). -3. Select it and **Connect**. The status panel shows the assigned IP, gateway, +2. Add an **auth key** (the key button in the left toolbar, or *Manage keys…* in + the profile editor): name it and leave the secret blank to generate a fresh + ed25519 keypair — or paste an `ed25519-sec:…` secret from another device to + reuse that identity. Copy the key's **public** half onto the server's + `authorized_keys` file; the secret never leaves the machine except through the + explicit copy action. +3. **+** to add a profile: give it a name, the server's iroh node id, the auth key + to authenticate with (required), and optional split-tunnel routes + (`10.0.0.0/8`, `fd00::/8`, …). +4. Select it and **Connect**. The status panel shows the assigned IP, gateway, routes, and the live iroh connection path once connected. -4. **Disconnect** tears down the tunnel and routes. +5. **Disconnect** tears down the tunnel and routes. + +Keys are shared across profiles: several profiles can authenticate with the same +device identity. A profile keeps its own copy of the secret it was saved with, so +deleting a key from the list doesn't break profiles already using it — but they +can't be re-saved until a key is picked again. diff --git a/native/native.targets b/native/native.targets index e33014e..af238e7 100644 --- a/native/native.targets +++ b/native/native.targets @@ -29,9 +29,9 @@ once an ezvpn release that includes the build-windows-lib asset exists. scripts\bump-dll.ps1 also mirrors this tag (minus "v") into EzvpnVersion in Directory.Build.props, which is the version the app UI + MSI report. --> - v0.0.36 + v0.0.43 https://github.com/flexaccessdev/ezvpn/releases/download/$(EzvpnReleaseTag)/ezvpn-windows.dll.zip - d51ecf7b0df94ad3347121c220c4735caf52fd2b7a0d5b77e7c81436b20c8d78 + 792d01e125058aebe0f73b3af54f8e6bab3d29246b51ec1abb40162bb2516f75 + + + + + + + + + + + + + + + + + + + + + + + + + +