bramble_qr/
scan.rs

1//! BQP scan payloads
2
3use crate::{Commit, Error, Result, BETA_VERSION, CURRENT_VERSION};
4use bramble_crypto::PublicKey;
5use bramble_data::{custom::array_as_bytes, Deserializer, Object, ObjectSerializer, Serializer};
6use serde::{de, Deserialize, Serialize};
7use std::{
8    convert::{TryFrom, TryInto},
9    io::{Cursor, Read, Write},
10    result, slice,
11};
12
13/// A QR code scan payload
14#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
15#[serde(into = "PayloadSerial", try_from = "PayloadSerial")]
16pub struct Payload {
17    commit: Commit,
18    transports: Vec<Descriptor>,
19}
20
21#[derive(Serialize, Deserialize)]
22#[serde(transparent)]
23struct PayloadSerial(Vec<PayloadEntry>);
24
25#[derive(Serialize, Deserialize)]
26#[serde(untagged)]
27enum PayloadEntry {
28    Commit(Commit),
29    Transport(Descriptor),
30}
31
32impl From<Payload> for PayloadSerial {
33    fn from(p: Payload) -> Self {
34        let mut v = vec![PayloadEntry::Commit(p.commit)];
35        v.extend(p.transports.into_iter().map(PayloadEntry::Transport));
36        Self(v)
37    }
38}
39
40impl TryFrom<PayloadSerial> for Payload {
41    type Error = Error;
42
43    fn try_from(p: PayloadSerial) -> Result<Self> {
44        let mut iter = p.0.into_iter();
45        let commit = match iter.next() {
46            Some(PayloadEntry::Commit(commit)) => commit,
47            Some(_) => return Err(Error::InvalidCommitment),
48            None => return Err(Error::EmptyPayload),
49        };
50        let transports = iter
51            .map(|e| match e {
52                PayloadEntry::Transport(d) => Ok(d),
53                _ => Err(Error::InvalidTransport),
54            })
55            .collect::<Result<_>>()?;
56        Ok(Self { commit, transports })
57    }
58}
59
60impl Payload {
61    /// Creates a new payload for a given public key and transports.
62    pub fn new(pk: &PublicKey, transports: Vec<Descriptor>) -> Self {
63        let commit = Commit::derive(pk);
64        Self { commit, transports }
65    }
66
67    /// Reads a payload from a [`Read`] instance.
68    pub fn read_from<R: Read>(r: &mut R) -> Result<Self> {
69        let mut version = 0;
70        r.read_exact(slice::from_mut(&mut version))?;
71        if version == BETA_VERSION {
72            return Err(Error::BetaVersion);
73        }
74        if version < CURRENT_VERSION {
75            return Err(Error::OlderVersion);
76        }
77        if version > CURRENT_VERSION {
78            return Err(Error::NewerVersion);
79        }
80        let mut de = Deserializer::new(r);
81        let value = Self::deserialize(&mut de)?;
82        de.end()?;
83        Ok(value)
84    }
85
86    /// Reads a payload from a byte slice.
87    pub fn from_bytes(mut slice: &[u8]) -> Result<Self> {
88        Self::read_from(&mut slice)
89    }
90
91    /// Writes a payload to a [`Write`] instance.
92    pub fn write_to<W: Write>(&self, w: &mut W) -> Result<()> {
93        w.write_all(&[CURRENT_VERSION])?;
94        let mut ser = Serializer::new(w);
95        self.serialize(&mut ser)?;
96        Ok(())
97    }
98
99    /// Writes a payload to a `Vec<u8>`.
100    pub fn to_bytes(&self) -> Vec<u8> {
101        let mut c = Cursor::new(vec![]);
102        self.write_to(&mut c).expect("writing to vec failed");
103        c.into_inner()
104    }
105
106    /// Gets this payload's commitment.
107    pub fn commit(&self) -> Commit {
108        self.commit
109    }
110
111    /// Gets this payload's transport descriptors.
112    pub fn transports(&self) -> &[Descriptor] {
113        &self.transports
114    }
115}
116
117/// A transport descriptor
118#[derive(Clone, Debug, PartialEq, Serialize)]
119#[serde(untagged)]
120pub enum Descriptor {
121    /// A Bluetooth transport descriptor
122    Bluetooth(BluetoothDescriptor),
123    /// A LAN transport descriptor
124    Lan(LanDescriptor),
125    /// An unknown transport descriptor
126    Unknown(UnknownDescriptor),
127}
128
129impl Descriptor {
130    /// Creates a new Bluetooth transport descriptor without a known address.
131    pub fn bluetooth() -> Self {
132        Self::Bluetooth(BluetoothDescriptor::new())
133    }
134
135    /// Creates a new Bluetooth transport descriptor with a known address.
136    pub fn bluetooth_address(address: [u8; BLUETOOTH_ADDRESS_LEN]) -> Self {
137        Self::Bluetooth(BluetoothDescriptor::with_address(address))
138    }
139
140    /// Creates a new LAN transport descriptor.
141    pub fn lan(address: [u8; IPV4_ADDRESS_LEN], port: u16) -> Self {
142        Self::Lan(LanDescriptor::new(address, port))
143    }
144
145    /// Creates a new unknown transport descriptor.
146    pub fn unknown(id: i64, data: Vec<Object>) -> Self {
147        Self::Unknown(UnknownDescriptor::new(id, data))
148    }
149}
150
151/// A Bluetooth transport descriptor
152#[derive(Clone, Default, Debug, PartialEq, Eq, Serialize, Deserialize)]
153#[serde(into = "UnknownDescriptor", try_from = "UnknownDescriptor")]
154pub struct BluetoothDescriptor {
155    address: Option<[u8; BLUETOOTH_ADDRESS_LEN]>,
156}
157
158impl BluetoothDescriptor {
159    /// Creates a new bluetooth transport descriptor without a known address.
160    pub fn new() -> Self {
161        Self { address: None }
162    }
163
164    /// Creates a new bluetooth transport descriptor with a known address.
165    pub fn with_address(address: [u8; BLUETOOTH_ADDRESS_LEN]) -> Self {
166        Self {
167            address: Some(address),
168        }
169    }
170
171    /// Gets the Bluetooth address, if known.
172    pub fn address(&self) -> Option<[u8; BLUETOOTH_ADDRESS_LEN]> {
173        self.address
174    }
175}
176
177impl From<BluetoothDescriptor> for UnknownDescriptor {
178    fn from(d: BluetoothDescriptor) -> Self {
179        match d.address {
180            Some(address) => {
181                let address_obj = array_as_bytes::serialize(&address, ObjectSerializer)
182                    .expect("failed to convert bluetooth address to object");
183                Self::new(BLUETOOTH_ID, vec![address_obj])
184            }
185            None => Self::new(BLUETOOTH_ID, vec![]),
186        }
187    }
188}
189
190impl TryFrom<UnknownDescriptor> for BluetoothDescriptor {
191    type Error = Error;
192
193    fn try_from(d: UnknownDescriptor) -> Result<Self> {
194        if d.id != BLUETOOTH_ID {
195            return Err(Error::InvalidTransport);
196        }
197
198        match d.data {
199            Object::List(l) if l.is_empty() => Ok(Self::new()),
200            Object::List(mut l) if l.len() == 1 => Ok(Self::with_address(
201                array_as_bytes::deserialize(l.remove(0))?,
202            )),
203            _ => Err(Error::InvalidTransport),
204        }
205    }
206}
207
208/// A LAN transport descriptor
209#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
210#[serde(into = "UnknownDescriptor", try_from = "UnknownDescriptor")]
211pub struct LanDescriptor {
212    id: i64,
213    address: [u8; IPV4_ADDRESS_LEN],
214    port: u16,
215}
216
217impl LanDescriptor {
218    /// Creates a new LAN transport descriptor.
219    pub fn new(address: [u8; IPV4_ADDRESS_LEN], port: u16) -> Self {
220        Self {
221            id: LAN_ID,
222            address,
223            port,
224        }
225    }
226
227    /// Gets the IPv4 address for this transport.
228    pub fn address(&self) -> [u8; IPV4_ADDRESS_LEN] {
229        self.address
230    }
231
232    /// Gets the port for this transport.
233    pub fn port(&self) -> u16 {
234        self.port
235    }
236}
237
238impl From<LanDescriptor> for UnknownDescriptor {
239    fn from(d: LanDescriptor) -> Self {
240        let address_obj = array_as_bytes::serialize(&d.address, ObjectSerializer)
241            .expect("failed to convert IPv4 address to object");
242        let port_obj = d
243            .port
244            .serialize(ObjectSerializer)
245            .expect("failed to convert IPv4 address to object");
246        Self::new(LAN_ID, vec![address_obj, port_obj])
247    }
248}
249
250impl TryFrom<UnknownDescriptor> for LanDescriptor {
251    type Error = Error;
252
253    fn try_from(d: UnknownDescriptor) -> Result<Self> {
254        if d.id != LAN_ID {
255            return Err(Error::InvalidTransport);
256        }
257
258        let mut list = d.data.to_list()?;
259        if list.len() != 2 {
260            return Err(Error::InvalidTransport);
261        }
262        let port_obj = list.remove(1);
263        let address_obj = list.remove(0);
264        Ok(Self {
265            id: LAN_ID,
266            address: array_as_bytes::deserialize(address_obj)?,
267            port: u16::deserialize(port_obj)?,
268        })
269    }
270}
271
272/// An unknown transport descriptor
273#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
274#[serde(into = "UnknownDescriptorSerial", try_from = "UnknownDescriptorSerial")]
275pub struct UnknownDescriptor {
276    id: i64,
277    data: Object,
278}
279
280impl UnknownDescriptor {
281    /// Creates a new unknown transport with the given identifier and described by the given data.
282    pub fn new(id: i64, data: Vec<Object>) -> Self {
283        Self {
284            id,
285            data: Object::List(data),
286        }
287    }
288
289    /// Gets this transport's identifier.
290    pub fn id(&self) -> i64 {
291        self.id
292    }
293
294    /// Gets an object that describes this transport.
295    pub fn data(&self) -> &Object {
296        &self.data
297    }
298}
299
300#[derive(Serialize, Deserialize)]
301#[serde(transparent)]
302struct UnknownDescriptorSerial(Vec<Object>);
303
304impl From<UnknownDescriptor> for UnknownDescriptorSerial {
305    fn from(d: UnknownDescriptor) -> Self {
306        let mut v = vec![Object::Integer(d.id)];
307        match d.data {
308            Object::List(l) => v.extend(l.into_iter()),
309            _ => unreachable!(),
310        }
311        Self(v)
312    }
313}
314
315impl TryFrom<UnknownDescriptorSerial> for UnknownDescriptor {
316    type Error = Error;
317
318    fn try_from(mut d: UnknownDescriptorSerial) -> Result<Self> {
319        let id = d.0.remove(0).to_integer()?;
320        Ok(Self {
321            id,
322            data: Object::List(d.0),
323        })
324    }
325}
326
327impl<'de> Deserialize<'de> for Descriptor {
328    fn deserialize<D>(de: D) -> result::Result<Self, D::Error>
329    where
330        D: de::Deserializer<'de>,
331    {
332        let error_map =
333            |_| de::Error::invalid_type(de::Unexpected::Other("not bluetooth"), &"bluetooth");
334        let unknown = UnknownDescriptor::deserialize(de)?;
335        Ok(match unknown.id {
336            BLUETOOTH_ID => Descriptor::Bluetooth(unknown.try_into().map_err(error_map)?),
337            LAN_ID => Descriptor::Lan(unknown.try_into().map_err(error_map)?),
338            _ => Descriptor::Unknown(unknown),
339        })
340    }
341}
342
343const BLUETOOTH_ID: i64 = 0;
344const LAN_ID: i64 = 1;
345
346const BLUETOOTH_ADDRESS_LEN: usize = 6;
347const IPV4_ADDRESS_LEN: usize = 4;
348
349#[cfg(test)]
350mod test {
351    use super::*;
352    use bramble_data::{from_object, to_object};
353    use hex_literal::hex;
354
355    #[test]
356    fn payload_read_rejects_older_versions() {
357        let mut buf: &[u8] = &hex!("03");
358        let e = Payload::read_from(&mut buf);
359        assert!(e.is_err());
360        let e = e.unwrap_err();
361        assert!(matches!(e, Error::OlderVersion));
362    }
363
364    #[test]
365    fn payload_read_rejects_beta_version() {
366        let mut buf: &[u8] = &hex!("59");
367        let e = Payload::read_from(&mut buf);
368        assert!(e.is_err());
369        let e = e.unwrap_err();
370        assert!(matches!(e, Error::BetaVersion));
371    }
372
373    #[test]
374    fn payload_read_rejects_newer_version() {
375        let mut buf: &[u8] = &hex!("05");
376        let e = Payload::read_from(&mut buf);
377        assert!(e.is_err());
378        let e = e.unwrap_err();
379        assert!(matches!(e, Error::NewerVersion));
380    }
381
382    #[test]
383    fn payload_read_rejects_non_list() {
384        let mut buf: &[u8] = &hex!("04 2180");
385        let e = Payload::read_from(&mut buf);
386        assert!(e.is_err());
387    }
388
389    #[test]
390    fn payload_read_rejects_empty_list() {
391        let mut buf: &[u8] = &hex!("04 6080");
392        let e = Payload::read_from(&mut buf);
393        assert!(e.is_err());
394    }
395
396    #[test]
397    fn payload_read_rejects_data_after_list() {
398        let mut buf: &[u8] = &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 21FF 80 80 00");
399        let e = Payload::read_from(&mut buf);
400        assert!(e.is_err());
401    }
402
403    #[test]
404    fn payload_read_rejects_short_commit() {
405        let mut buf: &[u8] = &hex!("04 60 510F000102030405060708090A0B0C0D0E 60 21FF 80 80");
406        let e = Payload::read_from(&mut buf);
407        assert!(e.is_err());
408    }
409
410    #[test]
411    fn payload_read_rejects_long_commit() {
412        let mut buf: &[u8] = &hex!("04 60 5111000102030405060708090A0B0C0D0E0F10 60 21FF 80 80");
413        let e = Payload::read_from(&mut buf);
414        assert!(e.is_err());
415    }
416
417    #[test]
418    fn payload_read_accepts_without_transports() {
419        let expected = Commit::from(hex!("000102030405060708090A0B0C0D0E0F"));
420        let mut buf: &[u8] = &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 80");
421        let p = Payload::read_from(&mut buf);
422        assert!(p.is_ok());
423        let p = p.unwrap();
424        assert_eq!(p.commit(), expected);
425        assert!(p.transports().is_empty());
426    }
427
428    #[test]
429    fn payload_read_rejects_bluetooth_with_bad_address() {
430        let mut buf: &[u8] =
431            &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2100 220101 80 80");
432        let e = Payload::read_from(&mut buf);
433        assert!(e.is_err());
434    }
435
436    #[test]
437    fn payload_read_accepts_bluetooth_without_address() {
438        let expected = Commit::from(hex!("000102030405060708090A0B0C0D0E0F"));
439        let mut buf: &[u8] = &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2100 80 80");
440        let p = Payload::read_from(&mut buf);
441        assert!(p.is_ok());
442        let p = p.unwrap();
443        assert_eq!(p.commit(), expected);
444        assert_eq!(p.transports().len(), 1);
445        assert_eq!(p.transports()[0], Descriptor::bluetooth());
446    }
447
448    #[test]
449    fn payload_read_accepts_bluetooth_with_address() {
450        let expected = Commit::from(hex!("000102030405060708090A0B0C0D0E0F"));
451        let mut buf: &[u8] =
452            &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2100 5106000102030405 80 80");
453        let p = Payload::read_from(&mut buf);
454        assert!(p.is_ok());
455        let p = p.unwrap();
456        assert_eq!(p.commit(), expected);
457        assert_eq!(p.transports().len(), 1);
458        assert_eq!(
459            p.transports()[0],
460            Descriptor::bluetooth_address([0, 1, 2, 3, 4, 5])
461        );
462    }
463
464    #[test]
465    fn payload_read_rejects_lan_with_bad_address() {
466        let mut buf: &[u8] =
467            &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2101 220101 80 80");
468        let e = Payload::read_from(&mut buf);
469        assert!(e.is_err());
470    }
471
472    #[test]
473    fn payload_read_rejects_lan_without_address() {
474        let mut buf: &[u8] = &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2101 80 80");
475        let e = Payload::read_from(&mut buf);
476        assert!(e.is_err());
477    }
478
479    #[test]
480    fn payload_read_rejects_lan_without_port() {
481        let mut buf: &[u8] =
482            &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2101 510401020304 80 80");
483        let e = Payload::read_from(&mut buf);
484        assert!(e.is_err());
485    }
486
487    #[test]
488    fn payload_read_accepts_lan_with_address_and_port() {
489        let expected = Commit::from(hex!("000102030405060708090A0B0C0D0E0F"));
490        let mut buf: &[u8] =
491            &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2101 510401020304 221020 80 80");
492        let p = Payload::read_from(&mut buf);
493        assert!(p.is_ok());
494        let p = p.unwrap();
495        assert_eq!(p.commit(), expected);
496        assert_eq!(p.transports().len(), 1);
497        assert_eq!(p.transports()[0], Descriptor::lan([1, 2, 3, 4], 4128));
498    }
499
500    #[test]
501    fn payload_read_accepts_unknown_transports() {
502        let expected = Commit::from(hex!("000102030405060708090A0B0C0D0E0F"));
503        let mut buf: &[u8] =
504            &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2159 2101 2102 80 80");
505        let p = Payload::read_from(&mut buf);
506        assert!(p.is_ok());
507        let p = p.unwrap();
508        assert_eq!(p.commit(), expected);
509        assert_eq!(p.transports().len(), 1);
510        assert_eq!(
511            p.transports()[0],
512            Descriptor::unknown(89, vec![Object::Integer(1), Object::Integer(2)])
513        );
514    }
515
516    #[test]
517    fn payload_read_accepts_multiple_transports() {
518        let expected = Commit::from(hex!("000102030405060708090A0B0C0D0E0F"));
519        let mut buf: &[u8] =
520                &hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2101 510401020304 221020 80 60 2100 80 60 2159 220000 80 80");
521        let p = Payload::read_from(&mut buf);
522        assert!(p.is_ok());
523        let p = p.unwrap();
524        assert_eq!(p.commit(), expected);
525        assert_eq!(p.transports().len(), 3);
526        assert_eq!(p.transports()[0], Descriptor::lan([1, 2, 3, 4], 4128));
527        assert_eq!(p.transports()[1], Descriptor::bluetooth());
528        assert_eq!(
529            p.transports()[2],
530            Descriptor::unknown(89, vec![Object::Integer(0)])
531        );
532    }
533
534    #[test]
535    fn payload_to_bytes() {
536        let p = Payload {
537            commit: Commit::from(hex!("000102030405060708090A0B0C0D0E0F")),
538            transports: vec![
539                Descriptor::lan([1, 2, 3, 4], 4128),
540                Descriptor::bluetooth(),
541                Descriptor::bluetooth_address([1, 2, 3, 4, 5, 6]),
542                Descriptor::unknown(89, vec![Object::Integer(17)]),
543            ],
544        };
545        let expected = hex!("04 60 5110000102030405060708090A0B0C0D0E0F 60 2101 510401020304 221020 80 60 2100 80 60 2100 5106010203040506 80 60 2159 2111 80 80");
546        assert_eq!(p.to_bytes(), expected);
547    }
548
549    #[test]
550    fn payload_roundtrips() {
551        let input = Payload {
552            commit: Commit::from(hex!("000102030405060708090A0B0C0D0E0F")),
553            transports: vec![
554                Descriptor::lan([1, 2, 3, 4], 4128),
555                Descriptor::bluetooth(),
556                Descriptor::bluetooth_address([1, 2, 3, 4, 5, 6]),
557                Descriptor::unknown(89, vec![Object::Integer(17)]),
558            ],
559        };
560        let obj = to_object(input.clone()).unwrap();
561        let output = from_object(obj).unwrap();
562
563        assert_eq!(input, output);
564    }
565}
566
567// TODO zero-copy serialization