Skip to main content

libsignal_service/
utils.rs

1mod phonenumber;
2use libsignal_core::{Aci, Pni, ServiceId};
3pub use phonenumber::*;
4use uuid::Uuid;
5
6// Signal sometimes adds padding, sometimes it does not.
7// This requires a custom decoding engine.
8// This engine is as general as possible.
9pub const BASE64_RELAXED: base64::engine::GeneralPurpose =
10    base64::engine::GeneralPurpose::new(
11        &base64::alphabet::STANDARD,
12        base64::engine::GeneralPurposeConfig::new()
13            .with_encode_padding(true)
14            .with_decode_padding_mode(
15                base64::engine::DecodePaddingMode::Indifferent,
16            ),
17    );
18
19pub fn parse_aci_with_fallback(
20    bytes: Option<&[u8]>,
21    utf8: Option<&str>,
22) -> Option<Aci> {
23    let binary = bytes.and_then(|bytes| {
24        let bytes = bytes
25            .try_into()
26            .inspect_err(|_e| tracing::warn!("binary ACI not 16 bytes"))
27            .ok()?;
28        Some(Aci::from_uuid_bytes(bytes))
29    });
30
31    binary.or_else(|| {
32        let utf8 = utf8?;
33        match Aci::parse_from_service_id_string(utf8) {
34            Some(sid) => Some(sid),
35            None => {
36                tracing::warn!("unparseable utf8 ACI");
37                None
38            },
39        }
40    })
41}
42
43pub fn parse_pni_with_fallback(
44    bytes: Option<&[u8]>,
45    utf8: Option<&str>,
46    pni_is_uuid: bool,
47) -> Option<Pni> {
48    let binary = bytes.and_then(|bytes| {
49        let bytes = bytes
50            .try_into()
51            .inspect_err(|_e| tracing::warn!("binary PNI not 16 bytes"))
52            .ok()?;
53        Some(Pni::from_uuid_bytes(bytes))
54    });
55
56    binary.or_else(|| {
57        let utf8 = utf8?;
58        if pni_is_uuid {
59            let uuid: uuid::Uuid = utf8
60                .parse()
61                .inspect_err(|e| {
62                    tracing::warn!(error = %e, "unparseable UUID");
63                })
64                .ok()?;
65            Some(Pni::from_uuid_bytes(*uuid.as_bytes()))
66        } else {
67            match Pni::parse_from_service_id_string(utf8) {
68                Some(sid) => Some(sid),
69                None => {
70                    tracing::warn!("unparseable utf8 PNI");
71                    None
72                },
73            }
74        }
75    })
76}
77
78/// Deserialize a [`ServiceId`] from its `"ACI:uuid"` / `"PNI:uuid"` server
79/// string form.
80pub fn deserialize_service_id<'de, D>(
81    deserializer: D,
82) -> Result<ServiceId, D::Error>
83where
84    D: serde::Deserializer<'de>,
85{
86    use serde::Deserialize;
87    let s = <&'de str>::deserialize(deserializer)?;
88    ServiceId::parse_from_service_id_string(s).ok_or_else(|| {
89        serde::de::Error::custom(format!("invalid service id: {s}"))
90    })
91}
92
93pub fn parse_service_id_with_fallback(
94    bytes: Option<&[u8]>,
95    utf8: Option<&str>,
96) -> Option<ServiceId> {
97    let binary = bytes.and_then(|bytes| {
98        match ServiceId::parse_from_service_id_binary(bytes) {
99            Some(sid) => Some(sid),
100            None => {
101                tracing::warn!("unparseable binary ServiceId");
102                None
103            },
104        }
105    });
106
107    binary.or_else(|| {
108        let utf8 = utf8?;
109        match ServiceId::parse_from_service_id_string(utf8) {
110            Some(sid) => Some(sid),
111            None => {
112                tracing::warn!("unparseable utf8 ServiceId");
113                None
114            },
115        }
116    })
117}
118
119/// Parse protobuf UUIDs specified in both binary and utf8 formats
120///
121/// Prefers the binary format
122pub fn parse_uuid_with_fallback(
123    binary: Option<&[u8]>,
124    utf8: Option<&str>,
125) -> Option<Uuid> {
126    let binary = binary
127        .map(<[u8; 16]>::try_from)
128        .transpose()
129        .inspect_err(|_e| tracing::warn!("invalid binary UUID length"))
130        .ok()
131        .flatten()
132        .map(Uuid::from_bytes);
133
134    binary.or_else(|| {
135        let utf8 = utf8?;
136        utf8.parse()
137            .inspect_err(|e| tracing::warn!(error=%e, "unparseable UUID"))
138            .ok()
139    })
140}
141
142pub fn random_length_padding<R: rand::Rng + rand::CryptoRng>(
143    csprng: &mut R,
144    max_len: usize,
145) -> Vec<u8> {
146    let length = csprng.random_range(0..max_len);
147    let mut padding = vec![0u8; length];
148    csprng.fill_bytes(&mut padding);
149    padding
150}
151
152pub mod serde_base64 {
153    use super::BASE64_RELAXED;
154    use base64::prelude::*;
155    use serde::{Deserialize, Deserializer, Serializer};
156
157    pub fn serialize<T, S>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error>
158    where
159        T: AsRef<[u8]>,
160        S: Serializer,
161    {
162        serializer.serialize_str(&BASE64_RELAXED.encode(bytes.as_ref()))
163    }
164
165    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
166    where
167        D: Deserializer<'de>,
168    {
169        use serde::de::Error;
170        <&str>::deserialize(deserializer).and_then(|string| {
171            BASE64_RELAXED
172                .decode(string)
173                .map_err(|err| Error::custom(err.to_string()))
174        })
175    }
176}
177
178pub mod serde_optional_base64 {
179    use super::BASE64_RELAXED;
180    use base64::prelude::*;
181    use serde::{Deserialize, Deserializer, Serializer};
182
183    use super::serde_base64;
184
185    pub fn serialize<T, S>(
186        bytes: &Option<T>,
187        serializer: S,
188    ) -> Result<S::Ok, S::Error>
189    where
190        T: AsRef<[u8]>,
191        S: Serializer,
192    {
193        match bytes {
194            Some(bytes) => serde_base64::serialize(bytes, serializer),
195            None => serializer.serialize_none(),
196        }
197    }
198
199    pub fn deserialize<'de, D>(
200        deserializer: D,
201    ) -> Result<Option<Vec<u8>>, D::Error>
202    where
203        D: Deserializer<'de>,
204    {
205        use serde::de::Error;
206        match Option::<String>::deserialize(deserializer)? {
207            Some(s) => BASE64_RELAXED
208                .decode(s)
209                .map_err(|err| Error::custom(err.to_string()))
210                .map(Some),
211            None => Ok(None),
212        }
213    }
214}
215
216pub mod serde_optional_base64_url_safe_no_pad {
217    use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
218    use serde::{Deserialize, Deserializer, Serializer};
219
220    use super::serde_base64_url_safe_no_pad;
221
222    pub fn serialize<T, S>(
223        bytes: &Option<T>,
224        serializer: S,
225    ) -> Result<S::Ok, S::Error>
226    where
227        T: AsRef<[u8]>,
228        S: Serializer,
229    {
230        match bytes {
231            Some(bytes) => {
232                serde_base64_url_safe_no_pad::serialize(bytes, serializer)
233            },
234            None => serializer.serialize_none(),
235        }
236    }
237
238    pub fn deserialize<'de, D>(
239        deserializer: D,
240    ) -> Result<Option<Vec<u8>>, D::Error>
241    where
242        D: Deserializer<'de>,
243    {
244        use serde::de::Error;
245        match Option::<String>::deserialize(deserializer)? {
246            Some(s) => BASE64_URL_SAFE_NO_PAD
247                .decode(s)
248                .map_err(|err| Error::custom(err.to_string()))
249                .map(Some),
250            None => Ok(None),
251        }
252    }
253}
254
255pub mod serde_base64_url_safe_no_pad {
256    use base64::{prelude::BASE64_URL_SAFE_NO_PAD, Engine};
257    use serde::{Deserialize, Deserializer, Serializer};
258
259    pub fn serialize<T, S>(bytes: &T, serializer: S) -> Result<S::Ok, S::Error>
260    where
261        T: AsRef<[u8]>,
262        S: Serializer,
263    {
264        serializer.serialize_str(&BASE64_URL_SAFE_NO_PAD.encode(bytes.as_ref()))
265    }
266
267    pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
268    where
269        D: Deserializer<'de>,
270    {
271        use serde::de::Error;
272        <&str>::deserialize(deserializer).and_then(|string| {
273            BASE64_URL_SAFE_NO_PAD
274                .decode(string)
275                .map_err(|err| Error::custom(err.to_string()))
276        })
277    }
278}
279
280pub mod serde_identity_key {
281    use super::BASE64_RELAXED;
282    use base64::prelude::*;
283    use libsignal_protocol::IdentityKey;
284    use serde::{Deserialize, Deserializer, Serializer};
285
286    pub fn serialize<S>(
287        public_key: &IdentityKey,
288        serializer: S,
289    ) -> Result<S::Ok, S::Error>
290    where
291        S: Serializer,
292    {
293        let public_key = public_key.serialize();
294        serializer.serialize_str(&BASE64_RELAXED.encode(&public_key))
295    }
296
297    pub fn deserialize<'de, D>(deserializer: D) -> Result<IdentityKey, D::Error>
298    where
299        D: Deserializer<'de>,
300    {
301        IdentityKey::decode(
302            &BASE64_RELAXED
303                .decode(<&str>::deserialize(deserializer)?)
304                .map_err(serde::de::Error::custom)?,
305        )
306        .map_err(serde::de::Error::custom)
307    }
308}
309
310pub mod serde_optional_identity_key {
311    use super::BASE64_RELAXED;
312    use base64::prelude::*;
313    use libsignal_protocol::IdentityKey;
314    use serde::{Deserialize, Deserializer, Serializer};
315
316    use super::serde_identity_key;
317
318    pub fn serialize<S>(
319        public_key: &Option<IdentityKey>,
320        serializer: S,
321    ) -> Result<S::Ok, S::Error>
322    where
323        S: Serializer,
324    {
325        match public_key {
326            Some(public_key) => {
327                serde_identity_key::serialize(public_key, serializer)
328            },
329            None => serializer.serialize_none(),
330        }
331    }
332
333    pub fn deserialize<'de, D>(
334        deserializer: D,
335    ) -> Result<Option<IdentityKey>, D::Error>
336    where
337        D: Deserializer<'de>,
338    {
339        match Option::<String>::deserialize(deserializer)? {
340            Some(public_key) => Ok(Some(
341                IdentityKey::decode(
342                    &BASE64_RELAXED
343                        .decode(public_key)
344                        .map_err(serde::de::Error::custom)?,
345                )
346                .map_err(serde::de::Error::custom)?,
347            )),
348            None => Ok(None),
349        }
350    }
351}
352
353pub mod serde_private_key {
354    use super::BASE64_RELAXED;
355    use base64::prelude::*;
356    use libsignal_protocol::PrivateKey;
357    use serde::{Deserialize, Deserializer, Serializer};
358
359    pub fn serialize<S>(
360        public_key: &PrivateKey,
361        serializer: S,
362    ) -> Result<S::Ok, S::Error>
363    where
364        S: Serializer,
365    {
366        let public_key = public_key.serialize();
367        serializer.serialize_str(&BASE64_RELAXED.encode(public_key))
368    }
369
370    pub fn deserialize<'de, D>(deserializer: D) -> Result<PrivateKey, D::Error>
371    where
372        D: Deserializer<'de>,
373    {
374        PrivateKey::deserialize(
375            &BASE64_RELAXED
376                .decode(<&str>::deserialize(deserializer)?)
377                .map_err(serde::de::Error::custom)?,
378        )
379        .map_err(serde::de::Error::custom)
380    }
381}
382
383pub mod serde_optional_private_key {
384    use super::BASE64_RELAXED;
385    use base64::prelude::*;
386    use libsignal_protocol::PrivateKey;
387    use serde::{Deserialize, Deserializer, Serializer};
388
389    use super::serde_private_key;
390
391    pub fn serialize<S>(
392        private_key: &Option<PrivateKey>,
393        serializer: S,
394    ) -> Result<S::Ok, S::Error>
395    where
396        S: Serializer,
397    {
398        match private_key {
399            Some(private_key) => {
400                serde_private_key::serialize(private_key, serializer)
401            },
402            None => serializer.serialize_none(),
403        }
404    }
405
406    pub fn deserialize<'de, D>(
407        deserializer: D,
408    ) -> Result<Option<PrivateKey>, D::Error>
409    where
410        D: Deserializer<'de>,
411    {
412        match Option::<String>::deserialize(deserializer)? {
413            Some(private_key) => Ok(Some(
414                PrivateKey::deserialize(
415                    &BASE64_RELAXED
416                        .decode(private_key)
417                        .map_err(serde::de::Error::custom)?,
418                )
419                .map_err(serde::de::Error::custom)?,
420            )),
421            None => Ok(None),
422        }
423    }
424}
425
426pub mod serde_optional_e164 {
427    use libsignal_core::E164;
428    use serde::{Deserialize, Deserializer, Serializer};
429
430    pub fn serialize<S>(
431        phone_number: &Option<E164>,
432        serializer: S,
433    ) -> Result<S::Ok, S::Error>
434    where
435        S: Serializer,
436    {
437        match phone_number {
438            Some(p) => serializer.serialize_str(&p.to_string()),
439            None => serializer.serialize_none(),
440        }
441    }
442
443    pub fn deserialize<'de, D>(
444        deserializer: D,
445    ) -> Result<Option<E164>, D::Error>
446    where
447        D: Deserializer<'de>,
448    {
449        match Option::<String>::deserialize(deserializer)? {
450            Some(s) => s.parse().map_err(serde::de::Error::custom).map(Some),
451            None => Ok(None),
452        }
453    }
454}
455
456pub mod serde_e164 {
457    use libsignal_core::E164;
458    use serde::{Deserialize, Deserializer, Serializer};
459
460    pub fn serialize<S>(
461        phone_number: &E164,
462        serializer: S,
463    ) -> Result<S::Ok, S::Error>
464    where
465        S: Serializer,
466    {
467        serializer.serialize_str(&phone_number.to_string())
468    }
469
470    pub fn deserialize<'de, D>(deserializer: D) -> Result<E164, D::Error>
471    where
472        D: Deserializer<'de>,
473    {
474        <&str>::deserialize(deserializer)?
475            .parse()
476            .map_err(serde::de::Error::custom)
477    }
478}
479
480#[cfg(feature = "phonenumber")]
481pub mod serde_phone_number {
482    use phonenumber::PhoneNumber;
483    use serde::{Deserialize, Deserializer, Serializer};
484
485    pub fn serialize<S>(
486        phone_number: &PhoneNumber,
487        serializer: S,
488    ) -> Result<S::Ok, S::Error>
489    where
490        S: Serializer,
491    {
492        serializer.serialize_str(&phone_number.to_string())
493    }
494
495    pub fn deserialize<'de, D>(deserializer: D) -> Result<PhoneNumber, D::Error>
496    where
497        D: Deserializer<'de>,
498    {
499        phonenumber::parse(None, <&str>::deserialize(deserializer)?)
500            .map_err(serde::de::Error::custom)
501    }
502}
503
504pub mod serde_service_id {
505    use libsignal_protocol::ServiceId;
506    use serde::{Deserialize, Deserializer, Serializer};
507
508    pub fn serialize<S>(
509        service_id: &ServiceId,
510        serializer: S,
511    ) -> Result<S::Ok, S::Error>
512    where
513        S: Serializer,
514    {
515        serializer.serialize_str(&service_id.service_id_string())
516    }
517
518    pub fn deserialize<'de, D>(deserializer: D) -> Result<ServiceId, D::Error>
519    where
520        D: Deserializer<'de>,
521    {
522        ServiceId::parse_from_service_id_string(<&str>::deserialize(
523            deserializer,
524        )?)
525        .ok_or_else(|| serde::de::Error::custom("invalid service ID string"))
526    }
527}
528
529pub mod serde_aci {
530    use libsignal_core::Aci;
531    use serde::{Deserialize, Deserializer, Serializer};
532
533    pub fn serialize<S>(aci: &Aci, serializer: S) -> Result<S::Ok, S::Error>
534    where
535        S: Serializer,
536    {
537        serializer.serialize_str(&aci.service_id_string())
538    }
539
540    pub fn deserialize<'de, D>(deserializer: D) -> Result<Aci, D::Error>
541    where
542        D: Deserializer<'de>,
543    {
544        Aci::parse_from_service_id_string(<&str>::deserialize(deserializer)?)
545            .ok_or_else(|| serde::de::Error::custom("invalid ACI string"))
546    }
547}
548
549pub mod serde_device_id {
550    use libsignal_core::DeviceId;
551    use serde::{Deserialize, Deserializer, Serializer};
552
553    pub fn serialize<S>(id: &DeviceId, serializer: S) -> Result<S::Ok, S::Error>
554    where
555        S: Serializer,
556    {
557        serializer.serialize_u8(u8::from(*id))
558    }
559
560    pub fn deserialize<'de, D>(deserializer: D) -> Result<DeviceId, D::Error>
561    where
562        D: Deserializer<'de>,
563    {
564        DeviceId::try_from(u8::deserialize(deserializer)?)
565            .map_err(|_| serde::de::Error::custom("invalid device id"))
566    }
567}
568
569pub mod serde_device_id_vec {
570    use libsignal_core::DeviceId;
571    use serde::{ser::SerializeSeq, Deserialize, Deserializer, Serializer};
572
573    pub fn serialize<S>(
574        ids: &Vec<DeviceId>,
575        serializer: S,
576    ) -> Result<S::Ok, S::Error>
577    where
578        S: Serializer,
579    {
580        let mut seq = serializer.serialize_seq(Some(ids.len()))?;
581        for id in ids {
582            seq.serialize_element(&u8::from(*id))?;
583        }
584        seq.end()
585    }
586
587    pub fn deserialize<'de, D>(
588        deserializer: D,
589    ) -> Result<Vec<DeviceId>, D::Error>
590    where
591        D: Deserializer<'de>,
592    {
593        Vec::<u8>::deserialize(deserializer)?
594            .into_iter()
595            .map(DeviceId::try_from)
596            .collect::<Result<Vec<_>, _>>()
597            .map_err(|_| serde::de::Error::custom("invalid device id"))
598    }
599}
600
601pub mod serde_prost_base64 {
602    use super::BASE64_RELAXED;
603    use base64::Engine;
604    use prost::Message;
605    use serde::{Deserialize, Deserializer, Serializer};
606
607    // Serializes a Prost message into a Base64 string
608    pub fn serialize<T, S>(value: &T, serializer: S) -> Result<S::Ok, S::Error>
609    where
610        T: Message,
611        S: Serializer,
612    {
613        let b64 = BASE64_RELAXED.encode(value.encode_to_vec());
614        serializer.serialize_str(&b64)
615    }
616
617    // Deserializes a Base64 string back into a Prost message
618    pub fn deserialize<'de, T, D>(deserializer: D) -> Result<T, D::Error>
619    where
620        T: Message + Default,
621        D: Deserializer<'de>,
622    {
623        let bytes = BASE64_RELAXED
624            .decode(<&str>::deserialize(deserializer)?)
625            .map_err(serde::de::Error::custom)?;
626
627        T::decode(bytes.as_slice()).map_err(serde::de::Error::custom)
628    }
629}
630
631pub mod serde_optional_prost_base64 {
632    use base64::Engine;
633    use prost::Message;
634    use serde::{Deserialize, Deserializer, Serializer};
635
636    use super::{serde_prost_base64, BASE64_RELAXED};
637
638    pub fn serialize<T, S>(
639        value: &Option<T>,
640        serializer: S,
641    ) -> Result<S::Ok, S::Error>
642    where
643        T: Message,
644        S: Serializer,
645    {
646        match value {
647            Some(msg) => serde_prost_base64::serialize(msg, serializer),
648            None => serializer.serialize_none(),
649        }
650    }
651
652    pub fn deserialize<'de, T, D>(
653        deserializer: D,
654    ) -> Result<Option<T>, D::Error>
655    where
656        T: Message + Default,
657        D: Deserializer<'de>,
658    {
659        match Option::<String>::deserialize(deserializer)? {
660            Some(s) => {
661                let bytes = BASE64_RELAXED
662                    .decode(s)
663                    .map_err(serde::de::Error::custom)?;
664                let msg = T::decode(bytes.as_slice())
665                    .map_err(serde::de::Error::custom)?;
666                Ok(Some(msg))
667            },
668            None => Ok(None),
669        }
670    }
671}