plabble_codec/codec/response/
response_body.rs

1use crate::{
2    abstractions::{
3        Serializable,
4        SerializationError::{self, InvalidFormat, MissingInfo},
5        SerializationInfo, KEY_SIZE, SIGNATURE_SIZE, TYPE_APPEND, TYPE_CONNECT, TYPE_CREATE,
6        TYPE_ERROR, TYPE_PUT, TYPE_REQUEST, TYPE_SUBSCRIBE, TYPE_UNSUBSCRIBE, TYPE_WIPE,
7    },
8    codec::{
9        common::{assert_len, SlotBody},
10        objects::Certificate,
11        ptp_packet::PtpBody,
12    },
13};
14
15/// The body of a response packet
16///
17/// # Variants
18///
19/// * `CONNECT` - the response to a connect request
20/// * `CREATE` - the response to a create request
21/// * `PUT` - the response to a put request
22/// * `APPEND` - the response to an append request
23/// * `WIPE` - the response to a wipe request
24/// * `REQUEST` - the response to a request request
25/// * `SUBSCRIBE` - the response to a subscribe request
26/// * `UNSUBSCRIBE` - the response to an unsubscribe request
27pub enum ResponseBody {
28    CONNECT {
29        pub_key: [u8; KEY_SIZE],
30        signature: [u8; SIGNATURE_SIZE],
31        certificates: Vec<Certificate>,
32    },
33    CREATE,
34    PUT,
35    APPEND,
36    WIPE,
37    REQUEST {
38        slots: SlotBody,
39    },
40    SUBSCRIBE {
41        slots: Option<SlotBody>,
42    },
43    UNSUBSCRIBE,
44    ERROR(u8, String),
45}
46
47impl PtpBody for ResponseBody {
48    fn packet_type(&self) -> u8 {
49        match self {
50            ResponseBody::CONNECT { .. } => TYPE_CONNECT,
51            ResponseBody::CREATE => TYPE_CREATE,
52            ResponseBody::PUT => TYPE_PUT,
53            ResponseBody::APPEND => TYPE_APPEND,
54            ResponseBody::WIPE => TYPE_WIPE,
55            ResponseBody::REQUEST { .. } => TYPE_REQUEST,
56            ResponseBody::SUBSCRIBE { .. } => TYPE_SUBSCRIBE,
57            ResponseBody::UNSUBSCRIBE => TYPE_UNSUBSCRIBE,
58            ResponseBody::ERROR(..) => TYPE_ERROR,
59        }
60    }
61}
62
63impl Serializable for ResponseBody {
64    fn size(&self) -> usize {
65        match self {
66            ResponseBody::CONNECT {
67                pub_key: _,
68                signature: _,
69                certificates,
70            } => {
71                KEY_SIZE
72                    + SIGNATURE_SIZE
73                    + certificates.iter().map(|c| c.size()).sum::<usize>()
74                    + certificates.len()
75            }
76            ResponseBody::REQUEST { slots } => slots.size(),
77            ResponseBody::SUBSCRIBE { slots: Some(slots) } => slots.size(),
78            ResponseBody::SUBSCRIBE { slots: None } => 0,
79            ResponseBody::ERROR(_, e) => 1 + e.len(),
80            _ => 0,
81        }
82    }
83
84    fn get_bytes(&self) -> Vec<u8> {
85        let mut buff = Vec::new();
86        match self {
87            ResponseBody::CONNECT {
88                pub_key,
89                signature,
90                certificates,
91            } => {
92                buff.extend_from_slice(pub_key);
93                buff.extend_from_slice(signature);
94                for c in certificates.iter() {
95                    let mut bytes = c.get_bytes();
96                    buff.push(bytes.len() as u8);
97                    buff.append(&mut bytes);
98                }
99            }
100            ResponseBody::REQUEST { slots } => {
101                buff = slots.get_bytes();
102            }
103            ResponseBody::SUBSCRIBE { slots: Some(slots) } => {
104                buff = slots.get_bytes();
105            }
106            ResponseBody::ERROR(code, err) => {
107                buff.push(*code);
108                buff.extend_from_slice(err.as_bytes());
109            }
110            _ => (),
111        }
112
113        buff
114    }
115
116    fn from_bytes(data: &[u8], info: Option<SerializationInfo>) -> Result<Self, SerializationError>
117    where
118        Self: Sized,
119    {
120        if let Some(SerializationInfo::PacketType(packet_type)) = info {
121            match packet_type {
122                TYPE_CONNECT => {
123                    let len = KEY_SIZE + SIGNATURE_SIZE;
124                    assert_len(data, len)?;
125                    let mut pub_key = [0u8; KEY_SIZE];
126                    pub_key.copy_from_slice(&data[..KEY_SIZE]);
127                    let mut signature = [0u8; SIGNATURE_SIZE];
128                    signature.copy_from_slice(&data[KEY_SIZE..len]);
129
130                    let mut certificates = Vec::new();
131                    let mut bytes_read = len;
132                    while bytes_read != data.len() {
133                        assert_len(data, bytes_read + 1)?;
134                        let cert_len = data[bytes_read] as usize;
135                        bytes_read += 1;
136                        assert_len(data, cert_len)?;
137                        certificates.push(Certificate::from_bytes(
138                            &data[bytes_read..(bytes_read + cert_len)],
139                            None,
140                        )?);
141                        bytes_read += cert_len;
142                    }
143
144                    Ok(ResponseBody::CONNECT {
145                        pub_key,
146                        signature,
147                        certificates,
148                    })
149                }
150                TYPE_CREATE => Ok(ResponseBody::CREATE),
151                TYPE_PUT => Ok(ResponseBody::PUT),
152                TYPE_APPEND => Ok(ResponseBody::APPEND),
153                TYPE_WIPE => Ok(ResponseBody::WIPE),
154                TYPE_REQUEST => Ok(ResponseBody::REQUEST {
155                    slots: SlotBody::from_bytes(data, None)?,
156                }),
157                TYPE_SUBSCRIBE => Ok(ResponseBody::SUBSCRIBE {
158                    slots: if !data.is_empty() {
159                        Some(SlotBody::from_bytes(data, None)?)
160                    } else {
161                        None
162                    },
163                }),
164                TYPE_UNSUBSCRIBE => Ok(ResponseBody::UNSUBSCRIBE),
165                TYPE_ERROR => {
166                    assert_len(data, 1)?;
167                    let res = String::from_utf8_lossy(&data[1..]).to_string();
168                    Ok(ResponseBody::ERROR(data[0], res))
169                }
170                _ => Err(InvalidFormat(format!(
171                    "Packet type {} is not supported",
172                    packet_type
173                ))),
174            }
175        } else {
176            Err(MissingInfo(String::from("Missing info parameter")))
177        }
178    }
179}
180
181#[cfg(test)]
182mod parse_test {
183    use time_macros::datetime;
184
185    use crate::abstractions::Serializable;
186
187    use super::*;
188
189    #[test]
190    fn can_parse_connect_wo_certs() {
191        let connect = &[
192            1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
193            0, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
194            0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
195            0, 0, 0, 0, 0, 0, 0, 0, 0,
196        ];
197        let connect =
198            ResponseBody::from_bytes(connect, Some(SerializationInfo::PacketType(0))).unwrap();
199
200        assert_eq!(96, connect.size());
201        assert_eq!(0, connect.packet_type());
202
203        if let ResponseBody::CONNECT {
204            pub_key,
205            signature,
206            certificates,
207        } = connect
208        {
209            assert_eq!(
210                &[
211                    1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 1, 2, 3, 4, 5, 6,
212                    7, 8, 9, 0, 1, 2
213                ],
214                &pub_key
215            );
216            assert_eq!(&[0u8; 64], &signature);
217            assert_eq!(0, certificates.len());
218        } else {
219            panic!("Not a connect");
220        }
221    }
222
223    #[test]
224    fn can_parse_connect_with_2_certs() {
225        let mut connect = Vec::new();
226        connect.extend_from_slice(&[1u8; 32]);
227        connect.extend_from_slice(&[0u8; 64]);
228        let mut cert1 = Certificate {
229            public_key: [2u8; 32],
230            signature: [3u8; 64],
231            valid_from: datetime!(2020-01-01 00:00:00 UTC),
232            valid_to: datetime!(2020-01-01 00:00:00 UTC),
233            domain_or_ip: String::from("cert.plabble.org"),
234        }
235        .get_bytes();
236        let mut cert2 = Certificate {
237            public_key: [3u8; 32],
238            signature: [4u8; 64],
239            valid_from: datetime!(2020-01-01 00:00:00 UTC),
240            valid_to: datetime!(2020-01-01 00:00:00 UTC),
241            domain_or_ip: String::from("cert2.plabble.org"),
242        }
243        .get_bytes();
244        connect.push(cert1.len() as u8);
245        connect.append(&mut cert1);
246        connect.push(cert2.len() as u8);
247        connect.append(&mut cert2);
248
249        let conn = ResponseBody::from_bytes(&connect, Some(SerializationInfo::PacketType(0)));
250        let conn = conn.unwrap();
251        assert_eq!(connect.len(), conn.size());
252
253        if let ResponseBody::CONNECT {
254            pub_key,
255            signature,
256            certificates,
257        } = conn
258        {
259            assert_eq!(&[1u8; 32], &pub_key);
260            assert_eq!(&[0u8; 64], &signature);
261            assert_eq!(2, certificates.len());
262            assert_eq!(&[2u8; 32], &certificates[0].public_key);
263            assert_eq!("cert.plabble.org", &certificates[0].domain_or_ip);
264            assert_eq!(&[3u8; 32], &certificates[1].public_key);
265            assert_eq!("cert2.plabble.org", &certificates[1].domain_or_ip);
266        } else {
267            panic!("Not a connect");
268        }
269    }
270
271    #[test]
272    fn can_parse_subscribe_without_slots() {
273        let bytes = &[];
274        let subscribe =
275            ResponseBody::from_bytes(bytes, Some(SerializationInfo::PacketType(6))).unwrap();
276
277        assert_eq!(0, subscribe.size());
278        if let ResponseBody::SUBSCRIBE { slots } = subscribe {
279            assert_eq!(slots, None);
280        } else {
281            panic!("Not a subscribe");
282        }
283    }
284
285    #[test]
286    fn can_deserialize_error() {
287        let bytes = &[7, 97, 110, 32, 101, 114, 114, 111, 114, 33];
288        let error =
289            ResponseBody::from_bytes(bytes, Some(SerializationInfo::PacketType(15))).unwrap();
290
291        assert_eq!(10, error.size());
292        if let ResponseBody::ERROR(code, e) = error {
293            assert_eq!("an error!", &e);
294            assert_eq!(7, code);
295        } else {
296            panic!("not an error");
297        }
298    }
299}
300
301#[cfg(test)]
302mod serialize_test {
303    use super::*;
304
305    #[test]
306    fn can_serialize_connect_wo_certificates() {
307        let expected = &[
308            1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
309            25, 26, 27, 28, 29, 30, 31, 32, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
310            17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38,
311            39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60,
312            61, 62, 63, 64,
313        ];
314        let mut pub_key = [0u8; 32];
315        pub_key.copy_from_slice((1u8..=32).collect::<Vec<u8>>().as_slice());
316        let mut signature = [0u8; 64];
317        signature.copy_from_slice((1u8..=64).collect::<Vec<u8>>().as_slice());
318
319        let connect = ResponseBody::CONNECT {
320            pub_key,
321            signature,
322            certificates: Vec::new(),
323        };
324        assert_eq!(&connect.get_bytes(), expected);
325    }
326
327    #[test]
328    fn can_serialize_subscribe_without_range() {
329        let subscribe = ResponseBody::SUBSCRIBE { slots: None };
330        assert_eq!(Vec::<u8>::new(), subscribe.get_bytes());
331    }
332
333    #[test]
334    fn can_serialize_error() {
335        let error = ResponseBody::ERROR(7, String::from("an error!"));
336        let bytes = error.get_bytes();
337        assert_eq!(vec![7, 97, 110, 32, 101, 114, 114, 111, 114, 33], bytes);
338    }
339}