1use crate::{
14 models::{
15 signer::{
16 AwsKmsSignerConfig, CdpSignerConfig, GoogleCloudKmsSignerConfig,
17 GoogleCloudKmsSignerKeyConfig, GoogleCloudKmsSignerServiceAccountConfig,
18 LocalSignerConfig, Signer, SignerConfig, SignerValidationError, TurnkeySignerConfig,
19 VaultSignerConfig, VaultTransitSignerConfig,
20 },
21 SecretString,
22 },
23 utils::{
24 deserialize_secret_string, deserialize_secret_vec, serialize_secret_string,
25 serialize_secret_vec,
26 },
27};
28use secrets::SecretVec;
29use serde::{Deserialize, Serialize};
30#[derive(Debug, Clone, Serialize, Deserialize)]
32pub struct SignerRepoModel {
33 pub id: String,
34 pub config: SignerConfigStorage,
35}
36
37#[derive(Debug, Clone, Serialize, Deserialize)]
38pub enum SignerConfigStorage {
39 Local(LocalSignerConfigStorage),
40 Vault(VaultSignerConfigStorage),
41 VaultTransit(VaultTransitSignerConfigStorage),
42 AwsKms(AwsKmsSignerConfigStorage),
43 Turnkey(TurnkeySignerConfigStorage),
44 Cdp(CdpSignerConfigStorage),
45 GoogleCloudKms(Box<GoogleCloudKmsSignerConfigStorage>),
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
50pub struct LocalSignerConfigStorage {
51 #[serde(
52 serialize_with = "serialize_secret_vec",
53 deserialize_with = "deserialize_secret_vec"
54 )]
55 pub raw_key: SecretVec<u8>,
56}
57
58impl From<LocalSignerConfig> for LocalSignerConfigStorage {
59 fn from(config: LocalSignerConfig) -> Self {
60 Self {
61 raw_key: config.raw_key,
62 }
63 }
64}
65
66impl From<LocalSignerConfigStorage> for LocalSignerConfig {
67 fn from(storage: LocalSignerConfigStorage) -> Self {
68 Self {
69 raw_key: storage.raw_key,
70 }
71 }
72}
73
74#[derive(Debug, Clone, Serialize, Deserialize)]
76pub struct AwsKmsSignerConfigStorage {
77 pub region: Option<String>,
78 pub key_id: String,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
82pub struct VaultSignerConfigStorage {
83 pub address: String,
84 pub namespace: Option<String>,
85 #[serde(
86 serialize_with = "serialize_secret_string",
87 deserialize_with = "deserialize_secret_string"
88 )]
89 pub role_id: SecretString,
90 #[serde(
91 serialize_with = "serialize_secret_string",
92 deserialize_with = "deserialize_secret_string"
93 )]
94 pub secret_id: SecretString,
95 pub key_name: String,
96 pub mount_point: Option<String>,
97}
98
99#[derive(Debug, Clone, Serialize, Deserialize)]
100pub struct VaultTransitSignerConfigStorage {
101 pub key_name: String,
102 pub address: String,
103 pub namespace: Option<String>,
104 #[serde(
105 serialize_with = "serialize_secret_string",
106 deserialize_with = "deserialize_secret_string"
107 )]
108 pub role_id: SecretString,
109 #[serde(
110 serialize_with = "serialize_secret_string",
111 deserialize_with = "deserialize_secret_string"
112 )]
113 pub secret_id: SecretString,
114 pub pubkey: String,
115 pub mount_point: Option<String>,
116}
117
118#[derive(Debug, Clone, Serialize, Deserialize)]
119pub struct TurnkeySignerConfigStorage {
120 pub api_public_key: String,
121 #[serde(
122 serialize_with = "serialize_secret_string",
123 deserialize_with = "deserialize_secret_string"
124 )]
125 pub api_private_key: SecretString,
126 pub organization_id: String,
127 pub private_key_id: String,
128 pub public_key: String,
129}
130
131#[derive(Debug, Clone, Serialize, Deserialize)]
132pub struct CdpSignerConfigStorage {
133 pub api_key_id: String,
134 #[serde(
135 serialize_with = "serialize_secret_string",
136 deserialize_with = "deserialize_secret_string"
137 )]
138 pub api_key_secret: SecretString,
139 #[serde(
140 serialize_with = "serialize_secret_string",
141 deserialize_with = "deserialize_secret_string"
142 )]
143 pub wallet_secret: SecretString,
144 pub account_address: String,
145}
146
147#[derive(Debug, Clone, Serialize, Deserialize)]
149pub struct GoogleCloudKmsSignerServiceAccountConfigStorage {
150 #[serde(
151 serialize_with = "serialize_secret_string",
152 deserialize_with = "deserialize_secret_string"
153 )]
154 pub private_key: SecretString,
155 #[serde(
156 serialize_with = "serialize_secret_string",
157 deserialize_with = "deserialize_secret_string"
158 )]
159 pub private_key_id: SecretString,
160 #[serde(
161 serialize_with = "serialize_secret_string",
162 deserialize_with = "deserialize_secret_string"
163 )]
164 pub project_id: SecretString,
165 #[serde(
166 serialize_with = "serialize_secret_string",
167 deserialize_with = "deserialize_secret_string"
168 )]
169 pub client_email: SecretString,
170 #[serde(
171 serialize_with = "serialize_secret_string",
172 deserialize_with = "deserialize_secret_string"
173 )]
174 pub client_id: SecretString,
175 #[serde(
176 serialize_with = "serialize_secret_string",
177 deserialize_with = "deserialize_secret_string"
178 )]
179 pub auth_uri: SecretString,
180 #[serde(
181 serialize_with = "serialize_secret_string",
182 deserialize_with = "deserialize_secret_string"
183 )]
184 pub token_uri: SecretString,
185 #[serde(
186 serialize_with = "serialize_secret_string",
187 deserialize_with = "deserialize_secret_string"
188 )]
189 pub auth_provider_x509_cert_url: SecretString,
190 #[serde(
191 serialize_with = "serialize_secret_string",
192 deserialize_with = "deserialize_secret_string"
193 )]
194 pub client_x509_cert_url: SecretString,
195 #[serde(
196 serialize_with = "serialize_secret_string",
197 deserialize_with = "deserialize_secret_string"
198 )]
199 pub universe_domain: SecretString,
200}
201
202#[derive(Debug, Clone, Serialize, Deserialize)]
207pub struct GoogleCloudKmsSignerKeyConfigStorage {
208 #[serde(
209 serialize_with = "serialize_secret_string",
210 deserialize_with = "deserialize_secret_string"
211 )]
212 pub location: SecretString,
213 #[serde(
214 serialize_with = "serialize_secret_string",
215 deserialize_with = "deserialize_secret_string"
216 )]
217 pub key_ring_id: SecretString,
218 #[serde(
219 serialize_with = "serialize_secret_string",
220 deserialize_with = "deserialize_secret_string"
221 )]
222 pub key_id: SecretString,
223 pub key_version: u32,
224}
225
226#[derive(Debug, Clone, Serialize, Deserialize)]
227pub struct GoogleCloudKmsSignerConfigStorage {
228 pub service_account: GoogleCloudKmsSignerServiceAccountConfigStorage,
229 pub key: GoogleCloudKmsSignerKeyConfigStorage,
230}
231
232impl From<Signer> for SignerRepoModel {
234 fn from(signer: Signer) -> Self {
235 Self {
236 id: signer.id,
237 config: signer.config.into(),
238 }
239 }
240}
241
242impl From<SignerRepoModel> for Signer {
244 fn from(repo_model: SignerRepoModel) -> Self {
245 Self {
246 id: repo_model.id,
247 config: repo_model.config.into(),
248 }
249 }
250}
251
252impl From<AwsKmsSignerConfig> for AwsKmsSignerConfigStorage {
253 fn from(config: AwsKmsSignerConfig) -> Self {
254 Self {
255 region: config.region,
256 key_id: config.key_id,
257 }
258 }
259}
260
261impl From<AwsKmsSignerConfigStorage> for AwsKmsSignerConfig {
262 fn from(storage: AwsKmsSignerConfigStorage) -> Self {
263 Self {
264 region: storage.region,
265 key_id: storage.key_id,
266 }
267 }
268}
269
270impl From<VaultSignerConfig> for VaultSignerConfigStorage {
271 fn from(config: VaultSignerConfig) -> Self {
272 Self {
273 address: config.address,
274 namespace: config.namespace,
275 role_id: config.role_id,
276 secret_id: config.secret_id,
277 key_name: config.key_name,
278 mount_point: config.mount_point,
279 }
280 }
281}
282
283impl From<VaultSignerConfigStorage> for VaultSignerConfig {
284 fn from(storage: VaultSignerConfigStorage) -> Self {
285 Self {
286 address: storage.address,
287 namespace: storage.namespace,
288 role_id: storage.role_id,
289 secret_id: storage.secret_id,
290 key_name: storage.key_name,
291 mount_point: storage.mount_point,
292 }
293 }
294}
295
296impl From<VaultTransitSignerConfig> for VaultTransitSignerConfigStorage {
297 fn from(config: VaultTransitSignerConfig) -> Self {
298 Self {
299 key_name: config.key_name,
300 address: config.address,
301 namespace: config.namespace,
302 role_id: config.role_id,
303 secret_id: config.secret_id,
304 pubkey: config.pubkey,
305 mount_point: config.mount_point,
306 }
307 }
308}
309
310impl From<VaultTransitSignerConfigStorage> for VaultTransitSignerConfig {
311 fn from(storage: VaultTransitSignerConfigStorage) -> Self {
312 Self {
313 key_name: storage.key_name,
314 address: storage.address,
315 namespace: storage.namespace,
316 role_id: storage.role_id,
317 secret_id: storage.secret_id,
318 pubkey: storage.pubkey,
319 mount_point: storage.mount_point,
320 }
321 }
322}
323
324impl From<TurnkeySignerConfig> for TurnkeySignerConfigStorage {
325 fn from(config: TurnkeySignerConfig) -> Self {
326 Self {
327 api_public_key: config.api_public_key,
328 api_private_key: config.api_private_key,
329 organization_id: config.organization_id,
330 private_key_id: config.private_key_id,
331 public_key: config.public_key,
332 }
333 }
334}
335
336impl From<TurnkeySignerConfigStorage> for TurnkeySignerConfig {
337 fn from(storage: TurnkeySignerConfigStorage) -> Self {
338 Self {
339 api_public_key: storage.api_public_key,
340 api_private_key: storage.api_private_key,
341 organization_id: storage.organization_id,
342 private_key_id: storage.private_key_id,
343 public_key: storage.public_key,
344 }
345 }
346}
347
348impl From<CdpSignerConfig> for CdpSignerConfigStorage {
349 fn from(config: CdpSignerConfig) -> Self {
350 Self {
351 api_key_id: config.api_key_id,
352 api_key_secret: config.api_key_secret,
353 wallet_secret: config.wallet_secret,
354 account_address: config.account_address,
355 }
356 }
357}
358
359impl From<CdpSignerConfigStorage> for CdpSignerConfig {
360 fn from(storage: CdpSignerConfigStorage) -> Self {
361 Self {
362 api_key_id: storage.api_key_id,
363 api_key_secret: storage.api_key_secret,
364 wallet_secret: storage.wallet_secret,
365 account_address: storage.account_address,
366 }
367 }
368}
369
370impl From<GoogleCloudKmsSignerConfig> for GoogleCloudKmsSignerConfigStorage {
371 fn from(config: GoogleCloudKmsSignerConfig) -> Self {
372 Self {
373 service_account: config.service_account.into(),
374 key: config.key.into(),
375 }
376 }
377}
378
379impl From<GoogleCloudKmsSignerConfigStorage> for GoogleCloudKmsSignerConfig {
380 fn from(storage: GoogleCloudKmsSignerConfigStorage) -> Self {
381 Self {
382 service_account: storage.service_account.into(),
383 key: storage.key.into(),
384 }
385 }
386}
387
388impl From<GoogleCloudKmsSignerServiceAccountConfig>
389 for GoogleCloudKmsSignerServiceAccountConfigStorage
390{
391 fn from(config: GoogleCloudKmsSignerServiceAccountConfig) -> Self {
392 Self {
393 private_key: config.private_key,
394 private_key_id: config.private_key_id,
395 project_id: config.project_id,
396 client_email: config.client_email,
397 client_id: config.client_id,
398 auth_uri: config.auth_uri,
399 token_uri: config.token_uri,
400 auth_provider_x509_cert_url: config.auth_provider_x509_cert_url,
401 client_x509_cert_url: config.client_x509_cert_url,
402 universe_domain: config.universe_domain,
403 }
404 }
405}
406
407impl From<GoogleCloudKmsSignerServiceAccountConfigStorage>
408 for GoogleCloudKmsSignerServiceAccountConfig
409{
410 fn from(storage: GoogleCloudKmsSignerServiceAccountConfigStorage) -> Self {
411 Self {
412 private_key: storage.private_key,
413 private_key_id: storage.private_key_id,
414 project_id: storage.project_id,
415 client_email: storage.client_email,
416 client_id: storage.client_id,
417 auth_uri: storage.auth_uri,
418 token_uri: storage.token_uri,
419 auth_provider_x509_cert_url: storage.auth_provider_x509_cert_url,
420 client_x509_cert_url: storage.client_x509_cert_url,
421 universe_domain: storage.universe_domain,
422 }
423 }
424}
425
426impl From<GoogleCloudKmsSignerKeyConfig> for GoogleCloudKmsSignerKeyConfigStorage {
427 fn from(config: GoogleCloudKmsSignerKeyConfig) -> Self {
428 Self {
429 location: config.location,
430 key_ring_id: config.key_ring_id,
431 key_id: config.key_id,
432 key_version: config.key_version,
433 }
434 }
435}
436
437impl From<GoogleCloudKmsSignerKeyConfigStorage> for GoogleCloudKmsSignerKeyConfig {
438 fn from(storage: GoogleCloudKmsSignerKeyConfigStorage) -> Self {
439 Self {
440 location: storage.location,
441 key_ring_id: storage.key_ring_id,
442 key_id: storage.key_id,
443 key_version: storage.key_version,
444 }
445 }
446}
447
448impl SignerRepoModel {
449 pub fn validate(&self) -> Result<(), SignerValidationError> {
451 let core_signer = Signer::from(self.clone());
452 core_signer.validate()
453 }
454}
455
456impl From<SignerConfig> for SignerConfigStorage {
457 fn from(config: SignerConfig) -> Self {
458 match config {
459 SignerConfig::Local(local) => SignerConfigStorage::Local(local.into()),
460 SignerConfig::Vault(vault) => SignerConfigStorage::Vault(vault.into()),
461 SignerConfig::VaultTransit(vault_transit) => {
462 SignerConfigStorage::VaultTransit(vault_transit.into())
463 }
464 SignerConfig::AwsKms(aws_kms) => SignerConfigStorage::AwsKms(aws_kms.into()),
465 SignerConfig::Turnkey(turnkey) => SignerConfigStorage::Turnkey(turnkey.into()),
466 SignerConfig::Cdp(cdp) => SignerConfigStorage::Cdp(cdp.into()),
467 SignerConfig::GoogleCloudKms(gcp) => {
468 SignerConfigStorage::GoogleCloudKms(Box::new((*gcp).into()))
469 }
470 }
471 }
472}
473
474impl From<SignerConfigStorage> for SignerConfig {
475 fn from(storage: SignerConfigStorage) -> Self {
476 match storage {
477 SignerConfigStorage::Local(local) => SignerConfig::Local(local.into()),
478 SignerConfigStorage::Vault(vault) => SignerConfig::Vault(vault.into()),
479 SignerConfigStorage::VaultTransit(vault_transit) => {
480 SignerConfig::VaultTransit(vault_transit.into())
481 }
482 SignerConfigStorage::AwsKms(aws_kms) => SignerConfig::AwsKms(aws_kms.into()),
483 SignerConfigStorage::Turnkey(turnkey) => SignerConfig::Turnkey(turnkey.into()),
484 SignerConfigStorage::Cdp(cdp) => SignerConfig::Cdp(cdp.into()),
485 SignerConfigStorage::GoogleCloudKms(gcp) => {
486 SignerConfig::GoogleCloudKms(Box::new((*gcp).into()))
487 }
488 }
489 }
490}
491
492impl SignerConfigStorage {
493 pub fn get_local(&self) -> Option<&LocalSignerConfigStorage> {
495 match self {
496 Self::Local(config) => Some(config),
497 _ => None,
498 }
499 }
500
501 pub fn get_vault_transit(&self) -> Option<&VaultTransitSignerConfigStorage> {
503 match self {
504 Self::VaultTransit(config) => Some(config),
505 _ => None,
506 }
507 }
508
509 pub fn get_vault(&self) -> Option<&VaultSignerConfigStorage> {
511 match self {
512 Self::Vault(config) => Some(config),
513 _ => None,
514 }
515 }
516
517 pub fn get_turnkey(&self) -> Option<&TurnkeySignerConfigStorage> {
519 match self {
520 Self::Turnkey(config) => Some(config),
521 _ => None,
522 }
523 }
524
525 pub fn get_cdp(&self) -> Option<&CdpSignerConfigStorage> {
527 match self {
528 Self::Cdp(config) => Some(config),
529 _ => None,
530 }
531 }
532
533 pub fn get_google_cloud_kms(&self) -> Option<&GoogleCloudKmsSignerConfigStorage> {
535 match self {
536 Self::GoogleCloudKms(config) => Some(config),
537 _ => None,
538 }
539 }
540
541 pub fn get_aws_kms(&self) -> Option<&AwsKmsSignerConfigStorage> {
543 match self {
544 Self::AwsKms(config) => Some(config),
545 _ => None,
546 }
547 }
548}
549
550#[cfg(test)]
551mod tests {
552 use super::*;
553 use crate::models::signer::{LocalSignerConfig, SignerConfig};
554 use secrets::SecretVec;
555
556 #[test]
557 fn test_from_core_signer() {
558 let config = LocalSignerConfig {
559 raw_key: SecretVec::new(32, |v| v.fill(1)),
560 };
561
562 let core =
563 crate::models::signer::Signer::new("test-id".to_string(), SignerConfig::Local(config));
564
565 let repo_model = SignerRepoModel::from(core);
566 assert_eq!(repo_model.id, "test-id");
567 assert!(matches!(repo_model.config, SignerConfigStorage::Local(_)));
568 }
569
570 #[test]
571 fn test_to_core_signer() {
572 use crate::models::signer::AwsKmsSignerConfigStorage;
573
574 let domain_config = AwsKmsSignerConfigStorage {
575 region: Some("us-east-1".to_string()),
576 key_id: "test-key".to_string(),
577 };
578
579 let repo_model = SignerRepoModel {
580 id: "test-id".to_string(),
581 config: SignerConfigStorage::AwsKms(domain_config),
582 };
583
584 let core = Signer::from(repo_model);
585 assert_eq!(core.id, "test-id");
586 assert_eq!(
587 core.signer_type(),
588 crate::models::signer::SignerType::AwsKms
589 );
590 }
591
592 #[test]
593 fn test_validation() {
594 use secrets::SecretVec;
595
596 let domain_config = LocalSignerConfig {
597 raw_key: SecretVec::new(32, |v| v.fill(1)),
598 };
599 let storage_config = LocalSignerConfigStorage::from(domain_config);
601
602 let repo_model = SignerRepoModel {
603 id: "test-id".to_string(),
604 config: SignerConfigStorage::Local(storage_config),
605 };
606
607 assert!(repo_model.validate().is_ok());
608 }
609
610 #[test]
611 fn test_local_config_storage_conversion() {
612 let domain_config = LocalSignerConfig {
613 raw_key: SecretVec::new(4, |v| v.copy_from_slice(&[1, 2, 3, 4])),
614 };
615
616 let storage_config = LocalSignerConfigStorage::from(domain_config.clone());
617 let converted_back = LocalSignerConfig::from(storage_config);
618
619 let original_data = domain_config.raw_key.borrow();
621 let converted_data = converted_back.raw_key.borrow();
622 assert_eq!(*original_data, *converted_data);
623 }
624
625 #[test]
626 fn test_cdp_config_storage_conversion() {
627 use crate::models::SecretString;
628
629 let domain_config = CdpSignerConfig {
630 api_key_id: "test-api-key-id".to_string(),
631 api_key_secret: SecretString::new("test-api-secret"),
632 wallet_secret: SecretString::new("test-wallet-secret"),
633 account_address: "0x1234567890123456789012345678901234567890".to_string(),
634 };
635
636 let storage_config = CdpSignerConfigStorage::from(domain_config.clone());
637 let converted_back = CdpSignerConfig::from(storage_config);
638
639 assert_eq!(domain_config.api_key_id, converted_back.api_key_id);
640 assert_eq!(
641 domain_config.account_address,
642 converted_back.account_address
643 );
644 assert_eq!(
645 domain_config.api_key_secret.to_str(),
646 converted_back.api_key_secret.to_str()
647 );
648 assert_eq!(
649 domain_config.wallet_secret.to_str(),
650 converted_back.wallet_secret.to_str()
651 );
652 }
653
654 #[test]
655 fn test_signer_config_storage_get_cdp() {
656 use crate::models::SecretString;
657
658 let cdp_storage = CdpSignerConfigStorage {
659 api_key_id: "test-id".to_string(),
660 api_key_secret: SecretString::new("secret"),
661 wallet_secret: SecretString::new("wallet-secret"),
662 account_address: "0x1234567890123456789012345678901234567890".to_string(),
663 };
664
665 let config_storage = SignerConfigStorage::Cdp(cdp_storage);
666 let retrieved_cdp = config_storage.get_cdp();
667 assert!(retrieved_cdp.is_some());
668 assert_eq!(retrieved_cdp.unwrap().api_key_id, "test-id");
669 }
670
671 #[test]
672 fn test_signer_config_storage_get_cdp_from_non_cdp() {
673 let aws_storage = AwsKmsSignerConfigStorage {
674 region: Some("us-east-1".to_string()),
675 key_id: "test-key".to_string(),
676 };
677
678 let config_storage = SignerConfigStorage::AwsKms(aws_storage);
679 let retrieved_cdp = config_storage.get_cdp();
680 assert!(retrieved_cdp.is_none());
681 }
682}