1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
//! Platform interfaces for credential storage.
//!
//! ## Key structure
//!
//! - `K_device`: device-bound root key managed by `DeviceKeystore`.
//! - `account_keys.bin`: account key envelope stored via `AtomicBlobStore` and
//! containing `DeviceKeystore::seal` of `K_intermediate` with associated data
//! `worldid:account-key-envelope`.
//! - `K_intermediate`: 32-byte per-account key unsealed at init and kept in
//! memory for the lifetime of the storage handle.
//! - `SQLCipher` databases: `account.vault.sqlite` (authoritative) and
//! `account.cache.sqlite` (non-authoritative) are opened with `K_intermediate`.
//! - Derived keys: per relying-party session keys may be derived from
//! `K_intermediate` and cached in `account.cache.sqlite` for performance.
//! cached in `account.cache.sqlite` for performance.
use Arc;
use StorageResult;
use StoragePaths;
/// Device keystore interface used to seal and open account keys.
/// Atomic blob store for small binary files (e.g., `account_keys.bin`).
/// Provider responsible for platform-specific storage components and paths.
/// Listener notified when the credential vault contents change and a new
/// backup is needed.
///
/// Register via [`super::CredentialStore::set_vault_changed_listener`]. The
/// callback is delivered on a dedicated background thread to avoid re-entering
/// the `UniFFI` call stack (see `logger.rs` for rationale).
///
/// This is only called when individual credentials are added or removed.
///
/// # Expected usage
///
/// The host app should treat this as a trigger to schedule a backup of the
/// vault. It should contain synchronous actions only.
///
/// # Safety
///
/// **Warning:** implementors **must not** call back into
/// [`super::CredentialStore`] from
/// [`on_vault_changed`](VaultChangedListener::on_vault_changed) — doing so
/// will deadlock.