fraiseql_core/security/kms/
models.rs1use std::{collections::HashMap, fmt};
7
8use serde::{Deserialize, Serialize};
9use zeroize::Zeroizing;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
13#[serde(rename_all = "snake_case")]
14pub enum KeyPurpose {
15 EncryptDecrypt,
17 SignVerify,
19 Mac,
21}
22
23impl fmt::Display for KeyPurpose {
24 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
25 match self {
26 Self::EncryptDecrypt => write!(f, "encrypt_decrypt"),
27 Self::SignVerify => write!(f, "sign_verify"),
28 Self::Mac => write!(f, "mac"),
29 }
30 }
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
35#[serde(rename_all = "snake_case")]
36pub enum KeyState {
37 Enabled,
39 Disabled,
41 PendingDeletion,
43 Destroyed,
45}
46
47impl fmt::Display for KeyState {
48 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
49 match self {
50 Self::Enabled => write!(f, "enabled"),
51 Self::Disabled => write!(f, "disabled"),
52 Self::PendingDeletion => write!(f, "pending_deletion"),
53 Self::Destroyed => write!(f, "destroyed"),
54 }
55 }
56}
57
58#[derive(Debug, Clone, Serialize, Deserialize)]
60pub struct KeyReference {
61 pub provider: String,
63 pub key_id: String,
65 pub key_alias: Option<String>,
67 pub purpose: KeyPurpose,
69 pub created_at: i64,
71}
72
73impl KeyReference {
74 pub fn new(provider: String, key_id: String, purpose: KeyPurpose, created_at: i64) -> Self {
76 Self {
77 provider,
78 key_id,
79 key_alias: None,
80 purpose,
81 created_at,
82 }
83 }
84
85 #[must_use]
87 pub fn with_alias(mut self, alias: String) -> Self {
88 self.key_alias = Some(alias);
89 self
90 }
91
92 #[must_use]
94 pub fn qualified_id(&self) -> String {
95 format!("{}:{}", self.provider, self.key_id)
96 }
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
101pub struct EncryptedData {
102 pub ciphertext: String,
104 pub key_reference: KeyReference,
106 pub algorithm: String,
108 pub encrypted_at: i64,
110 pub context: HashMap<String, String>,
112}
113
114impl EncryptedData {
115 pub fn new(
117 ciphertext: String,
118 key_reference: KeyReference,
119 algorithm: String,
120 encrypted_at: i64,
121 context: HashMap<String, String>,
122 ) -> Self {
123 Self {
124 ciphertext,
125 key_reference,
126 algorithm,
127 encrypted_at,
128 context,
129 }
130 }
131}
132
133#[derive(Debug, Clone)]
135pub struct DataKeyPair {
136 pub plaintext_key: Zeroizing<Vec<u8>>,
138 pub encrypted_key: EncryptedData,
140 pub key_reference: KeyReference,
142}
143
144impl DataKeyPair {
145 pub fn new(
147 plaintext_key: Vec<u8>,
148 encrypted_key: EncryptedData,
149 key_reference: KeyReference,
150 ) -> Self {
151 Self {
152 plaintext_key: Zeroizing::new(plaintext_key),
153 encrypted_key,
154 key_reference,
155 }
156 }
157}
158
159#[derive(Debug, Clone, Serialize, Deserialize)]
161pub struct RotationPolicy {
162 pub enabled: bool,
164 pub rotation_period_days: u32,
166 pub last_rotation: Option<i64>,
168 pub next_rotation: Option<i64>,
170}
171
172impl RotationPolicy {
173 pub fn new(enabled: bool, rotation_period_days: u32) -> Self {
175 Self {
176 enabled,
177 rotation_period_days,
178 last_rotation: None,
179 next_rotation: None,
180 }
181 }
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187
188 #[test]
189 fn test_key_reference_qualified_id() {
190 let key_ref = KeyReference::new(
191 "vault".to_string(),
192 "my-key-123".to_string(),
193 KeyPurpose::EncryptDecrypt,
194 1_000_000,
195 );
196 assert_eq!(key_ref.qualified_id(), "vault:my-key-123");
197 }
198
199 #[test]
200 fn test_key_reference_with_alias() {
201 let key_ref = KeyReference::new(
202 "vault".to_string(),
203 "my-key-123".to_string(),
204 KeyPurpose::EncryptDecrypt,
205 1_000_000,
206 )
207 .with_alias("production-key".to_string());
208
209 assert_eq!(key_ref.key_alias, Some("production-key".to_string()));
210 }
211
212 #[test]
213 fn test_key_purpose_display() {
214 assert_eq!(KeyPurpose::EncryptDecrypt.to_string(), "encrypt_decrypt");
215 assert_eq!(KeyPurpose::SignVerify.to_string(), "sign_verify");
216 assert_eq!(KeyPurpose::Mac.to_string(), "mac");
217 }
218
219 #[test]
220 fn test_key_state_display() {
221 assert_eq!(KeyState::Enabled.to_string(), "enabled");
222 assert_eq!(KeyState::Disabled.to_string(), "disabled");
223 }
224
225 #[test]
226 fn test_rotation_policy_new() {
227 let policy = RotationPolicy::new(true, 90);
228 assert!(policy.enabled);
229 assert_eq!(policy.rotation_period_days, 90);
230 assert_eq!(policy.last_rotation, None);
231 assert_eq!(policy.next_rotation, None);
232 }
233}