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(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)]
148pub struct GoogleCloudKmsSignerServiceAccountConfigStorage {
149 #[serde(
150 serialize_with = "serialize_secret_string",
151 deserialize_with = "deserialize_secret_string"
152 )]
153 pub private_key: SecretString,
154 #[serde(
155 serialize_with = "serialize_secret_string",
156 deserialize_with = "deserialize_secret_string"
157 )]
158 pub private_key_id: SecretString,
159 pub project_id: String,
160 #[serde(
161 serialize_with = "serialize_secret_string",
162 deserialize_with = "deserialize_secret_string"
163 )]
164 pub client_email: SecretString,
165 pub client_id: String,
166 pub auth_uri: String,
167 pub token_uri: String,
168 pub auth_provider_x509_cert_url: String,
169 pub client_x509_cert_url: String,
170 pub universe_domain: String,
171}
172
173#[derive(Debug, Clone, Serialize, Deserialize)]
174pub struct GoogleCloudKmsSignerKeyConfigStorage {
175 pub location: String,
176 pub key_ring_id: String,
177 pub key_id: String,
178 pub key_version: u32,
179}
180
181#[derive(Debug, Clone, Serialize, Deserialize)]
182pub struct GoogleCloudKmsSignerConfigStorage {
183 pub service_account: GoogleCloudKmsSignerServiceAccountConfigStorage,
184 pub key: GoogleCloudKmsSignerKeyConfigStorage,
185}
186
187impl From<Signer> for SignerRepoModel {
189 fn from(signer: Signer) -> Self {
190 Self {
191 id: signer.id,
192 config: signer.config.into(),
193 }
194 }
195}
196
197impl From<SignerRepoModel> for Signer {
199 fn from(repo_model: SignerRepoModel) -> Self {
200 Self {
201 id: repo_model.id,
202 config: repo_model.config.into(),
203 }
204 }
205}
206
207impl From<AwsKmsSignerConfig> for AwsKmsSignerConfigStorage {
208 fn from(config: AwsKmsSignerConfig) -> Self {
209 Self {
210 region: config.region,
211 key_id: config.key_id,
212 }
213 }
214}
215
216impl From<AwsKmsSignerConfigStorage> for AwsKmsSignerConfig {
217 fn from(storage: AwsKmsSignerConfigStorage) -> Self {
218 Self {
219 region: storage.region,
220 key_id: storage.key_id,
221 }
222 }
223}
224
225impl From<VaultSignerConfig> for VaultSignerConfigStorage {
226 fn from(config: VaultSignerConfig) -> Self {
227 Self {
228 address: config.address,
229 namespace: config.namespace,
230 role_id: config.role_id,
231 secret_id: config.secret_id,
232 key_name: config.key_name,
233 mount_point: config.mount_point,
234 }
235 }
236}
237
238impl From<VaultSignerConfigStorage> for VaultSignerConfig {
239 fn from(storage: VaultSignerConfigStorage) -> Self {
240 Self {
241 address: storage.address,
242 namespace: storage.namespace,
243 role_id: storage.role_id,
244 secret_id: storage.secret_id,
245 key_name: storage.key_name,
246 mount_point: storage.mount_point,
247 }
248 }
249}
250
251impl From<VaultTransitSignerConfig> for VaultTransitSignerConfigStorage {
252 fn from(config: VaultTransitSignerConfig) -> Self {
253 Self {
254 key_name: config.key_name,
255 address: config.address,
256 namespace: config.namespace,
257 role_id: config.role_id,
258 secret_id: config.secret_id,
259 pubkey: config.pubkey,
260 mount_point: config.mount_point,
261 }
262 }
263}
264
265impl From<VaultTransitSignerConfigStorage> for VaultTransitSignerConfig {
266 fn from(storage: VaultTransitSignerConfigStorage) -> Self {
267 Self {
268 key_name: storage.key_name,
269 address: storage.address,
270 namespace: storage.namespace,
271 role_id: storage.role_id,
272 secret_id: storage.secret_id,
273 pubkey: storage.pubkey,
274 mount_point: storage.mount_point,
275 }
276 }
277}
278
279impl From<TurnkeySignerConfig> for TurnkeySignerConfigStorage {
280 fn from(config: TurnkeySignerConfig) -> Self {
281 Self {
282 api_public_key: config.api_public_key,
283 api_private_key: config.api_private_key,
284 organization_id: config.organization_id,
285 private_key_id: config.private_key_id,
286 public_key: config.public_key,
287 }
288 }
289}
290
291impl From<TurnkeySignerConfigStorage> for TurnkeySignerConfig {
292 fn from(storage: TurnkeySignerConfigStorage) -> Self {
293 Self {
294 api_public_key: storage.api_public_key,
295 api_private_key: storage.api_private_key,
296 organization_id: storage.organization_id,
297 private_key_id: storage.private_key_id,
298 public_key: storage.public_key,
299 }
300 }
301}
302
303impl From<CdpSignerConfig> for CdpSignerConfigStorage {
304 fn from(config: CdpSignerConfig) -> Self {
305 Self {
306 api_key_id: config.api_key_id,
307 api_key_secret: config.api_key_secret,
308 wallet_secret: config.wallet_secret,
309 account_address: config.account_address,
310 }
311 }
312}
313
314impl From<CdpSignerConfigStorage> for CdpSignerConfig {
315 fn from(storage: CdpSignerConfigStorage) -> Self {
316 Self {
317 api_key_id: storage.api_key_id,
318 api_key_secret: storage.api_key_secret,
319 wallet_secret: storage.wallet_secret,
320 account_address: storage.account_address,
321 }
322 }
323}
324
325impl From<GoogleCloudKmsSignerConfig> for GoogleCloudKmsSignerConfigStorage {
326 fn from(config: GoogleCloudKmsSignerConfig) -> Self {
327 Self {
328 service_account: config.service_account.into(),
329 key: config.key.into(),
330 }
331 }
332}
333
334impl From<GoogleCloudKmsSignerConfigStorage> for GoogleCloudKmsSignerConfig {
335 fn from(storage: GoogleCloudKmsSignerConfigStorage) -> Self {
336 Self {
337 service_account: storage.service_account.into(),
338 key: storage.key.into(),
339 }
340 }
341}
342
343impl From<GoogleCloudKmsSignerServiceAccountConfig>
344 for GoogleCloudKmsSignerServiceAccountConfigStorage
345{
346 fn from(config: GoogleCloudKmsSignerServiceAccountConfig) -> Self {
347 Self {
348 private_key: config.private_key,
349 private_key_id: config.private_key_id,
350 project_id: config.project_id,
351 client_email: config.client_email,
352 client_id: config.client_id,
353 auth_uri: config.auth_uri,
354 token_uri: config.token_uri,
355 auth_provider_x509_cert_url: config.auth_provider_x509_cert_url,
356 client_x509_cert_url: config.client_x509_cert_url,
357 universe_domain: config.universe_domain,
358 }
359 }
360}
361
362impl From<GoogleCloudKmsSignerServiceAccountConfigStorage>
363 for GoogleCloudKmsSignerServiceAccountConfig
364{
365 fn from(storage: GoogleCloudKmsSignerServiceAccountConfigStorage) -> Self {
366 Self {
367 private_key: storage.private_key,
368 private_key_id: storage.private_key_id,
369 project_id: storage.project_id,
370 client_email: storage.client_email,
371 client_id: storage.client_id,
372 auth_uri: storage.auth_uri,
373 token_uri: storage.token_uri,
374 auth_provider_x509_cert_url: storage.auth_provider_x509_cert_url,
375 client_x509_cert_url: storage.client_x509_cert_url,
376 universe_domain: storage.universe_domain,
377 }
378 }
379}
380
381impl From<GoogleCloudKmsSignerKeyConfig> for GoogleCloudKmsSignerKeyConfigStorage {
382 fn from(config: GoogleCloudKmsSignerKeyConfig) -> Self {
383 Self {
384 location: config.location,
385 key_ring_id: config.key_ring_id,
386 key_id: config.key_id,
387 key_version: config.key_version,
388 }
389 }
390}
391
392impl From<GoogleCloudKmsSignerKeyConfigStorage> for GoogleCloudKmsSignerKeyConfig {
393 fn from(storage: GoogleCloudKmsSignerKeyConfigStorage) -> Self {
394 Self {
395 location: storage.location,
396 key_ring_id: storage.key_ring_id,
397 key_id: storage.key_id,
398 key_version: storage.key_version,
399 }
400 }
401}
402
403impl SignerRepoModel {
404 pub fn validate(&self) -> Result<(), SignerValidationError> {
406 let core_signer = Signer::from(self.clone());
407 core_signer.validate()
408 }
409}
410
411impl From<SignerConfig> for SignerConfigStorage {
412 fn from(config: SignerConfig) -> Self {
413 match config {
414 SignerConfig::Local(local) => SignerConfigStorage::Local(local.into()),
415 SignerConfig::Vault(vault) => SignerConfigStorage::Vault(vault.into()),
416 SignerConfig::VaultTransit(vault_transit) => {
417 SignerConfigStorage::VaultTransit(vault_transit.into())
418 }
419 SignerConfig::AwsKms(aws_kms) => SignerConfigStorage::AwsKms(aws_kms.into()),
420 SignerConfig::Turnkey(turnkey) => SignerConfigStorage::Turnkey(turnkey.into()),
421 SignerConfig::Cdp(cdp) => SignerConfigStorage::Cdp(cdp.into()),
422 SignerConfig::GoogleCloudKms(gcp) => SignerConfigStorage::GoogleCloudKms(gcp.into()),
423 }
424 }
425}
426
427impl From<SignerConfigStorage> for SignerConfig {
428 fn from(storage: SignerConfigStorage) -> Self {
429 match storage {
430 SignerConfigStorage::Local(local) => SignerConfig::Local(local.into()),
431 SignerConfigStorage::Vault(vault) => SignerConfig::Vault(vault.into()),
432 SignerConfigStorage::VaultTransit(vault_transit) => {
433 SignerConfig::VaultTransit(vault_transit.into())
434 }
435 SignerConfigStorage::AwsKms(aws_kms) => SignerConfig::AwsKms(aws_kms.into()),
436 SignerConfigStorage::Turnkey(turnkey) => SignerConfig::Turnkey(turnkey.into()),
437 SignerConfigStorage::Cdp(cdp) => SignerConfig::Cdp(cdp.into()),
438 SignerConfigStorage::GoogleCloudKms(gcp) => SignerConfig::GoogleCloudKms(gcp.into()),
439 }
440 }
441}
442
443impl SignerConfigStorage {
444 pub fn get_local(&self) -> Option<&LocalSignerConfigStorage> {
446 match self {
447 Self::Local(config) => Some(config),
448 _ => None,
449 }
450 }
451
452 pub fn get_vault_transit(&self) -> Option<&VaultTransitSignerConfigStorage> {
454 match self {
455 Self::VaultTransit(config) => Some(config),
456 _ => None,
457 }
458 }
459
460 pub fn get_vault(&self) -> Option<&VaultSignerConfigStorage> {
462 match self {
463 Self::Vault(config) => Some(config),
464 _ => None,
465 }
466 }
467
468 pub fn get_turnkey(&self) -> Option<&TurnkeySignerConfigStorage> {
470 match self {
471 Self::Turnkey(config) => Some(config),
472 _ => None,
473 }
474 }
475
476 pub fn get_cdp(&self) -> Option<&CdpSignerConfigStorage> {
478 match self {
479 Self::Cdp(config) => Some(config),
480 _ => None,
481 }
482 }
483
484 pub fn get_google_cloud_kms(&self) -> Option<&GoogleCloudKmsSignerConfigStorage> {
486 match self {
487 Self::GoogleCloudKms(config) => Some(config),
488 _ => None,
489 }
490 }
491
492 pub fn get_aws_kms(&self) -> Option<&AwsKmsSignerConfigStorage> {
494 match self {
495 Self::AwsKms(config) => Some(config),
496 _ => None,
497 }
498 }
499}
500
501#[cfg(test)]
502mod tests {
503 use super::*;
504 use crate::models::signer::{LocalSignerConfig, SignerConfig};
505 use secrets::SecretVec;
506
507 #[test]
508 fn test_from_core_signer() {
509 let config = LocalSignerConfig {
510 raw_key: SecretVec::new(32, |v| v.fill(1)),
511 };
512
513 let core =
514 crate::models::signer::Signer::new("test-id".to_string(), SignerConfig::Local(config));
515
516 let repo_model = SignerRepoModel::from(core);
517 assert_eq!(repo_model.id, "test-id");
518 assert!(matches!(repo_model.config, SignerConfigStorage::Local(_)));
519 }
520
521 #[test]
522 fn test_to_core_signer() {
523 use crate::models::signer::AwsKmsSignerConfigStorage;
524
525 let domain_config = AwsKmsSignerConfigStorage {
526 region: Some("us-east-1".to_string()),
527 key_id: "test-key".to_string(),
528 };
529
530 let repo_model = SignerRepoModel {
531 id: "test-id".to_string(),
532 config: SignerConfigStorage::AwsKms(domain_config),
533 };
534
535 let core = Signer::from(repo_model);
536 assert_eq!(core.id, "test-id");
537 assert_eq!(
538 core.signer_type(),
539 crate::models::signer::SignerType::AwsKms
540 );
541 }
542
543 #[test]
544 fn test_validation() {
545 use secrets::SecretVec;
546
547 let domain_config = LocalSignerConfig {
548 raw_key: SecretVec::new(32, |v| v.fill(1)),
549 };
550 let storage_config = LocalSignerConfigStorage::from(domain_config);
552
553 let repo_model = SignerRepoModel {
554 id: "test-id".to_string(),
555 config: SignerConfigStorage::Local(storage_config),
556 };
557
558 assert!(repo_model.validate().is_ok());
559 }
560
561 #[test]
562 fn test_local_config_storage_conversion() {
563 let domain_config = LocalSignerConfig {
564 raw_key: SecretVec::new(4, |v| v.copy_from_slice(&[1, 2, 3, 4])),
565 };
566
567 let storage_config = LocalSignerConfigStorage::from(domain_config.clone());
568 let converted_back = LocalSignerConfig::from(storage_config);
569
570 let original_data = domain_config.raw_key.borrow();
572 let converted_data = converted_back.raw_key.borrow();
573 assert_eq!(*original_data, *converted_data);
574 }
575
576 #[test]
577 fn test_cdp_config_storage_conversion() {
578 use crate::models::SecretString;
579
580 let domain_config = CdpSignerConfig {
581 api_key_id: "test-api-key-id".to_string(),
582 api_key_secret: SecretString::new("test-api-secret"),
583 wallet_secret: SecretString::new("test-wallet-secret"),
584 account_address: "0x1234567890123456789012345678901234567890".to_string(),
585 };
586
587 let storage_config = CdpSignerConfigStorage::from(domain_config.clone());
588 let converted_back = CdpSignerConfig::from(storage_config);
589
590 assert_eq!(domain_config.api_key_id, converted_back.api_key_id);
591 assert_eq!(
592 domain_config.account_address,
593 converted_back.account_address
594 );
595 assert_eq!(
596 domain_config.api_key_secret.to_str(),
597 converted_back.api_key_secret.to_str()
598 );
599 assert_eq!(
600 domain_config.wallet_secret.to_str(),
601 converted_back.wallet_secret.to_str()
602 );
603 }
604
605 #[test]
606 fn test_signer_config_storage_get_cdp() {
607 use crate::models::SecretString;
608
609 let cdp_storage = CdpSignerConfigStorage {
610 api_key_id: "test-id".to_string(),
611 api_key_secret: SecretString::new("secret"),
612 wallet_secret: SecretString::new("wallet-secret"),
613 account_address: "0x1234567890123456789012345678901234567890".to_string(),
614 };
615
616 let config_storage = SignerConfigStorage::Cdp(cdp_storage);
617 let retrieved_cdp = config_storage.get_cdp();
618 assert!(retrieved_cdp.is_some());
619 assert_eq!(retrieved_cdp.unwrap().api_key_id, "test-id");
620 }
621
622 #[test]
623 fn test_signer_config_storage_get_cdp_from_non_cdp() {
624 let aws_storage = AwsKmsSignerConfigStorage {
625 region: Some("us-east-1".to_string()),
626 key_id: "test-key".to_string(),
627 };
628
629 let config_storage = SignerConfigStorage::AwsKms(aws_storage);
630 let retrieved_cdp = config_storage.get_cdp();
631 assert!(retrieved_cdp.is_none());
632 }
633}