openzeppelin_relayer/models/signer/
repository.rs

1use secrets::SecretVec;
2use serde::{Deserialize, Serialize, Serializer};
3
4use crate::models::SecretString;
5
6fn serialize_secretvec<S>(_secret: &SecretVec<u8>, serializer: S) -> Result<S::Ok, S::Error>
7where
8    S: Serializer,
9{
10    serializer.serialize_str("[REDACTED]")
11}
12
13#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
14#[serde(rename_all = "lowercase")]
15pub enum SignerType {
16    Test,
17    Local,
18    #[serde(rename = "aws_kms")]
19    AwsKms,
20    Vault,
21    Turnkey,
22}
23
24#[derive(Debug, Clone, Serialize)]
25pub struct SignerRepoModel {
26    pub id: String,
27    pub config: SignerConfig,
28}
29
30#[derive(Debug, Clone, Serialize)]
31pub struct LocalSignerConfig {
32    #[serde(serialize_with = "serialize_secretvec")]
33    pub raw_key: SecretVec<u8>,
34}
35
36#[derive(Debug, Clone, Serialize)]
37pub struct AwsKmsSignerConfig {
38    pub region: Option<String>,
39    pub key_id: String,
40}
41
42#[derive(Debug, Clone, Serialize)]
43pub struct VaultTransitSignerConfig {
44    pub key_name: String,
45    pub address: String,
46    pub namespace: Option<String>,
47    pub role_id: SecretString,
48    pub secret_id: SecretString,
49    pub pubkey: String,
50    pub mount_point: Option<String>,
51}
52
53#[derive(Debug, Clone, Serialize)]
54pub struct TurnkeySignerConfig {
55    pub api_public_key: String,
56    pub api_private_key: SecretString,
57    pub organization_id: String,
58    pub private_key_id: String,
59    pub public_key: String,
60}
61
62#[derive(Debug, Clone, Serialize)]
63pub struct GoogleCloudKmsSignerServiceAccountConfig {
64    pub private_key: SecretString,
65    pub private_key_id: SecretString,
66    pub project_id: String,
67    pub client_email: SecretString,
68    pub client_id: String,
69    pub auth_uri: String,
70    pub token_uri: String,
71    pub auth_provider_x509_cert_url: String,
72    pub client_x509_cert_url: String,
73    pub universe_domain: String,
74}
75
76#[derive(Debug, Clone, Serialize)]
77pub struct GoogleCloudKmsSignerKeyConfig {
78    pub location: String,
79    pub key_ring_id: String,
80    pub key_id: String,
81    pub key_version: u32,
82}
83
84#[derive(Debug, Clone, Serialize)]
85pub struct GoogleCloudKmsSignerConfig {
86    pub service_account: GoogleCloudKmsSignerServiceAccountConfig,
87    pub key: GoogleCloudKmsSignerKeyConfig,
88}
89
90#[derive(Debug, Clone, Serialize)]
91pub enum SignerConfig {
92    Test(LocalSignerConfig),
93    Local(LocalSignerConfig),
94    Vault(LocalSignerConfig),
95    VaultCloud(LocalSignerConfig),
96    VaultTransit(VaultTransitSignerConfig),
97    AwsKms(AwsKmsSignerConfig),
98    Turnkey(TurnkeySignerConfig),
99    GoogleCloudKms(GoogleCloudKmsSignerConfig),
100}
101
102impl SignerConfig {
103    pub fn get_local(&self) -> Option<&LocalSignerConfig> {
104        match self {
105            Self::Local(config)
106            | Self::Test(config)
107            | Self::Vault(config)
108            | Self::VaultCloud(config) => Some(config),
109            Self::VaultTransit(_)
110            | Self::AwsKms(_)
111            | Self::Turnkey(_)
112            | Self::GoogleCloudKms(_) => None,
113        }
114    }
115
116    pub fn get_aws_kms(&self) -> Option<&AwsKmsSignerConfig> {
117        let SignerConfig::AwsKms(config) = self else {
118            return None;
119        };
120
121        Some(config)
122    }
123
124    pub fn get_vault_transit(&self) -> Option<&VaultTransitSignerConfig> {
125        let SignerConfig::VaultTransit(config) = self else {
126            return None;
127        };
128
129        Some(config)
130    }
131
132    pub fn get_turnkey(&self) -> Option<&TurnkeySignerConfig> {
133        let SignerConfig::Turnkey(config) = self else {
134            return None;
135        };
136
137        Some(config)
138    }
139
140    pub fn get_google_cloud_kms(&self) -> Option<&GoogleCloudKmsSignerConfig> {
141        let SignerConfig::GoogleCloudKms(config) = self else {
142            return None;
143        };
144
145        Some(config)
146    }
147}
148
149#[cfg(test)]
150mod tests {
151    use super::*;
152    use serde_json::{from_str, to_string};
153
154    #[test]
155    fn test_signer_type_serialization() {
156        assert_eq!(to_string(&SignerType::Test).unwrap(), "\"test\"");
157        assert_eq!(to_string(&SignerType::Local).unwrap(), "\"local\"");
158        assert_eq!(to_string(&SignerType::AwsKms).unwrap(), "\"aws_kms\"");
159        assert_eq!(to_string(&SignerType::Vault).unwrap(), "\"vault\"");
160        assert_eq!(to_string(&SignerType::Turnkey).unwrap(), "\"turnkey\"");
161    }
162
163    #[test]
164    fn test_signer_type_deserialization() {
165        assert_eq!(
166            from_str::<SignerType>("\"test\"").unwrap(),
167            SignerType::Test
168        );
169        assert_eq!(
170            from_str::<SignerType>("\"local\"").unwrap(),
171            SignerType::Local
172        );
173        assert_eq!(
174            from_str::<SignerType>("\"aws_kms\"").unwrap(),
175            SignerType::AwsKms
176        );
177        assert_eq!(
178            from_str::<SignerType>("\"vault\"").unwrap(),
179            SignerType::Vault
180        );
181        assert_eq!(
182            from_str::<SignerType>("\"turnkey\"").unwrap(),
183            SignerType::Turnkey
184        );
185    }
186
187    #[test]
188    fn test_signer_repo_model_creation() {
189        let model = SignerRepoModel {
190            id: "test-signer".to_string(),
191            config: SignerConfig::Test(LocalSignerConfig {
192                raw_key: SecretVec::new(4, |v| v.copy_from_slice(&[1, 2, 3, 4])),
193            }),
194        };
195
196        assert_eq!(model.id, "test-signer");
197        assert!(matches!(model.config, SignerConfig::Test(_)));
198    }
199
200    #[test]
201    fn test_local_signer_config() {
202        let private_key = vec![0, 1, 2, 3, 4, 5];
203        let config = LocalSignerConfig {
204            raw_key: SecretVec::new(private_key.len(), |v| v.copy_from_slice(&private_key)),
205        };
206
207        let test = config.raw_key.borrow();
208        assert_eq!(*test, private_key);
209    }
210
211    #[test]
212    fn test_vault_transit_signer_config() {
213        let config = VaultTransitSignerConfig {
214            key_name: "transit-key".to_string(),
215            address: "https://vault.example.com".to_string(),
216            namespace: Some("ns1".to_string()),
217            role_id: SecretString::new("role-123"),
218            secret_id: SecretString::new("secret-456"),
219            pubkey: "mypubkey123".to_string(),
220            mount_point: Some("transit".to_string()),
221        };
222
223        assert_eq!(config.key_name, "transit-key");
224        assert_eq!(config.address, "https://vault.example.com");
225        assert_eq!(config.namespace, Some("ns1".to_string()));
226        assert_eq!(config.role_id.to_str().as_str(), "role-123");
227        assert_eq!(config.secret_id.to_str().as_str(), "secret-456");
228        assert_eq!(config.pubkey, "mypubkey123");
229        assert_eq!(config.mount_point, Some("transit".to_string()));
230
231        let config2 = VaultTransitSignerConfig {
232            key_name: "transit-key".to_string(),
233            address: "https://vault.example.com".to_string(),
234            namespace: None,
235            role_id: SecretString::new("role-123"),
236            secret_id: SecretString::new("secret-456"),
237            pubkey: "mypubkey123".to_string(),
238            mount_point: None,
239        };
240
241        assert_eq!(config2.namespace, None);
242        assert_eq!(config2.mount_point, None);
243    }
244
245    #[test]
246    fn test_turnkey_signer_config() {
247        let config = TurnkeySignerConfig {
248            api_private_key: SecretString::new("123"),
249            api_public_key: "api_public_key".to_string(),
250            organization_id: "organization_id".to_string(),
251            private_key_id: "private_key_id".to_string(),
252            public_key: "public_key".to_string(),
253        };
254
255        assert_eq!(config.api_public_key, "api_public_key");
256        assert_eq!(config.organization_id, "organization_id");
257        assert_eq!(config.api_private_key.to_str().as_str(), "123");
258        assert_eq!(config.private_key_id, "private_key_id");
259        assert_eq!(config.public_key, "public_key");
260    }
261
262    #[test]
263    fn test_google_cloud_kms_config() {
264        let config = GoogleCloudKmsSignerConfig {
265            service_account: GoogleCloudKmsSignerServiceAccountConfig {
266                private_key: SecretString::new("private_key"),
267                private_key_id: SecretString::new("private_key_id"),
268                project_id: "project_id".to_string(),
269                client_email: SecretString::new("client_email"),
270                client_id: "client_id".to_string(),
271                auth_uri: "auth_uri".to_string(),
272                token_uri: "token_uri".to_string(),
273                auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
274                client_x509_cert_url: "client_x509_cert_url".to_string(),
275                universe_domain: "universe_domain".to_string(),
276            },
277            key: GoogleCloudKmsSignerKeyConfig {
278                location: "global".to_string(),
279                key_ring_id: "key_ring_id".to_string(),
280                key_id: "key_id".to_string(),
281                key_version: 1,
282            },
283        };
284
285        assert_eq!(config.service_account.project_id, "project_id");
286        assert_eq!(config.key.key_ring_id, "key_ring_id");
287        assert_eq!(config.key.key_id, "key_id");
288        assert_eq!(config.key.key_version, 1);
289        assert_eq!(
290            config.service_account.private_key.to_str().as_str(),
291            "private_key"
292        );
293        assert_eq!(
294            config.service_account.private_key_id.to_str().as_str(),
295            "private_key_id"
296        );
297        assert_eq!(
298            config.service_account.client_email.to_str().as_str(),
299            "client_email"
300        );
301        assert_eq!(config.service_account.client_id, "client_id");
302        assert_eq!(config.service_account.auth_uri, "auth_uri");
303        assert_eq!(config.service_account.token_uri, "token_uri");
304        assert_eq!(
305            config.service_account.auth_provider_x509_cert_url,
306            "auth_provider_x509_cert_url"
307        );
308        assert_eq!(
309            config.service_account.client_x509_cert_url,
310            "client_x509_cert_url"
311        );
312        assert_eq!(config.service_account.universe_domain, "universe_domain");
313    }
314
315    #[test]
316    fn test_signer_config_variants() {
317        let test_config = SignerConfig::Test(LocalSignerConfig {
318            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
319        });
320
321        let local_config = SignerConfig::Local(LocalSignerConfig {
322            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[4, 5, 6])),
323        });
324
325        let vault_config = SignerConfig::Vault(LocalSignerConfig {
326            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[7, 8, 9])),
327        });
328
329        let vault_cloud_config = SignerConfig::VaultCloud(LocalSignerConfig {
330            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[10, 11, 12])),
331        });
332
333        let vault_transit_config = SignerConfig::VaultTransit(VaultTransitSignerConfig {
334            key_name: "transit-key".to_string(),
335            address: "https://vault.example.com".to_string(),
336            namespace: None,
337            role_id: SecretString::new("role-123"),
338            secret_id: SecretString::new("secret-456"),
339            pubkey: "mypubkey123".to_string(),
340            mount_point: None,
341        });
342
343        let aws_kms_config = SignerConfig::AwsKms(AwsKmsSignerConfig {
344            region: Some("us-east-1".to_string()),
345            key_id: "test-key-id".to_string(),
346        });
347
348        let turnkey_config = SignerConfig::Turnkey(TurnkeySignerConfig {
349            api_private_key: SecretString::new("123"),
350            api_public_key: "api_public_key".to_string(),
351            organization_id: "organization_id".to_string(),
352            private_key_id: "private_key_id".to_string(),
353            public_key: "public_key".to_string(),
354        });
355
356        let google_cloud_kms_config = SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
357            service_account: GoogleCloudKmsSignerServiceAccountConfig {
358                private_key: SecretString::new("private_key"),
359                private_key_id: SecretString::new("private_key_id"),
360                project_id: "project_id".to_string(),
361                client_email: SecretString::new("client_email"),
362                client_id: "client_id".to_string(),
363                auth_uri: "auth_uri".to_string(),
364                token_uri: "token_uri".to_string(),
365                auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
366                client_x509_cert_url: "client_x509_cert_url".to_string(),
367                universe_domain: "universe_domain".to_string(),
368            },
369            key: GoogleCloudKmsSignerKeyConfig {
370                location: "global".to_string(),
371                key_ring_id: "key_ring_id".to_string(),
372                key_id: "key_id".to_string(),
373                key_version: 1,
374            },
375        });
376
377        assert!(matches!(test_config, SignerConfig::Test(_)));
378        assert!(matches!(local_config, SignerConfig::Local(_)));
379        assert!(matches!(vault_config, SignerConfig::Vault(_)));
380        assert!(matches!(vault_cloud_config, SignerConfig::VaultCloud(_)));
381        assert!(matches!(
382            vault_transit_config,
383            SignerConfig::VaultTransit(_)
384        ));
385        assert!(matches!(aws_kms_config, SignerConfig::AwsKms(_)));
386        assert!(matches!(turnkey_config, SignerConfig::Turnkey(_)));
387        assert!(matches!(
388            google_cloud_kms_config,
389            SignerConfig::GoogleCloudKms(_)
390        ));
391    }
392
393    #[test]
394    fn test_signer_config_get_local() {
395        let local_config = SignerConfig::Local(LocalSignerConfig {
396            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
397        });
398        let retrieved = local_config.get_local().unwrap();
399        assert_eq!(*retrieved.raw_key.borrow(), vec![1, 2, 3]);
400
401        let test_config = SignerConfig::Test(LocalSignerConfig {
402            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[4, 5, 6])),
403        });
404        let retrieved = test_config.get_local().unwrap();
405        assert_eq!(*retrieved.raw_key.borrow(), vec![4, 5, 6]);
406
407        let vault_config = SignerConfig::Vault(LocalSignerConfig {
408            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[7, 8, 9])),
409        });
410        let retrieved = vault_config.get_local().unwrap();
411        assert_eq!(*retrieved.raw_key.borrow(), vec![7, 8, 9]);
412
413        let vault_cloud_config = SignerConfig::VaultCloud(LocalSignerConfig {
414            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[10, 11, 12])),
415        });
416        let retrieved = vault_cloud_config.get_local().unwrap();
417        assert_eq!(*retrieved.raw_key.borrow(), vec![10, 11, 12]);
418
419        let vault_transit_config = SignerConfig::VaultTransit(VaultTransitSignerConfig {
420            key_name: "transit-key".to_string(),
421            address: "https://vault.example.com".to_string(),
422            namespace: None,
423            role_id: SecretString::new("role-123"),
424            secret_id: SecretString::new("secret-456"),
425            pubkey: "mypubkey123".to_string(),
426            mount_point: None,
427        });
428        assert!(vault_transit_config.get_local().is_none());
429
430        let google_cloud_kms_config = SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
431            service_account: GoogleCloudKmsSignerServiceAccountConfig {
432                private_key: SecretString::new("private_key"),
433                private_key_id: SecretString::new("private_key_id"),
434                project_id: "project_id".to_string(),
435                client_email: SecretString::new("client_email"),
436                client_id: "client_id".to_string(),
437                auth_uri: "auth_uri".to_string(),
438                token_uri: "token_uri".to_string(),
439                auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
440                client_x509_cert_url: "client_x509_cert_url".to_string(),
441                universe_domain: "universe_domain".to_string(),
442            },
443            key: GoogleCloudKmsSignerKeyConfig {
444                location: "global".to_string(),
445                key_ring_id: "key_ring_id".to_string(),
446                key_id: "key_id".to_string(),
447                key_version: 1,
448            },
449        });
450        assert!(google_cloud_kms_config.get_local().is_none());
451
452        let aws_kms_config = SignerConfig::AwsKms(AwsKmsSignerConfig {
453            region: Some("us-east-1".to_string()),
454            key_id: "test-key-id".to_string(),
455        });
456        assert!(aws_kms_config.get_local().is_none());
457
458        let turnkey_config = SignerConfig::Turnkey(TurnkeySignerConfig {
459            api_private_key: SecretString::new("123"),
460            api_public_key: "api_public_key".to_string(),
461            organization_id: "organization_id".to_string(),
462            private_key_id: "private_key_id".to_string(),
463            public_key: "public_key".to_string(),
464        });
465        assert!(turnkey_config.get_local().is_none());
466    }
467
468    #[test]
469    fn test_signer_config_get_aws_kms() {
470        let aws_kms_config = SignerConfig::AwsKms(AwsKmsSignerConfig {
471            region: Some("us-east-1".to_string()),
472            key_id: "test-key-id".to_string(),
473        });
474        assert!(aws_kms_config.get_aws_kms().is_some());
475
476        // Test with configs that should return None
477        let local_config = SignerConfig::Local(LocalSignerConfig {
478            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
479        });
480        assert!(local_config.get_aws_kms().is_none());
481
482        let test_config = SignerConfig::Test(LocalSignerConfig {
483            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[4, 5, 6])),
484        });
485        assert!(test_config.get_aws_kms().is_none());
486    }
487
488    #[test]
489    fn test_signer_config_get_vault_transit() {
490        let vault_transit_config = SignerConfig::VaultTransit(VaultTransitSignerConfig {
491            key_name: "transit-key".to_string(),
492            address: "https://vault.example.com".to_string(),
493            namespace: None,
494            role_id: SecretString::new("role-123"),
495            secret_id: SecretString::new("secret-456"),
496            pubkey: "mypubkey123".to_string(),
497            mount_point: None,
498        });
499        let retrieved = vault_transit_config.get_vault_transit().unwrap();
500        assert_eq!(retrieved.key_name, "transit-key");
501        assert_eq!(retrieved.address, "https://vault.example.com");
502
503        let local_config = SignerConfig::Local(LocalSignerConfig {
504            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[1, 2, 3])),
505        });
506        assert!(local_config.get_vault_transit().is_none());
507
508        let vault_config = SignerConfig::Vault(LocalSignerConfig {
509            raw_key: SecretVec::new(3, |v| v.copy_from_slice(&[7, 8, 9])),
510        });
511        assert!(vault_config.get_vault_transit().is_none());
512    }
513
514    #[test]
515    fn test_signer_config_get_turnkey() {
516        let turnkey_config = SignerConfig::Turnkey(TurnkeySignerConfig {
517            api_private_key: SecretString::new("123"),
518            api_public_key: "api_public_key".to_string(),
519            organization_id: "organization_id".to_string(),
520            private_key_id: "private_key_id".to_string(),
521            public_key: "public_key".to_string(),
522        });
523
524        let retrieved = turnkey_config.get_turnkey().unwrap();
525
526        assert_eq!(retrieved.api_public_key, "api_public_key");
527        assert_eq!(retrieved.organization_id, "organization_id");
528        assert_eq!(retrieved.api_private_key.to_str().as_str(), "123");
529        assert_eq!(retrieved.private_key_id, "private_key_id");
530        assert_eq!(retrieved.public_key, "public_key");
531        assert!(turnkey_config.get_aws_kms().is_none());
532        assert!(turnkey_config.get_local().is_none());
533        assert!(turnkey_config.get_vault_transit().is_none());
534    }
535
536    #[test]
537    fn test_signer_config_get_google_cloud_kms() {
538        let google_config = SignerConfig::GoogleCloudKms(GoogleCloudKmsSignerConfig {
539            service_account: GoogleCloudKmsSignerServiceAccountConfig {
540                private_key: SecretString::new("private_key"),
541                private_key_id: SecretString::new("private_key_id"),
542                project_id: "project_id".to_string(),
543                client_email: SecretString::new("client_email"),
544                client_id: "client_id".to_string(),
545                auth_uri: "auth_uri".to_string(),
546                token_uri: "token_uri".to_string(),
547                auth_provider_x509_cert_url: "auth_provider_x509_cert_url".to_string(),
548                client_x509_cert_url: "client_x509_cert_url".to_string(),
549                universe_domain: "universe_domain".to_string(),
550            },
551            key: GoogleCloudKmsSignerKeyConfig {
552                location: "global".to_string(),
553                key_ring_id: "key_ring_id".to_string(),
554                key_id: "key_id".to_string(),
555                key_version: 1,
556            },
557        });
558        let retrieved = google_config.get_google_cloud_kms().unwrap();
559        assert_eq!(retrieved.service_account.project_id, "project_id");
560        assert!(google_config.get_aws_kms().is_none());
561        assert!(google_config.get_local().is_none());
562        assert!(google_config.get_vault_transit().is_none());
563    }
564}