kv-wasm: onboarding (setup codes, enrollment tickets, scan-to-join) for the web vault
Mirrors kv-ffi's docs/10 §5 API in WebCore and binds it under the names the web app codes against: setupPayloadForKit, addDevicePayload, revokeEnrollmentTicket, loginWithSetup, joinStart/joinPoll/joinCancel, joinApprove, joinSend, and the free function parseSetupPayload (also callable through the worker client). Unlike kv-ffi, the Secret Key is not persisted: every unlock on the web takes it, so it is kept zeroized in the unlocked state and dropped on lock. loginWithSetup refuses a code for a different server than the configured origin (the browser only talks to its own origin). Tests: ticket enrollment and scan-to-join in both roles against kv-ffi via the kv-sync test server, a swapped-approver rejection, a Chrome test (IndexedDB never holds the Secret Key, JS shapes, error codes) and a Node smoke check of the built package. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
@@ -181,3 +181,81 @@ pub struct ImportReport {
|
||||
pub warnings: Vec<String>,
|
||||
pub item_ids: Vec<String>,
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------- onboarding (docs/10)
|
||||
|
||||
/// A parsed, validated setup payload: everything a new device needs except the master password.
|
||||
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct SetupInfo {
|
||||
/// Normalized server URL.
|
||||
pub server_url: String,
|
||||
/// Standard base64 SPKI pins, the format `configure_server` takes. Empty = WebPKI only.
|
||||
#[serde(default)]
|
||||
pub spki_pins: Vec<String>,
|
||||
pub account_id: String,
|
||||
/// Display form `K1-…`.
|
||||
pub secret_key: String,
|
||||
/// Enrollment ticket; `login_with_setup` presents it so no manual approval is needed.
|
||||
#[serde(default)]
|
||||
pub ticket: Option<String>,
|
||||
}
|
||||
|
||||
impl zeroize::Zeroize for SetupInfo {
|
||||
fn zeroize(&mut self) {
|
||||
self.secret_key.zeroize();
|
||||
self.ticket.zeroize();
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Debug for SetupInfo {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("SetupInfo")
|
||||
.field("server_url", &self.server_url)
|
||||
.field("spki_pins", &self.spki_pins)
|
||||
.field("account_id", &self.account_id)
|
||||
.field("secret_key", &"<redacted>")
|
||||
.field("ticket", &self.ticket.as_ref().map(|_| "<redacted>"))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
/// The "Add a device" QR: a setup payload with a fresh, unbound ticket.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AddDevicePayload {
|
||||
pub payload: String,
|
||||
/// For `revoke_enrollment_ticket` when the user cancels.
|
||||
pub ticket_id: String,
|
||||
/// Unix seconds; hide the QR after this.
|
||||
pub expires_at: i64,
|
||||
}
|
||||
|
||||
/// Shown by the joining device: a QR for a signed-in phone to scan.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JoinSession {
|
||||
pub qr: String,
|
||||
/// Unix seconds.
|
||||
pub expires_at: i64,
|
||||
}
|
||||
|
||||
/// Result of `join_poll`: `code` once a phone has scanned the QR, `setup` once it sent the bundle.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JoinProgress {
|
||||
pub code: Option<String>,
|
||||
pub setup: Option<SetupInfo>,
|
||||
}
|
||||
|
||||
/// Shown by the approving device after scanning: the code to compare and who is asking.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
pub struct JoinConfirm {
|
||||
/// `"123 456"`. The joining device shows the same code.
|
||||
pub code: String,
|
||||
pub device_name: String,
|
||||
pub platform: PlatformDto,
|
||||
/// Same format as `DeviceDto.key_fingerprint`.
|
||||
pub key_fingerprint: String,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user