Skip to main content

im_core/internal/secret_vault/
record.rs

1use super::policy::SecretAccessPolicy;
2use serde::{Deserialize, Serialize};
3use std::fmt;
4
5pub(crate) const VAULT_RECORD_SCHEMA_VERSION: u32 = 1;
6
7#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
8#[serde(rename_all = "snake_case")]
9pub enum SecretKind {
10    IdentityRootPrivate,
11    IdentityE2eeSigningPrivate,
12    IdentityE2eeAgreementPrivate,
13    IdentityDaemonPrivate,
14    AuthJwt,
15    DirectE2eeSignedPrekeyPrivate,
16    DirectE2eeOneTimePrekeyPrivate,
17    DirectE2eeSessionState,
18    GroupMlsState,
19    RuntimeSecret,
20}
21
22impl SecretKind {
23    pub fn as_str(&self) -> &'static str {
24        match self {
25            Self::IdentityRootPrivate => "identity.root.private",
26            Self::IdentityE2eeSigningPrivate => "identity.e2ee.signing.private",
27            Self::IdentityE2eeAgreementPrivate => "identity.e2ee.agreement.private",
28            Self::IdentityDaemonPrivate => "identity.daemon.private",
29            Self::AuthJwt => "auth.jwt",
30            Self::DirectE2eeSignedPrekeyPrivate => "direct_e2ee.signed_prekey.private",
31            Self::DirectE2eeOneTimePrekeyPrivate => "direct_e2ee.one_time_prekey.private",
32            Self::DirectE2eeSessionState => "direct_e2ee.session_state",
33            Self::GroupMlsState => "group_mls.state",
34            Self::RuntimeSecret => "runtime.secret",
35        }
36    }
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
40#[serde(rename_all = "snake_case")]
41pub(crate) enum VaultCipher {
42    ChaCha20Poly1305,
43}
44
45impl VaultCipher {
46    pub(crate) fn as_str(&self) -> &'static str {
47        match self {
48            Self::ChaCha20Poly1305 => "chacha20-poly1305",
49        }
50    }
51}
52
53#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
54#[serde(rename_all = "snake_case")]
55pub(crate) enum VaultKdf {
56    HkdfSha256,
57}
58
59impl VaultKdf {
60    pub(crate) fn as_str(&self) -> &'static str {
61        match self {
62            Self::HkdfSha256 => "hkdf-sha256",
63        }
64    }
65}
66
67#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
68pub struct SecretMetadata {
69    pub workspace_id: String,
70    pub device_id: String,
71    pub identity_id: Option<String>,
72    pub did: Option<String>,
73    pub kind: SecretKind,
74    pub key_id: String,
75    pub key_version: u32,
76    pub policy: SecretAccessPolicy,
77}
78
79impl SecretMetadata {
80    pub fn secret_ref(&self) -> SecretRef {
81        SecretRef {
82            workspace_id: self.workspace_id.clone(),
83            device_id: self.device_id.clone(),
84            identity_id: self.identity_id.clone(),
85            did: self.did.clone(),
86            kind: self.kind.clone(),
87            key_id: self.key_id.clone(),
88            key_version: self.key_version,
89        }
90    }
91}
92
93#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
94pub struct SecretRef {
95    pub workspace_id: String,
96    pub device_id: String,
97    pub identity_id: Option<String>,
98    pub did: Option<String>,
99    pub kind: SecretKind,
100    pub key_id: String,
101    pub key_version: u32,
102}
103
104#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
105pub(crate) struct VaultSecretRecord {
106    pub(crate) schema_version: u32,
107    pub(crate) workspace_id: String,
108    pub(crate) device_id: String,
109    pub(crate) identity_id: Option<String>,
110    pub(crate) did: Option<String>,
111    pub(crate) kind: SecretKind,
112    pub(crate) key_id: String,
113    pub(crate) key_version: u32,
114    pub(crate) cipher: VaultCipher,
115    pub(crate) kdf: VaultKdf,
116    pub(crate) nonce_b64u: String,
117    pub(crate) aad_b64u: String,
118    pub(crate) ciphertext_b64u: String,
119    pub(crate) created_at: String,
120    pub(crate) updated_at: String,
121    pub(crate) policy: SecretAccessPolicy,
122}
123
124impl VaultSecretRecord {
125    pub(crate) fn metadata(&self) -> SecretMetadata {
126        SecretMetadata {
127            workspace_id: self.workspace_id.clone(),
128            device_id: self.device_id.clone(),
129            identity_id: self.identity_id.clone(),
130            did: self.did.clone(),
131            kind: self.kind.clone(),
132            key_id: self.key_id.clone(),
133            key_version: self.key_version,
134            policy: self.policy.clone(),
135        }
136    }
137
138    pub(crate) fn secret_ref(&self) -> SecretRef {
139        self.metadata().secret_ref()
140    }
141}
142
143impl fmt::Debug for VaultSecretRecord {
144    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145        f.debug_struct("VaultSecretRecord")
146            .field("schema_version", &self.schema_version)
147            .field("workspace_id", &self.workspace_id)
148            .field("device_id", &self.device_id)
149            .field("identity_id", &self.identity_id)
150            .field("did", &self.did)
151            .field("kind", &self.kind)
152            .field("key_id", &self.key_id)
153            .field("key_version", &self.key_version)
154            .field("cipher", &self.cipher)
155            .field("kdf", &self.kdf)
156            .field("nonce", &"[REDACTED]")
157            .field("aad", &"[REDACTED]")
158            .field("ciphertext", &"[REDACTED]")
159            .field("created_at", &self.created_at)
160            .field("updated_at", &self.updated_at)
161            .field("policy", &self.policy)
162            .finish()
163    }
164}