vta_sdk/protocols/key_management/
import.rs1use serde::{Deserialize, Serialize};
4
5use crate::keys::KeyType;
6
7#[derive(Clone, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
23pub struct ImportKeyBody {
24 #[serde(alias = "key_type")]
25 pub key_type: KeyType,
26 #[serde(
29 default,
30 alias = "private_key_sealed",
31 skip_serializing_if = "Option::is_none"
32 )]
33 pub private_key_sealed: Option<String>,
34 #[serde(
36 default,
37 alias = "private_key_jwe",
38 skip_serializing_if = "Option::is_none"
39 )]
40 pub private_key_jwe: Option<String>,
41 #[serde(
44 default,
45 alias = "private_key_multibase",
46 skip_serializing_if = "Option::is_none"
47 )]
48 pub private_key_multibase: Option<String>,
49 #[serde(default, skip_serializing_if = "Option::is_none")]
50 pub label: Option<String>,
51 #[serde(default, alias = "context_id", skip_serializing_if = "Option::is_none")]
52 pub context_id: Option<String>,
53}
54
55impl std::fmt::Debug for ImportKeyBody {
59 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60 f.debug_struct("ImportKeyBody")
61 .field("key_type", &self.key_type)
62 .field(
63 "private_key_sealed",
64 &self.private_key_sealed.as_ref().map(|_| "<redacted>"),
65 )
66 .field(
67 "private_key_jwe",
68 &self.private_key_jwe.as_ref().map(|_| "<redacted>"),
69 )
70 .field(
71 "private_key_multibase",
72 &self.private_key_multibase.as_ref().map(|_| "<redacted>"),
73 )
74 .field("label", &self.label)
75 .field("context_id", &self.context_id)
76 .finish()
77 }
78}
79
80pub use super::create::CreateKeyResponseBody as ImportKeyResponseBody;
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 #[test]
92 fn accepts_both_spellings_on_intake() {
93 let canonical = serde_json::json!({
94 "keyType": "ed25519",
95 "privateKeySealed": "-----BEGIN SEALED TRANSFER-----",
96 "contextId": "app"
97 });
98 let body: ImportKeyBody = serde_json::from_value(canonical).unwrap();
99 assert_eq!(body.context_id.as_deref(), Some("app"));
100 assert!(body.private_key_sealed.is_some());
101
102 let legacy = serde_json::json!({
103 "key_type": "ed25519",
104 "private_key_sealed": "-----BEGIN SEALED TRANSFER-----",
105 "context_id": "app"
106 });
107 let body: ImportKeyBody = serde_json::from_value(legacy).unwrap();
108 assert_eq!(body.context_id.as_deref(), Some("app"));
109 }
110
111 #[test]
113 fn emits_camel_case() {
114 let body = ImportKeyBody {
115 key_type: KeyType::Ed25519,
116 private_key_sealed: Some("sealed".into()),
117 private_key_jwe: None,
118 private_key_multibase: None,
119 label: None,
120 context_id: Some("app".into()),
121 };
122 let v = serde_json::to_value(&body).unwrap();
123 assert!(v.get("keyType").is_some(), "{v}");
124 assert!(v.get("privateKeySealed").is_some(), "{v}");
125 assert!(v.get("key_type").is_none(), "{v}");
126 }
127
128 #[test]
131 fn debug_redacts_every_carrier() {
132 let body = ImportKeyBody {
133 key_type: KeyType::Ed25519,
134 private_key_sealed: Some("SEALED-SECRET".into()),
135 private_key_jwe: Some("JWE-SECRET".into()),
136 private_key_multibase: Some("z-MULTIBASE-SECRET".into()),
137 label: None,
138 context_id: None,
139 };
140 let rendered = format!("{body:?}");
141 assert!(!rendered.contains("SEALED-SECRET"), "{rendered}");
142 assert!(!rendered.contains("JWE-SECRET"), "{rendered}");
143 assert!(!rendered.contains("MULTIBASE-SECRET"), "{rendered}");
144 assert!(rendered.contains("<redacted>"), "{rendered}");
145 }
146}