vta_sdk/protocols/key_management/
create.rs1use chrono::{DateTime, Utc};
2use serde::{Deserialize, Serialize};
3
4use crate::keys::{KeyOrigin, KeyStatus, KeyType};
5
6#[derive(Clone, Serialize, Deserialize)]
7#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
8#[serde(rename_all = "camelCase")]
9pub struct CreateKeyBody {
10 #[serde(alias = "key_type")]
11 pub key_type: KeyType,
12 #[serde(alias = "derivation_path")]
13 pub derivation_path: String,
14 #[serde(default, skip_serializing_if = "Option::is_none")]
18 pub mnemonic: Option<String>,
19 #[serde(default, skip_serializing_if = "Option::is_none")]
20 pub label: Option<String>,
21 #[serde(default, alias = "context_id", skip_serializing_if = "Option::is_none")]
22 pub context_id: Option<String>,
23}
24
25impl std::fmt::Debug for CreateKeyBody {
29 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30 f.debug_struct("CreateKeyBody")
31 .field("key_type", &self.key_type)
32 .field("derivation_path", &self.derivation_path)
33 .field("mnemonic", &self.mnemonic.as_ref().map(|_| "<redacted>"))
34 .field("label", &self.label)
35 .field("context_id", &self.context_id)
36 .finish()
37 }
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
43#[serde(rename_all = "camelCase")]
44#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
45pub struct CreateKeyResultBody {
46 #[serde(alias = "key_id")]
47 pub key_id: String,
48 #[serde(alias = "key_type")]
49 pub key_type: KeyType,
50 #[serde(alias = "derivation_path")]
51 pub derivation_path: String,
52 #[serde(alias = "public_key")]
53 pub public_key: String,
54 pub status: KeyStatus,
55 #[serde(default, skip_serializing_if = "Option::is_none")]
56 pub label: Option<String>,
57 #[serde(default = "default_derived")]
58 pub origin: KeyOrigin,
59 #[serde(alias = "created_at")]
60 pub created_at: DateTime<Utc>,
61}
62
63#[derive(Debug, Clone, Serialize, Deserialize)]
70#[cfg_attr(feature = "openapi", derive(utoipa::ToSchema))]
71pub struct CreateKeyResponseBody {
72 pub key: CreateKeyResultBody,
73}
74
75fn default_derived() -> KeyOrigin {
76 KeyOrigin::Derived
77}
78
79#[cfg(test)]
80mod null_member_tests {
81 use super::*;
82
83 #[test]
108 fn an_unset_member_is_absent_from_the_wire_not_null() {
109 let minimal = CreateKeyBody {
111 key_type: KeyType::Ed25519,
112 derivation_path: String::new(),
113 mnemonic: None,
114 label: None,
115 context_id: None,
116 };
117
118 assert_eq!(
119 serde_json::to_value(&minimal).expect("serialises"),
120 serde_json::json!({"keyType": "ed25519", "derivationPath": ""}),
121 "an unset member must be absent, not null"
122 );
123 }
124
125 #[test]
128 fn a_set_member_still_serialises() {
129 let labelled = CreateKeyBody {
130 key_type: KeyType::Ed25519,
131 derivation_path: "m/26'/2'/0'/1'".into(),
132 mnemonic: None,
133 label: Some("persona-signing".into()),
134 context_id: Some("openvtc".into()),
135 };
136
137 assert_eq!(
138 serde_json::to_value(&labelled).expect("serialises"),
139 serde_json::json!({
140 "keyType": "ed25519",
141 "derivationPath": "m/26'/2'/0'/1'",
142 "label": "persona-signing",
143 "contextId": "openvtc",
144 })
145 );
146 }
147}