Merge branch 'feature/phase-8-gui-keys'
Phase 8: GUI Keys tab. Lists current user's enrolled FIDO2 credentials, enrolls a new key with a touch-prompt modal driven by the daemon's EnrollmentFailed signal (success comes from the call return), removes credentials per row, degrades gracefully to a Retry banner when the daemon is unreachable, and surfaces transient errors via adw::Toast. 8 tasks, 4 unit tests (error classifier).
This commit is contained in:
@@ -4,12 +4,15 @@
|
||||
|
||||
**Goal:** Land a working `authforge` GUI that lists the current user's enrolled FIDO2 credentials, enrolls a new key with a touch-prompt modal driven by the daemon's `EnrollmentSucceeded`/`EnrollmentFailed` signals, removes a credential, and degrades gracefully when the daemon is unreachable.
|
||||
|
||||
**Architecture:** Single-window GTK4 + libadwaita app on the user's session, talking to the daemon on the **system bus** at `io.dangerousthings.AuthForge / /io/dangerousthings/AuthForge / io.dangerousthings.AuthForge1`. zbus uses its **glib** integration (`features = ["glib"]`) instead of the workspace tokio config, so all async runs on the GTK main thread via `glib::MainContext::spawn_local`. No tokio dep in the GUI process.
|
||||
**Architecture:** Single-window GTK4 + libadwaita app on the user's session, talking to the daemon on the **system bus** at `io.dangerousthings.AuthForge / /io/dangerousthings/AuthForge / io.dangerousthings.AuthForge1`. zbus uses the workspace tokio runtime; a multi-thread tokio runtime is installed at app startup and its enter-guard is held for the lifetime of `app.run()`. Closures that touch widgets dispatch async work via `glib::MainContext::spawn_local`, which polls the future on the GTK main thread; tokio's reactor (running on its own worker threads) wakes the future when zbus I/O is ready, and glib re-polls.
|
||||
|
||||
> **Plan note (2026-04-27):** an earlier draft of this plan claimed zbus 4 has a `glib` feature for runtime integration. It does not — zbus 4.4's features are `async-io` (default), `tokio`, `bus-impl`, `chrono`, `p2p`, `time`, `url`, `uuid`, `vsock`. We use `tokio` to match the rest of the workspace.
|
||||
|
||||
**Tech Stack:**
|
||||
- `gtk4-rs` 0.8 (already pinned in `gui/Cargo.toml`).
|
||||
- `libadwaita` 0.6 (already pinned).
|
||||
- `zbus = { version = "4", default-features = false, features = ["glib"] }` — **not** `workspace = true`; the workspace dep is tokio-flavored and would conflict.
|
||||
- `zbus = { workspace = true }` — workspace config is `default-features = false, features = ["tokio", "p2p"]`.
|
||||
- `tokio = { workspace = true }` — needed for the runtime guard that hosts zbus's tokio executor.
|
||||
- `authforge-common = { path = "../common" }` for the shared `Credential` wire type.
|
||||
|
||||
**Reference:**
|
||||
@@ -38,18 +41,20 @@
|
||||
**Step 1:** Append to `gui/Cargo.toml` `[dependencies]`:
|
||||
|
||||
```toml
|
||||
zbus = { version = "4", default-features = false, features = ["glib"] }
|
||||
zbus = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
futures-util = { workspace = true }
|
||||
```
|
||||
|
||||
(Do **not** use `workspace = true`. The workspace zbus is tokio-flavored — the GUI needs the glib runtime feature, which is mutually exclusive at the zbus crate level.)
|
||||
The tokio runtime guard installed in Task 4 (`main.rs`) is what makes zbus's tokio-flavored futures actually run when `glib::MainContext::spawn_local` polls them. `futures-util` shows up here so Task 6's `select!`-style race in `enroll_dialog.rs` doesn't need a follow-up Cargo.toml edit.
|
||||
|
||||
**Step 2:** `cargo build -p authforge-gui`. Expected: clean compile (no usages yet, but the dep resolves).
|
||||
**Step 2:** `cargo build -p authforge-gui`. Expected: clean compile (no usages yet, but the deps resolve).
|
||||
|
||||
**Step 3:** Commit.
|
||||
|
||||
```bash
|
||||
git add gui/Cargo.toml Cargo.lock
|
||||
git commit --no-gpg-sign -m "chore(gui): add zbus glib feature for D-Bus client"
|
||||
git commit --no-gpg-sign -m "chore(gui): add zbus + tokio + futures-util deps for D-Bus client"
|
||||
```
|
||||
|
||||
---
|
||||
@@ -357,6 +362,16 @@ mod keys_page;
|
||||
const APP_ID: &str = "io.dangerousthings.AuthForge";
|
||||
|
||||
fn main() -> glib::ExitCode {
|
||||
// Multi-thread tokio runtime hosts zbus's tokio-flavored futures. The
|
||||
// `_guard` keeps the runtime context active on this thread so calls like
|
||||
// `zbus::Connection::system().await` from within `glib::MainContext::
|
||||
// spawn_local` closures don't panic with "no current reactor".
|
||||
let runtime = tokio::runtime::Builder::new_multi_thread()
|
||||
.enable_all()
|
||||
.build()
|
||||
.expect("build tokio runtime");
|
||||
let _guard = runtime.enter();
|
||||
|
||||
let app = adw::Application::builder().application_id(APP_ID).build();
|
||||
app.connect_activate(|app| {
|
||||
let win = adw::ApplicationWindow::builder()
|
||||
@@ -624,13 +639,7 @@ fn show_failure(dialog: &adw::AlertDialog, msg: &str) {
|
||||
}
|
||||
```
|
||||
|
||||
**Step 3:** Add `futures-util` to `gui/Cargo.toml`:
|
||||
|
||||
```toml
|
||||
futures-util = { workspace = true }
|
||||
```
|
||||
|
||||
**Step 4:** Replace the `start_enroll` body in `gui/src/keys_page.rs`:
|
||||
**Step 3:** Replace the `start_enroll` body in `gui/src/keys_page.rs`:
|
||||
|
||||
```rust
|
||||
async fn start_enroll(self: &Rc<Self>) {
|
||||
@@ -648,12 +657,12 @@ futures-util = { workspace = true }
|
||||
}
|
||||
```
|
||||
|
||||
**Step 5:** `cargo build -p authforge-gui && cargo clippy -p authforge-gui --all-targets -- -D warnings`. Clean.
|
||||
**Step 4:** `cargo build -p authforge-gui && cargo clippy -p authforge-gui --all-targets -- -D warnings`. Clean.
|
||||
|
||||
**Step 6:** Commit.
|
||||
**Step 5:** Commit.
|
||||
|
||||
```bash
|
||||
git add gui/src/enroll_dialog.rs gui/src/keys_page.rs gui/src/main.rs gui/Cargo.toml Cargo.lock
|
||||
git add gui/src/enroll_dialog.rs gui/src/keys_page.rs gui/src/main.rs
|
||||
git commit --no-gpg-sign -m "feat(gui): TouchDialog modal racing EnrollOwn call against EnrollmentFailed signal"
|
||||
```
|
||||
|
||||
|
||||
Reference in New Issue
Block a user