cfxstore/json/
vault_key_file.rs1use super::{Crypto, Uuid, Version, H160};
18use serde::de::Error;
19use serde_derive::{Deserialize, Serialize};
20use serde_json::{self, error, value::Value};
21use std::io::{Read, Write};
22
23const VAULT_NAME_META_KEY: &str = "vault";
25
26#[derive(Debug, PartialEq, Serialize, Deserialize)]
28pub struct VaultKeyFile {
29 pub id: Uuid,
31 pub version: Version,
33 pub crypto: Crypto,
35 pub metacrypto: Crypto,
37}
38
39#[derive(Debug, PartialEq, Serialize, Deserialize)]
41pub struct VaultKeyMeta {
42 pub address: H160,
44 pub name: Option<String>,
46 pub meta: Option<String>,
48}
49
50pub fn insert_vault_name_to_json_meta(
52 meta: &str, vault_name: &str,
53) -> Result<String, error::Error> {
54 let mut meta = if meta.is_empty() {
55 Value::Object(serde_json::Map::new())
56 } else {
57 serde_json::from_str(meta)?
58 };
59
60 if let Some(meta_obj) = meta.as_object_mut() {
61 meta_obj.insert(
62 VAULT_NAME_META_KEY.to_owned(),
63 Value::String(vault_name.to_owned()),
64 );
65 serde_json::to_string(meta_obj)
66 } else {
67 Err(error::Error::custom(
68 "Meta is expected to be a serialized JSON object",
69 ))
70 }
71}
72
73pub fn remove_vault_name_from_json_meta(
75 meta: &str,
76) -> Result<String, error::Error> {
77 let mut meta = if meta.is_empty() {
78 Value::Object(serde_json::Map::new())
79 } else {
80 serde_json::from_str(meta)?
81 };
82
83 if let Some(meta_obj) = meta.as_object_mut() {
84 meta_obj.remove(VAULT_NAME_META_KEY);
85 serde_json::to_string(meta_obj)
86 } else {
87 Err(error::Error::custom(
88 "Meta is expected to be a serialized JSON object",
89 ))
90 }
91}
92
93impl VaultKeyFile {
94 pub fn load<R>(reader: R) -> Result<Self, serde_json::Error>
95 where R: Read {
96 serde_json::from_reader(reader)
97 }
98
99 pub fn write<W>(&self, writer: &mut W) -> Result<(), serde_json::Error>
100 where W: Write {
101 serde_json::to_writer(writer, self)
102 }
103}
104
105impl VaultKeyMeta {
106 pub fn load(bytes: &[u8]) -> Result<Self, serde_json::Error> {
107 serde_json::from_slice(&bytes)
108 }
109
110 pub fn write(&self) -> Result<Vec<u8>, serde_json::Error> {
111 let s = serde_json::to_string(self)?;
112 Ok(s.as_bytes().into())
113 }
114}
115
116#[cfg(test)]
117mod test {
118 use crate::json::{
119 insert_vault_name_to_json_meta, remove_vault_name_from_json_meta,
120 Aes128Ctr, Cipher, Crypto, Kdf, Pbkdf2, Prf, VaultKeyFile, Version,
121 };
122 use serde_json;
123
124 #[test]
125 fn to_and_from_json() {
126 let file = VaultKeyFile {
127 id: "08d82c39-88e3-7a71-6abb-89c8f36c3ceb".into(),
128 version: Version::V3,
129 crypto: Crypto {
130 cipher: Cipher::Aes128Ctr(Aes128Ctr {
131 iv: "fecb968bbc8c7e608a89ebcfe53a41d0".into(),
132 }),
133 ciphertext: "4befe0a66d9a4b6fec8e39eb5c90ac5dafdeaab005fff1af665fd1f9af925c91".into(),
134 kdf: Kdf::Pbkdf2(Pbkdf2 {
135 c: 10240,
136 dklen: 32,
137 prf: Prf::HmacSha256,
138 salt: "f17731e84ecac390546692dbd4ccf6a3a2720dc9652984978381e61c28a471b2".into(),
139 }),
140 mac: "7c7c3daafb24cf11eb3079dfb9064a11e92f309a0ee1dd676486bab119e686b7".into(),
141 },
142 metacrypto: Crypto {
143 cipher: Cipher::Aes128Ctr(Aes128Ctr {
144 iv: "9c353fb3f894fc05946843616c26bb3f".into(),
145 }),
146 ciphertext: "fef0d113d7576c1702daf380ad6f4c5408389e57991cae2a174facd74bd549338e1014850bddbab7eb486ff5f5c9c5532800c6a6d4db2be2212cd5cd3769244ab230e1f369e8382a9e6d7c0a".into(),
147 kdf: Kdf::Pbkdf2(Pbkdf2 {
148 c: 10240,
149 dklen: 32,
150 prf: Prf::HmacSha256,
151 salt: "aca82865174a82249a198814b263f43a631f272cbf7ed329d0f0839d259c652a".into(),
152 }),
153 mac: "b7413946bfe459d2801268dc331c04b3a84d92be11ef4dd9a507f895e8d9b5bd".into(),
154 }
155 };
156
157 let serialized = serde_json::to_string(&file).unwrap();
158 let deserialized = serde_json::from_str(&serialized).unwrap();
159
160 assert_eq!(file, deserialized);
161 }
162
163 #[test]
164 fn vault_name_inserted_to_json_meta() {
165 assert_eq!(
166 insert_vault_name_to_json_meta(r#""#, "MyVault").unwrap(),
167 r#"{"vault":"MyVault"}"#
168 );
169 assert_eq!(
170 insert_vault_name_to_json_meta(
171 r#"{"tags":["kalabala"]}"#,
172 "MyVault"
173 )
174 .unwrap(),
175 r#"{"tags":["kalabala"],"vault":"MyVault"}"#
176 );
177 }
178
179 #[test]
180 fn vault_name_not_inserted_to_json_meta() {
181 assert!(
182 insert_vault_name_to_json_meta(r#"///3533"#, "MyVault").is_err()
183 );
184 assert!(
185 insert_vault_name_to_json_meta(r#""string""#, "MyVault").is_err()
186 );
187 }
188
189 #[test]
190 fn vault_name_removed_from_json_meta() {
191 assert_eq!(
192 remove_vault_name_from_json_meta(r#"{"vault":"MyVault"}"#).unwrap(),
193 r#"{}"#
194 );
195 assert_eq!(
196 remove_vault_name_from_json_meta(
197 r#"{"tags":["kalabala"],"vault":"MyVault"}"#
198 )
199 .unwrap(),
200 r#"{"tags":["kalabala"]}"#
201 );
202 }
203
204 #[test]
205 fn vault_name_not_removed_from_json_meta() {
206 assert!(remove_vault_name_from_json_meta(r#"///3533"#).is_err());
207 assert!(remove_vault_name_from_json_meta(r#""string""#).is_err());
208 }
209}