emerald_vault/convert/proto/
pk.rs1use crate::{
2 blockchain::EthereumAddress,
3 convert::error::ConversionError,
4 proto::{
5 common::FileType as proto_FileType,
6 crypto::Encrypted as proto_Encrypted,
7 pk::{
8 EthereumPK3 as proto_EthereumPK3,
9 EthereumPrivateKey as proto_EthereumPrivateKey,
10 PrivateKey as proto_PrivateKey,
11 },
12 },
13 structs::{
14 crypto::Encrypted,
15 pk::{EthereumPk3, PrivateKeyHolder, PrivateKeyType},
16 },
17};
18use chrono::{TimeZone, Utc};
19use protobuf::Message;
20use std::{convert::TryFrom, str::FromStr};
21use uuid::Uuid;
22
23impl TryFrom<&[u8]> for PrivateKeyHolder {
25 type Error = ConversionError;
26 fn try_from(data: &[u8]) -> Result<Self, Self::Error> {
27 let m = proto_PrivateKey::parse_from_bytes(data)?;
28 if m.has_ethereum() {
29 let pk = m.get_ethereum();
30 if pk.has_pk() {
31 let pk = pk.get_pk();
32 let key = match &pk.value.clone().into_option() {
33 Some(v) => Encrypted::try_from(v),
34 None => Err(ConversionError::FieldIsEmpty("encrypted".to_string())),
35 }?;
36 let address = match EthereumAddress::from_str(pk.get_address()) {
37 Ok(a) => Some(a),
38 Err(_) => None,
39 };
40 let result = EthereumPk3 { address, key };
41 let pk = PrivateKeyType::EthereumPk(result);
42 let created_at = Utc
43 .timestamp_millis_opt(m.get_created_at() as i64)
44 .single()
45 .unwrap_or_else(|| Utc.timestamp_millis_opt(0).unwrap());
46 let result = PrivateKeyHolder {
47 id: Uuid::from_slice(m.get_id())
48 .map_err(|_| ConversionError::InvalidFieldValue("id".to_string()))?,
49 pk,
50 created_at,
51 };
52 Ok(result)
53 } else {
54 Err(ConversionError::FieldIsEmpty("pk".to_string()))
55 }
56 } else {
57 Err(ConversionError::InvalidFieldValue("pk".to_string()))
58 }
59 }
60}
61
62impl TryFrom<Vec<u8>> for PrivateKeyHolder {
64 type Error = ConversionError;
65
66 fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
67 PrivateKeyHolder::try_from(value.as_slice())
68 }
69}
70
71impl TryFrom<PrivateKeyHolder> for Vec<u8> {
73 type Error = ConversionError;
74
75 fn try_from(value: PrivateKeyHolder) -> Result<Self, Self::Error> {
76 let mut result = proto_PrivateKey::default();
77 result.set_file_type(proto_FileType::FILE_PK);
78 result.set_id(value.id.as_bytes().to_vec());
79 let mut ethereum = proto_EthereumPrivateKey::default();
80 match &value.pk {
81 PrivateKeyType::EthereumPk(it) => {
82 let mut ethereum_pk3 = proto_EthereumPK3::default();
83 if let Some(address) = it.address { ethereum_pk3.set_address(address.to_string()) };
84 ethereum_pk3.set_value(proto_Encrypted::try_from(&it.key)?);
85 ethereum.set_pk(ethereum_pk3);
86 }
87 }
88 result.set_ethereum(ethereum);
89 result.set_created_at(value.created_at.timestamp_millis() as u64);
90 result
91 .write_to_bytes()
92 .map_err(ConversionError::from)
93 }
94}
95
96#[cfg(test)]
97mod tests {
98 use crate::{proto::pk::PrivateKey as proto_PrivateKey, structs::pk::PrivateKeyHolder};
99 use chrono::{TimeZone, Utc};
100 use protobuf::{Message, ProtobufEnum};
101 use std::{
102 convert::{TryFrom, TryInto},
103 str::FromStr,
104 };
105 use uuid::Uuid;
106
107 #[test]
108 fn write_as_protobuf() {
109 let mut pk = PrivateKeyHolder::generate_ethereum_raw("test").unwrap();
110 pk.id = Uuid::from_str("18ba0447-81f3-40d7-bab1-e74de07a1001").unwrap();
111 pk.created_at = Utc.timestamp_millis_opt(1592624592679).unwrap();
112
113 let b: Vec<u8> = pk.try_into().unwrap();
114 assert!(!b.is_empty());
115 let act = proto_PrivateKey::parse_from_bytes(b.as_slice()).unwrap();
116 assert_eq!(act.get_file_type().value(), 2);
117 assert_eq!(
118 Uuid::from_slice(act.get_id()).unwrap(),
119 Uuid::from_str("18ba0447-81f3-40d7-bab1-e74de07a1001").unwrap()
120 );
121 assert!(act.has_ethereum());
122 assert_eq!(act.created_at, 1592624592679);
123 }
124
125 #[test]
126 fn write_and_read() {
127 let mut pk = PrivateKeyHolder::generate_ethereum_raw("test").unwrap();
128 pk.id = Uuid::from_str("18ba0447-81f3-40d7-bab1-e74de07a1001").unwrap();
129 pk.created_at = Utc.timestamp_millis_opt(1592624592679).unwrap();
130
131 let b: Vec<u8> = pk.try_into().unwrap();
132 assert!(!b.is_empty());
133 let act = PrivateKeyHolder::try_from(b).unwrap();
134 assert_eq!(act.id.to_string(), "18ba0447-81f3-40d7-bab1-e74de07a1001");
135 assert!(act.decrypt("test".as_bytes(), None).is_ok());
136 assert_eq!(act.created_at, Utc.timestamp_millis_opt(1592624592679).unwrap());
137 }
138
139 #[test]
140 fn ignore_big_created_at() {
141 let pk = PrivateKeyHolder::generate_ethereum_raw("test").unwrap();
142 let tmp: Vec<u8> = pk.try_into().unwrap();
143 let mut m = proto_PrivateKey::parse_from_bytes(tmp.as_slice()).unwrap();
144 m.set_created_at((i64::MAX as u64) + 100);
145
146 let buf = m.write_to_bytes().unwrap();
147 let act = PrivateKeyHolder::try_from(buf).unwrap();
148 assert_eq!(act.created_at.timestamp_millis(), 0);
149 }
150}