1
//! POD types for the system-keyring surface
2
//! (SUPER_PLAN_2 §4 P4.2 + research/02 §0 "hardware-bound" storage).
3
//!
4
//! A biometry-bindable secret key/value store backed by the OS keyring:
5
//! iOS/macOS Keychain (`SecItem*`, optionally `kSecAttrAccessControl =
6
//! biometryCurrentSet`), Android `KeyStore` (`setUserAuthenticationRequired`),
7
//! Linux libsecret, Windows `CredentialLocker`. Defined here in `azul-core`
8
//! so the request/result types cross the FFI without `azul-layout` being a
9
//! dependency; the stateful side lives in
10
//! `azul_layout::managers::keyring::KeyringManager`.
11
//!
12
//! Request-driven and channel-delivered, mirroring biometric ([`crate::
13
//! biometric`]): a `Get` of a biometry-bound item shows the OS prompt and
14
//! resolves asynchronously, so *every* op resolves through the result
15
//! channel for a uniform, engine-agnostic surface. One op is in flight at
16
//! a time (the demo reveals one entry at a time); request↔result
17
//! correlation by id is a future refinement.
18

            
19
use azul_css::AzString;
20

            
21
/// A keyring operation queued by a callback
22
/// (`CallbackInfo::keyring_store` / `keyring_get` / `keyring_delete`) and
23
/// dispatched to the platform backend by the layout pass.
24
///
25
/// `secret` is an [`AzString`] — the common case is a password / token;
26
/// binary blobs are base64-encoded by the caller. `key` is the lookup
27
/// name, scoped to the app's keyring service.
28
#[repr(C, u8)]
29
#[derive(Debug, Clone, PartialEq)]
30
pub enum KeyringRequest {
31
    /// Write `secret` under `key`, overwriting any existing value. When
32
    /// `require_biometry` is set the item is stored access-controlled so a
33
    /// later `Get` triggers the OS biometric prompt (Keychain
34
    /// `biometryCurrentSet` / KeyStore `setUserAuthenticationRequired`).
35
    Store {
36
        key: AzString,
37
        secret: AzString,
38
        require_biometry: bool,
39
    },
40
    /// Read the secret stored under `key`. For a biometry-bound item the
41
    /// OS shows its auth prompt first; the result arrives asynchronously.
42
    Get { key: AzString },
43
    /// Remove the item stored under `key` (no-op if absent).
44
    Delete { key: AzString },
45
}
46

            
47
/// The outcome of a [`KeyringRequest`], delivered to the result channel
48
/// and read by callbacks via `CallbackInfo::get_keyring_result()`.
49
#[repr(C, u8)]
50
#[derive(Debug, Clone, PartialEq)]
51
pub enum KeyringResult {
52
    /// A `Store` succeeded.
53
    Stored,
54
    /// A `Get` returned the secret.
55
    Retrieved(AzString),
56
    /// A `Delete` succeeded (the key is now absent).
57
    Deleted,
58
    /// The requested key was not present in the keyring.
59
    NotFound,
60
    /// A biometry-bound read was refused — the user failed or cancelled
61
    /// the OS auth prompt.
62
    Denied,
63
    /// No keyring backend is available on this platform / it isn't
64
    /// configured (e.g. Linux without a running secret service).
65
    Unavailable,
66
    /// A platform error occurred (locked keychain, I/O, unmapped code).
67
    Error,
68
}
69

            
70
impl KeyringResult {
71
    /// The retrieved secret, if this is a successful `Get`.
72
6
    pub fn secret(&self) -> Option<&AzString> {
73
6
        match self {
74
2
            KeyringResult::Retrieved(s) => Some(s),
75
4
            _ => None,
76
        }
77
6
    }
78

            
79
    /// `true` for the success outcomes (`Stored` / `Retrieved` / `Deleted`).
80
7
    pub fn is_ok(&self) -> bool {
81
4
        matches!(
82
7
            self,
83
            KeyringResult::Stored | KeyringResult::Retrieved(_) | KeyringResult::Deleted
84
        )
85
7
    }
86
}
87

            
88
// FFI Option wrapper for `CallbackInfo::get_keyring_result() ->
89
// Option<KeyringResult>` — `None` until the first op completes. Not Copy
90
// (carries an `AzString` in `Retrieved`), so `copy = false` (mirrors
91
// `OptionNodeType`).
92
impl_option!(
93
    KeyringResult,
94
    OptionKeyringResult,
95
    copy = false,
96
    [Debug, Clone, PartialEq]
97
);