M3: working desktop app + browser pairing channel

- Builds and runs (tauri build --debug); placeholder icons; persistent VaultCore::open in the
  OS app-data dir; Secret Key remembered on the device; tray keeps the app serving the extension.
- Auto-lock: idle (system idle on Windows/macOS, in-app activity on Linux), screen lock, sleep.
- Local IPC for kestrove-nmh: 0700 dir + 0600 Unix socket with peer-uid checks; Windows named
  pipe (first instance, local only, user DACL, client SID check) behind cfg.
- Pairing channel: X25519 → HKDF → 6-word fingerprint confirmed in both UIs, per-connection
  session keys, AES-256-GCM with strict counters. Test vectors shared with kestrove-browser.
- Broker: query/fill/totp/save with origin re-checks; pairing and save prompts in the UI.
- kestrove-nmh relays ciphertext only; native-host installers for Linux/macOS/Windows.
- Tests: unit tests, tests/nmh_stdio.rs (real kestrove-nmh over stdio), examples/test-host.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-16 20:13:54 +09:00
co-authored by Claude Opus 5.5
parent 30cdcee3d2
commit 923c466dea
44 changed files with 9289 additions and 270 deletions
+39 -1
View File
@@ -6,6 +6,11 @@ rust-version = "1.82"
license = "Apache-2.0"
publish = false
# Shared by the app, the native-messaging host and the integration tests.
[lib]
name = "kestrove_desktop"
path = "src/lib.rs"
[[bin]]
name = "kestrove-desktop"
path = "src/main.rs"
@@ -21,10 +26,43 @@ tauri-build = { version = "2", features = [] }
[dependencies]
# Repos are checked out side by side (see ../../README.md).
kv-ffi = { path = "../../kestrove-core/crates/kv-ffi" }
tauri = { version = "2", features = [] }
tauri = { version = "2", features = ["tray-icon"] }
serde = { version = "1", features = ["derive"] }
serde_json = "1"
arboard = "3"
# Browser pairing channel (docs/05): X25519 + HKDF-SHA256 + AES-256-GCM (what WebCrypto offers on the extension side).
x25519-dalek = { version = "2", features = ["static_secrets", "zeroize"] }
hkdf = "0.12"
sha2 = "0.10"
aes-gcm = "0.10"
getrandom = "0.2"
base64 = "0.22"
uuid = { version = "1", features = ["v4"] }
url = "2"
zeroize = "1"
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[target.'cfg(windows)'.dependencies]
windows-sys = { version = "0.61", features = [
"Win32_Foundation",
"Win32_Security",
"Win32_Security_Authorization",
"Win32_Storage_FileSystem",
"Win32_System_IO",
"Win32_System_Pipes",
"Win32_System_Threading",
"Win32_System_StationsAndDesktops",
"Win32_System_SystemInformation",
"Win32_UI_Input_KeyboardAndMouse",
] }
[target.'cfg(target_os = "macos")'.dependencies]
core-foundation = "0.10"
[dev-dependencies]
tempfile = "3"
[profile.release]
lto = true