dpp/identity/identity_public_key/v0/conversion/
json.rs1use crate::identity::identity_public_key::conversion::json::IdentityPublicKeyJsonConversionMethodsV0;
2use crate::identity::identity_public_key::conversion::platform_value::IdentityPublicKeyPlatformValueConversionMethodsV0;
3use crate::identity::identity_public_key::fields::BINARY_DATA_FIELDS;
4use crate::identity::identity_public_key::v0::IdentityPublicKeyV0;
5use crate::version::PlatformVersion;
6use crate::ProtocolError;
7use platform_value::{ReplacementType, Value};
8use serde_json::Value as JsonValue;
9use std::convert::{TryFrom, TryInto};
10
11impl IdentityPublicKeyJsonConversionMethodsV0 for IdentityPublicKeyV0 {
12 fn to_json_object(&self) -> Result<JsonValue, ProtocolError> {
13 self.to_cleaned_object()?
14 .try_into_validating_json()
15 .map_err(ProtocolError::ValueError)
16 }
17
18 fn to_json(&self) -> Result<JsonValue, ProtocolError> {
19 self.to_cleaned_object()?
20 .try_into()
21 .map_err(ProtocolError::ValueError)
22 }
23
24 fn from_json_object(
25 raw_object: JsonValue,
26 platform_version: &PlatformVersion,
27 ) -> Result<Self, ProtocolError> {
28 let mut value: Value = raw_object.into();
29 value.replace_at_paths(BINARY_DATA_FIELDS, ReplacementType::BinaryBytes)?;
30 Self::from_object(value, platform_version)
31 }
32}
33
34impl TryFrom<&str> for IdentityPublicKeyV0 {
35 type Error = ProtocolError;
36
37 fn try_from(value: &str) -> Result<Self, Self::Error> {
38 let mut platform_value: Value = serde_json::from_str::<JsonValue>(value)
39 .map_err(|e| ProtocolError::StringDecodeError(e.to_string()))?
40 .into();
41 platform_value.replace_at_paths(BINARY_DATA_FIELDS, ReplacementType::BinaryBytes)?;
42 platform_value.try_into().map_err(ProtocolError::ValueError)
43 }
44}
45
46#[cfg(test)]
47mod tests {
48 use super::*;
49 use crate::identity::{KeyType, Purpose, SecurityLevel};
50 use platform_value::BinaryData;
51 use platform_version::version::LATEST_PLATFORM_VERSION;
52
53 fn sample_v0(disabled_at: Option<u64>) -> IdentityPublicKeyV0 {
54 IdentityPublicKeyV0 {
55 id: 1,
56 purpose: Purpose::AUTHENTICATION,
57 security_level: SecurityLevel::MASTER,
58 contract_bounds: None,
59 key_type: KeyType::ECDSA_SECP256K1,
60 read_only: false,
61 data: BinaryData::new(vec![0x01; 33]),
62 disabled_at,
63 }
64 }
65
66 #[test]
67 fn to_json_returns_object() {
68 let key = sample_v0(None);
69 let json = key.to_json().expect("to_json succeeds");
70 let obj = json.as_object().expect("expected json object");
71 assert!(obj.contains_key("id"));
72 assert!(obj.contains_key("type"));
73 assert!(obj.contains_key("purpose"));
74 assert!(obj.contains_key("securityLevel"));
75 assert!(obj.contains_key("readOnly"));
76 assert!(obj.contains_key("data"));
77 assert!(!obj.contains_key("disabledAt"));
79 }
80
81 #[test]
82 fn to_json_includes_disabled_at_when_some() {
83 let key = sample_v0(Some(1_000_000));
84 let json = key.to_json().expect("to_json succeeds");
85 let obj = json.as_object().expect("object");
86 assert!(obj.contains_key("disabledAt"));
87 }
88
89 #[test]
90 fn to_json_object_data_is_byte_array() {
91 let key = sample_v0(None);
93 let json = key.to_json_object().expect("to_json_object succeeds");
94 let obj = json.as_object().expect("object");
95 let data = obj.get("data").expect("data field").as_array().expect(
96 "to_json_object should encode binary data as a JSON array of bytes (validating form)",
97 );
98 assert_eq!(data.len(), 33);
99 }
100
101 #[test]
102 fn from_json_object_roundtrip() {
103 let key = sample_v0(None);
104 let json = key.to_json().unwrap();
105 let back = IdentityPublicKeyV0::from_json_object(json, LATEST_PLATFORM_VERSION).unwrap();
106 assert_eq!(back, key);
107 }
108
109 #[test]
110 fn try_from_str_parses_canonical_json() {
111 let bytes = [0xABu8; 33];
113 let b64 = platform_value::string_encoding::encode(
114 &bytes,
115 platform_value::string_encoding::Encoding::Base64,
116 );
117 let s = format!(
118 r#"{{
119 "id": 7,
120 "type": 0,
121 "purpose": 0,
122 "securityLevel": 0,
123 "readOnly": false,
124 "data": "{}"
125 }}"#,
126 b64
127 );
128 let key: IdentityPublicKeyV0 = s.as_str().try_into().expect("parse succeeds");
129 assert_eq!(key.id, 7);
130 assert_eq!(key.data.as_slice(), &vec![0xABu8; 33][..]);
131 }
132
133 #[test]
134 fn try_from_str_fails_on_invalid_json() {
135 let result = IdentityPublicKeyV0::try_from("not valid json");
136 match result {
137 Err(ProtocolError::StringDecodeError(_)) => {}
138 other => panic!("expected StringDecodeError, got {:?}", other),
139 }
140 }
141
142 #[test]
143 fn try_from_str_fails_when_data_is_not_base64() {
144 let s = r#"{
145 "id": 1,
146 "type": 0,
147 "purpose": 0,
148 "securityLevel": 0,
149 "readOnly": false,
150 "data": "!!!not-base64!!!"
151 }"#;
152 let result = IdentityPublicKeyV0::try_from(s);
153 assert!(result.is_err());
154 }
155
156 #[test]
157 fn from_json_object_fails_on_missing_fields() {
158 let json = serde_json::json!({ "id": 1 });
159 let result = IdentityPublicKeyV0::from_json_object(json, LATEST_PLATFORM_VERSION);
160 assert!(result.is_err());
161 }
162}