1use super::{IncomingBso, IncomingEnvelope, OutgoingBso, OutgoingEnvelope};
9use crate::error;
10use crate::key_bundle::KeyBundle;
11use crate::EncryptedPayload;
12use serde::{de::DeserializeOwned, Deserialize, Serialize};
13
14#[derive(Deserialize, Debug)]
20pub struct IncomingEncryptedBso {
21 #[serde(flatten)]
22 pub envelope: IncomingEnvelope,
23 #[serde(
24 with = "as_json",
25 bound(deserialize = "EncryptedPayload: DeserializeOwned")
26 )]
27 pub(crate) payload: EncryptedPayload,
28}
29
30impl IncomingEncryptedBso {
31 pub fn new(envelope: IncomingEnvelope, payload: EncryptedPayload) -> Self {
32 Self { envelope, payload }
33 }
34 pub fn into_decrypted(self, key: &KeyBundle) -> error::Result<IncomingBso> {
36 Ok(IncomingBso::new(self.envelope, self.payload.decrypt(key)?))
37 }
38}
39
40#[derive(Serialize, Debug)]
41pub struct OutgoingEncryptedBso {
42 #[serde(flatten)]
43 pub envelope: OutgoingEnvelope,
44 #[serde(with = "as_json", bound(serialize = "EncryptedPayload: Serialize"))]
45 payload: EncryptedPayload,
46}
47
48impl OutgoingEncryptedBso {
49 pub fn new(envelope: OutgoingEnvelope, payload: EncryptedPayload) -> Self {
50 Self { envelope, payload }
51 }
52
53 #[inline]
54 pub fn serialized_payload_len(&self) -> usize {
55 self.payload.serialized_len()
56 }
57}
58
59impl OutgoingBso {
60 pub fn into_encrypted(self, key: &KeyBundle) -> error::Result<OutgoingEncryptedBso> {
61 Ok(OutgoingEncryptedBso {
62 envelope: self.envelope,
63 payload: EncryptedPayload::from_cleartext(key, self.payload)?,
64 })
65 }
66}
67
68mod as_json {
82 use serde::de::{self, Deserialize, DeserializeOwned, Deserializer};
83 use serde::ser::{self, Serialize, Serializer};
84
85 pub fn serialize<T, S>(t: &T, serializer: S) -> Result<S::Ok, S::Error>
86 where
87 T: Serialize,
88 S: Serializer,
89 {
90 let j = serde_json::to_string(t).map_err(ser::Error::custom)?;
91 serializer.serialize_str(&j)
92 }
93
94 pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
95 where
96 T: DeserializeOwned,
97 D: Deserializer<'de>,
98 {
99 let j = String::deserialize(deserializer)?;
100 serde_json::from_str(&j).map_err(de::Error::custom)
101 }
102}
103
104#[cfg(test)]
112impl OutgoingEncryptedBso {
113 pub fn payload_serialized_len(&self) -> usize {
115 self.payload.serialized_len()
116 }
117
118 pub fn make_test_bso(ciphertext: String) -> Self {
122 Self {
123 envelope: OutgoingEnvelope {
124 id: "".into(),
125 sortindex: None,
126 ttl: None,
127 },
128 payload: EncryptedPayload {
129 iv: "".into(),
130 hmac: "".into(),
131 ciphertext,
132 },
133 }
134 }
135}
136
137#[cfg(test)]
138mod tests {
139 use super::*;
140 use crate::bso::OutgoingEnvelope;
141
142 #[test]
143 fn test_deserialize_enc() {
144 let serialized = r#"{
145 "id": "1234",
146 "collection": "passwords",
147 "modified": 12344321.0,
148 "payload": "{\"IV\": \"aaaaa\", \"hmac\": \"bbbbb\", \"ciphertext\": \"ccccc\"}"
149 }"#;
150 let record: IncomingEncryptedBso = serde_json::from_str(serialized).unwrap();
151 assert_eq!(&record.envelope.id, "1234");
152 assert_eq!((record.envelope.modified.0 - 12_344_321_000).abs(), 0);
153 assert_eq!(record.envelope.sortindex, None);
154 assert_eq!(&record.payload.iv, "aaaaa");
155 assert_eq!(&record.payload.hmac, "bbbbb");
156 assert_eq!(&record.payload.ciphertext, "ccccc");
157 }
158
159 #[test]
160 fn test_deserialize_autofields() {
161 let serialized = r#"{
162 "id": "1234",
163 "collection": "passwords",
164 "modified": 12344321.0,
165 "sortindex": 100,
166 "ttl": 99,
167 "payload": "{\"IV\": \"aaaaa\", \"hmac\": \"bbbbb\", \"ciphertext\": \"ccccc\"}"
168 }"#;
169 let record: IncomingEncryptedBso = serde_json::from_str(serialized).unwrap();
170 assert_eq!(record.envelope.sortindex, Some(100));
171 assert_eq!(record.envelope.ttl, Some(99));
172 }
173
174 #[test]
175 fn test_serialize_enc() {
176 let goal = r#"{"id":"1234","payload":"{\"IV\":\"aaaaa\",\"hmac\":\"bbbbb\",\"ciphertext\":\"ccccc\"}"}"#;
177 let record = OutgoingEncryptedBso {
178 envelope: OutgoingEnvelope {
179 id: "1234".into(),
180 ..Default::default()
181 },
182 payload: EncryptedPayload {
183 iv: "aaaaa".into(),
184 hmac: "bbbbb".into(),
185 ciphertext: "ccccc".into(),
186 },
187 };
188 let actual = serde_json::to_string(&record).unwrap();
189 assert_eq!(actual, goal);
190
191 let val_str_payload: serde_json::Value = serde_json::from_str(goal).unwrap();
192 assert_eq!(
193 val_str_payload["payload"].as_str().unwrap().len(),
194 record.payload.serialized_len()
195 )
196 }
197}