im_core/internal/secret_vault/
record.rs1use 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}