Approve sites' passkey requests from the browser extension

The app comes forward with a prompt to sign in with or save a passkey,
confirmed with the master password (the user verification each use needs).
Asked while locked: unlock, then it continues.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
2026-10-24 15:02:10 +07:00
co-authored by Claude Opus 5.5
parent b1c98f6376
commit 6f06b1e631
5 changed files with 118 additions and 4 deletions
+40
View File
@@ -10,6 +10,7 @@ use std::{io, thread};
use kestrove_desktop::autolock::{self, Activity, Reason};
use kestrove_desktop::broker::{Broker, PairingStore, PairingView, SaveView, Ui};
use kestrove_desktop::passkey::PasskeyView;
use kestrove_desktop::device_key::DeviceKey;
use kestrove_desktop::sync::{
self, AddDeviceView, DeviceView, JoinConfirmView, JoinPollView, JoinView, SetupView, SignIn, SyncService,
@@ -136,6 +137,13 @@ impl Ui for TauriUi {
self.surface();
let _ = self.handle.emit("save-request", req);
}
fn passkey_requested(&self, req: &PasskeyView) {
self.surface();
let _ = self.handle.emit("passkey-request", req);
}
fn passkey_settled(&self, id: &str) {
let _ = self.handle.emit("passkey-settled", id);
}
fn activity(&self) {
self.activity.touch();
}
@@ -355,6 +363,36 @@ fn resolve_save(app: State<'_, App>, id: String, accept: bool) -> CmdResult<()>
Ok(())
}
#[tauri::command]
fn pending_passkeys(app: State<'_, App>) -> Vec<PasskeyView> {
app.broker.pending_passkeys()
}
/// A page's passkey request (docs/05 "Passkeys in the browser"). Accepting needs the master password: the user
/// verification every passkey use requires, where the app has no biometrics to ask.
#[tauri::command]
fn resolve_passkey(
app: State<'_, App>,
id: String,
accept: bool,
credential_id: Option<String>,
master_password: Option<String>,
) -> CmdResult<()> {
if accept {
let pw = Zeroizing::new(master_password.unwrap_or_default());
app.core.confirm_master_password(pw.to_string()).map_err(|e| match e {
CoreError::BadCredentials => "Wrong master password.".to_string(),
e => err(e),
})?;
}
app.broker.resolve_passkey(&id, accept, credential_id.as_deref())?;
app.activity.touch();
if accept {
app.sync.request_sync();
}
Ok(())
}
// ---------------------------------------------------------------- sync server (docs/03)
#[tauri::command]
@@ -645,6 +683,8 @@ fn main() {
list_pairings,
revoke_pairing,
pending_saves,
pending_passkeys,
resolve_passkey,
resolve_save,
sync_status,
sync_now,