qualia_client_core/wellfair/api/sanctuary_vault.rs
1//! Vault v2 decoy audit + OS-keychain wrapping
2
3use super::*;
4
5impl WebizenHostApi {
6 // --- Vault v2 (S6): per-session decoy audit, real→decoy curation, real-lane audit review ---
7
8 /// Add a note, attributing a **decoy** (duress) write to `session_ref` — a fresh ref per duress
9 /// unlock yields the git-like per-session branch in the audit DAG (ADR §10). Real-lane writes
10 /// ignore `session_ref` (real activity is never audited). The host should mint one `session_ref`
11 /// per unlock (e.g. a UUID) and reuse it for every write in that session.
12 #[cfg(not(target_arch = "wasm32"))]
13 pub fn add_sanctuary_vault_note_in_session(
14 &self,
15 pin: &str,
16 body: &str,
17 session_ref: &str,
18 ) -> Result<super::super::sanctuary_vault::SanctuaryLane, String> {
19 super::super::sanctuary_vault::add_note_in_session(
20 &self.storage_root,
21 pin,
22 body,
23 Self::now_unix() as u32,
24 session_ref,
25 )
26 }
27
28 /// **Curate the decoy from a real session (ADR §3.2).** Write a plausible note into the decoy
29 /// lane *without* the decoy PIN, so a coercer's re-unlock shows fresh, believable content.
30 /// Requires the **real** PIN; the decoy/wrong PIN is rejected.
31 #[cfg(not(target_arch = "wasm32"))]
32 pub fn curate_sanctuary_decoy_note(&self, real_pin: &str, body: &str) -> Result<(), String> {
33 super::super::sanctuary_vault::real_curate_decoy_add_note(
34 &self.storage_root,
35 real_pin,
36 body,
37 Self::now_unix() as u32,
38 )
39 }
40
41 /// **Review decoy activity from the real lane (ADR §3.1 / §10).** Decrypts every sealed
42 /// decoy-session record, verifies chain integrity + each witnessed-prefix head anchor, advances
43 /// the anchors, and returns the decrypted actions with an integrity verdict. Requires the
44 /// **real** PIN. `session_count` is a proxy for "number of attackers", never a hard head-count.
45 #[cfg(not(target_arch = "wasm32"))]
46 pub fn review_sanctuary_decoy_activity(
47 &self,
48 real_pin: &str,
49 ) -> Result<super::super::sanctuary_vault::DecoyActivityReport, String> {
50 super::super::sanctuary_vault::review_decoy_activity(&self.storage_root, real_pin)
51 }
52
53 /// Read the decoy-audit retention policy (ADR §8). **Real-session only** — requires the real PIN;
54 /// the setting is invisible/unreachable from a decoy session. Defaults to auto-archive.
55 #[cfg(not(target_arch = "wasm32"))]
56 pub fn get_sanctuary_decoy_retention_mode(
57 &self,
58 real_pin: &str,
59 ) -> Result<qualia_core_db::crypto::sanctuary_audit_dag::RetentionMode, String> {
60 super::super::sanctuary_vault::get_retention_mode(&self.storage_root, real_pin)
61 }
62
63 /// Set the decoy-audit retention policy (ADR §8). **Real-session only** — requires the real PIN.
64 #[cfg(not(target_arch = "wasm32"))]
65 pub fn set_sanctuary_decoy_retention_mode(
66 &self,
67 real_pin: &str,
68 mode: qualia_core_db::crypto::sanctuary_audit_dag::RetentionMode,
69 ) -> Result<(), String> {
70 super::super::sanctuary_vault::set_retention_mode(&self.storage_root, real_pin, mode)
71 }
72
73 // --- T1.2: OS-keychain vault wrapping (opt-in, off by default; recovery-gated) ---
74
75 /// Is the on-disk Sanctuary vault keychain-wrapped (bound to an OS-keychain pepper)?
76 #[cfg(not(target_arch = "wasm32"))]
77 pub fn sanctuary_vault_is_keychain_wrapped(&self) -> bool {
78 super::super::sanctuary_vault::is_keychain_wrapped(&self.storage_root)
79 }
80
81 /// Opt-in: create the Sanctuary vault with an OS-keychain-held pepper so disk + PIN alone can't
82 /// open it. Returns the hex **recovery code** the user MUST record — losing the keychain entry
83 /// otherwise loses the vault. The ordinary [`Self::setup_sanctuary_vault`] path stays unwrapped.
84 #[cfg(not(target_arch = "wasm32"))]
85 pub fn setup_sanctuary_vault_wrapped(
86 &self,
87 real_pin: &str,
88 decoy_pin: &str,
89 ) -> Result<String, String> {
90 super::super::sanctuary_vault::setup_wrapped(&self.storage_root, real_pin, decoy_pin)
91 }
92
93 /// Recover a keychain-wrapped vault on a device whose keychain entry is missing, using the
94 /// recovery code from [`Self::setup_sanctuary_vault_wrapped`]. Re-seats the pepper on success.
95 #[cfg(not(target_arch = "wasm32"))]
96 pub fn sanctuary_vault_unlock_with_recovery(
97 &self,
98 pin: &str,
99 recovery_code_hex: &str,
100 ) -> Result<super::super::sanctuary_vault::SanctuaryLane, String> {
101 super::super::sanctuary_vault::unlock_with_recovery(
102 &self.storage_root,
103 pin,
104 recovery_code_hex,
105 )
106 }
107}