1use crate::models::{Signer, SignerConfig, SignerRepoModel, SignerType};
13use serde::{Deserialize, Serialize};
14use utoipa::ToSchema;
15
16#[derive(Debug, Serialize, Deserialize, ToSchema, PartialEq, Eq)]
19#[serde(untagged)]
20#[serde(rename_all = "lowercase")]
21pub enum SignerConfigResponse {
22 #[serde(rename = "plain")]
23 Vault {
24 address: String,
25 namespace: Option<String>,
26 key_name: String,
27 mount_point: Option<String>,
28 },
31 #[serde(rename = "vault_transit")]
32 VaultTransit {
33 key_name: String,
34 address: String,
35 namespace: Option<String>,
36 pubkey: String,
37 mount_point: Option<String>,
38 },
41 #[serde(rename = "aws_kms")]
42 AwsKms {
43 region: Option<String>,
44 key_id: String,
45 },
46 Turnkey {
47 api_public_key: String,
48 organization_id: String,
49 private_key_id: String,
50 public_key: String,
51 },
53 Cdp {
54 api_key_id: String,
55 account_address: String,
56 },
59 #[serde(rename = "google_cloud_kms")]
60 GoogleCloudKms {
61 service_account: GoogleCloudKmsSignerServiceAccountResponseConfig,
62 key: GoogleCloudKmsSignerKeyResponseConfig,
63 },
64 Plain {},
65}
66
67#[derive(Debug, Serialize, Deserialize, ToSchema, PartialEq, Eq)]
68pub struct GoogleCloudKmsSignerServiceAccountResponseConfig {
69 pub project_id: String,
70 pub client_id: String,
71 pub auth_uri: String,
72 pub token_uri: String,
73 pub auth_provider_x509_cert_url: String,
74 pub client_x509_cert_url: String,
75 pub universe_domain: String,
76 }
80
81#[derive(Debug, Serialize, Deserialize, ToSchema, PartialEq, Eq)]
82pub struct GoogleCloudKmsSignerKeyResponseConfig {
83 pub location: String,
84 pub key_ring_id: String,
85 pub key_id: String,
86 pub key_version: u32,
87}
88
89impl From<SignerConfig> for SignerConfigResponse {
90 fn from(config: SignerConfig) -> Self {
91 match config {
92 SignerConfig::Local(_) => SignerConfigResponse::Plain {},
93 SignerConfig::Vault(c) => SignerConfigResponse::Vault {
94 address: c.address,
95 namespace: c.namespace,
96 key_name: c.key_name,
97 mount_point: c.mount_point,
98 },
99 SignerConfig::VaultTransit(c) => SignerConfigResponse::VaultTransit {
100 key_name: c.key_name,
101 address: c.address,
102 namespace: c.namespace,
103 pubkey: c.pubkey,
104 mount_point: c.mount_point,
105 },
106 SignerConfig::AwsKms(c) => SignerConfigResponse::AwsKms {
107 region: c.region,
108 key_id: c.key_id,
109 },
110 SignerConfig::Turnkey(c) => SignerConfigResponse::Turnkey {
111 api_public_key: c.api_public_key,
112 organization_id: c.organization_id,
113 private_key_id: c.private_key_id,
114 public_key: c.public_key,
115 },
116 SignerConfig::Cdp(c) => SignerConfigResponse::Cdp {
117 api_key_id: c.api_key_id,
118 account_address: c.account_address,
119 },
120 SignerConfig::GoogleCloudKms(c) => SignerConfigResponse::GoogleCloudKms {
121 service_account: GoogleCloudKmsSignerServiceAccountResponseConfig {
122 project_id: (*c.service_account.project_id.to_str()).clone(),
123 client_id: (*c.service_account.client_id.to_str()).clone(),
124 auth_uri: (*c.service_account.auth_uri.to_str()).clone(),
125 token_uri: (*c.service_account.token_uri.to_str()).clone(),
126 auth_provider_x509_cert_url: (*c
127 .service_account
128 .auth_provider_x509_cert_url
129 .to_str())
130 .clone(),
131 client_x509_cert_url: (*c.service_account.client_x509_cert_url.to_str())
132 .clone(),
133 universe_domain: (*c.service_account.universe_domain.to_str()).clone(),
134 },
135 key: GoogleCloudKmsSignerKeyResponseConfig {
136 location: (*c.key.location.to_str()).clone(),
137 key_ring_id: (*c.key.key_ring_id.to_str()).clone(),
138 key_id: (*c.key.key_id.to_str()).clone(),
139 key_version: c.key.key_version,
140 },
141 },
142 }
143 }
144}
145
146#[derive(Debug, Serialize, Deserialize, ToSchema)]
147pub struct SignerResponse {
148 pub id: String,
150 pub r#type: SignerType,
152 pub config: SignerConfigResponse,
154}
155
156impl From<SignerRepoModel> for SignerResponse {
157 fn from(repo_model: SignerRepoModel) -> Self {
158 let domain_signer = Signer::from(repo_model);
160
161 Self {
162 id: domain_signer.id.clone(),
163 r#type: domain_signer.signer_type(),
164 config: SignerConfigResponse::from(domain_signer.config),
165 }
166 }
167}
168
169impl From<Signer> for SignerResponse {
170 fn from(signer: Signer) -> Self {
171 Self {
172 id: signer.id.clone(),
173 r#type: signer.signer_type(),
174 config: SignerConfigResponse::from(signer.config),
175 }
176 }
177}
178
179#[cfg(test)]
180mod tests {
181 use super::*;
182 use crate::models::{LocalSignerConfigStorage, SignerConfigStorage};
183 use secrets::SecretVec;
184
185 #[test]
186 fn test_signer_response_from_repo_model() {
187 let repo_model = SignerRepoModel {
188 id: "test-signer".to_string(),
189 config: SignerConfigStorage::Local(LocalSignerConfigStorage {
190 raw_key: SecretVec::new(32, |v| v.copy_from_slice(&[1; 32])),
191 }),
192 };
193
194 let response = SignerResponse::from(repo_model);
195
196 assert_eq!(response.id, "test-signer");
197 assert_eq!(response.r#type, SignerType::Local);
198 assert_eq!(response.config, SignerConfigResponse::Plain {});
199 }
200
201 #[test]
202 fn test_signer_response_from_domain_model() {
203 use crate::models::signer::{AwsKmsSignerConfig, SignerConfig};
204
205 let aws_config = AwsKmsSignerConfig {
206 key_id: "test-key-id".to_string(),
207 region: Some("us-east-1".to_string()),
208 };
209
210 let signer = crate::models::Signer::new(
211 "domain-signer".to_string(),
212 SignerConfig::AwsKms(aws_config),
213 );
214
215 let response = SignerResponse::from(signer);
216
217 assert_eq!(response.id, "domain-signer");
218 assert_eq!(response.r#type, SignerType::AwsKms);
219 assert_eq!(
220 response.config,
221 SignerConfigResponse::AwsKms {
222 region: Some("us-east-1".to_string()),
223 key_id: "test-key-id".to_string(),
224 }
225 );
226 }
227
228 #[test]
229 fn test_signer_type_mapping_from_config() {
230 let test_cases = vec![
231 (
232 SignerConfigStorage::Local(LocalSignerConfigStorage {
233 raw_key: SecretVec::new(32, |v| v.copy_from_slice(&[1; 32])),
234 }),
235 SignerType::Local,
236 SignerConfigResponse::Plain {},
237 ),
238 (
239 SignerConfigStorage::AwsKms(crate::models::AwsKmsSignerConfigStorage {
240 region: Some("us-east-1".to_string()),
241 key_id: "test-key".to_string(),
242 }),
243 SignerType::AwsKms,
244 SignerConfigResponse::AwsKms {
245 region: Some("us-east-1".to_string()),
246 key_id: "test-key".to_string(),
247 },
248 ),
249 ];
250
251 for (config, expected_type, expected_config) in test_cases {
252 let repo_model = SignerRepoModel {
253 id: "test".to_string(),
254 config,
255 };
256
257 let response = SignerResponse::from(repo_model);
258 assert_eq!(
259 response.r#type, expected_type,
260 "Type mapping failed for {:?}",
261 expected_type
262 );
263 assert_eq!(response.config, expected_config);
264 }
265 }
266
267 #[test]
268 fn test_response_serialization() {
269 let response = SignerResponse {
270 id: "test-signer".to_string(),
271 r#type: SignerType::Local,
272 config: SignerConfigResponse::Plain {},
273 };
274
275 let json = serde_json::to_string(&response).unwrap();
276 assert!(json.contains("\"id\":\"test-signer\""));
277 assert!(json.contains("\"type\":\"local\""));
278 }
279
280 #[test]
281 fn test_response_deserialization() {
282 let json = r#"{
283 "id": "test-signer",
284 "type": "aws_kms",
285 "config": {
286 "region": "us-east-1",
287 "key_id": "test-key-id"
288 }
289 }"#;
290
291 let response: SignerResponse = serde_json::from_str(json).unwrap();
292 assert_eq!(response.id, "test-signer");
293 assert_eq!(response.r#type, SignerType::AwsKms);
294 assert_eq!(
295 response.config,
296 SignerConfigResponse::AwsKms {
297 region: Some("us-east-1".to_string()),
298 key_id: "test-key-id".to_string(),
299 }
300 );
301 }
302
303 #[test]
304 fn test_response_deserialization_all_types() {
305 let json = r#"{"id": "test", "type": "google_cloud_kms", "config": {"service_account": {"project_id": "proj", "client_id": "cid", "auth_uri": "auth", "token_uri": "token", "auth_provider_x509_cert_url": "cert", "client_x509_cert_url": "client_cert", "universe_domain": "domain"}, "key": {"location": "loc", "key_ring_id": "ring", "key_id": "key", "key_version": 1}}}"#;
306
307 let response: SignerResponse = serde_json::from_str(json).unwrap();
308 assert_eq!(response.r#type, SignerType::GoogleCloudKms);
309 }
310
311 #[test]
312 fn test_cdp_signer_response_conversion() {
313 use crate::models::signer::{CdpSignerConfig, SignerConfig};
314 use crate::models::SecretString;
315
316 let cdp_config = CdpSignerConfig {
317 api_key_id: "test-api-key-id".to_string(),
318 api_key_secret: SecretString::new("secret"),
319 wallet_secret: SecretString::new("wallet-secret"),
320 account_address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string(),
321 };
322
323 let signer =
324 crate::models::Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(cdp_config));
325
326 let response = SignerResponse::from(signer);
327
328 assert_eq!(response.id, "cdp-signer");
329 assert_eq!(response.r#type, SignerType::Cdp);
330 assert_eq!(
331 response.config,
332 SignerConfigResponse::Cdp {
333 api_key_id: "test-api-key-id".to_string(),
334 account_address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string(),
335 }
336 );
337 }
338
339 #[test]
340 fn test_cdp_response_serialization() {
341 let response = SignerResponse {
342 id: "test-cdp-signer".to_string(),
343 r#type: SignerType::Cdp,
344 config: SignerConfigResponse::Cdp {
345 api_key_id: "test-api-key-id".to_string(),
346 account_address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string(),
347 },
348 };
349
350 let json = serde_json::to_string(&response).unwrap();
351 assert!(json.contains("\"id\":\"test-cdp-signer\""));
352 assert!(json.contains("\"type\":\"cdp\""));
353 assert!(json.contains("\"api_key_id\":\"test-api-key-id\""));
354 assert!(json.contains("\"account_address\":\"0x742d35Cc6634C0532925a3b844Bc454e4438f44f\""));
355
356 assert!(!json.contains("api_key_secret"));
358 assert!(!json.contains("wallet_secret"));
359 }
360
361 #[test]
362 fn test_cdp_response_deserialization() {
363 let json = r#"{
364 "id": "test-cdp-signer",
365 "type": "cdp",
366 "config": {
367 "api_key_id": "test-api-key-id",
368 "account_address": "0x742d35Cc6634C0532925a3b844Bc454e4438f44f"
369 }
370 }"#;
371
372 let response: SignerResponse = serde_json::from_str(json).unwrap();
373 assert_eq!(response.id, "test-cdp-signer");
374 assert_eq!(response.r#type, SignerType::Cdp);
375 assert_eq!(
376 response.config,
377 SignerConfigResponse::Cdp {
378 api_key_id: "test-api-key-id".to_string(),
379 account_address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string(),
380 }
381 );
382 }
383}