radicle_protocol/
wire.rs

1pub mod frame;
2pub mod message;
3pub mod varint;
4
5pub use frame::StreamId;
6pub use message::{AddressType, MessageType};
7
8use std::collections::BTreeMap;
9use std::convert::TryFrom;
10use std::fmt::Debug;
11use std::mem;
12use std::ops::Deref;
13use std::str::FromStr;
14use std::string::FromUtf8Error;
15
16use bytes::{Buf, BufMut};
17
18use cyphernet::addr::tor;
19
20use radicle::crypto::{PublicKey, Signature, Unverified};
21use radicle::git;
22use radicle::git::fmt;
23use radicle::identity::RepoId;
24use radicle::node;
25use radicle::node::Alias;
26use radicle::node::NodeId;
27use radicle::node::Timestamp;
28use radicle::node::UserAgent;
29use radicle::storage::refs::Refs;
30use radicle::storage::refs::RefsAt;
31use radicle::storage::refs::SignedRefs;
32
33use crate::bounded::BoundedVec;
34use crate::service::filter;
35
36/// The default type we use to represent sizes on the wire.
37///
38/// Since wire messages are limited to 64KB by the transport layer,
39/// two bytes is enough to represent any message.
40///
41/// Note that in certain cases, we may use a smaller type.
42pub type Size = u16;
43
44#[derive(thiserror::Error, Debug)]
45pub enum Invalid {
46    #[error("invalid Git object identifier size: expected {expected}, got {actual}")]
47    Oid { expected: usize, actual: usize },
48    #[error(transparent)]
49    Bounded(#[from] crate::bounded::Error),
50    #[error("invalid filter size: {actual}")]
51    FilterSize { actual: usize },
52    #[error("UTF-8 error: {0}")]
53    FromUtf8(#[from] FromUtf8Error),
54    #[error(transparent)]
55    RefName(#[from] fmt::Error),
56    #[error(transparent)]
57    Alias(#[from] node::AliasError),
58    #[error("invalid user agent string: {err}")]
59    InvalidUserAgent { err: String },
60    #[error("invalid onion address: {0}")]
61    OnionAddr(#[from] tor::OnionAddrDecodeError),
62    #[error("invalid timestamp: {actual_millis} millis")]
63    Timestamp { actual_millis: u64 },
64
65    // Message types
66    #[error("invalid control message type: {actual:x}")]
67    ControlType { actual: u8 },
68    #[error("invalid stream type: {actual:x}")]
69    StreamType { actual: u8 },
70    #[error("invalid address type: {actual:x}")]
71    AddressType { actual: u8 },
72    #[error("invalid message type: {actual:x}")]
73    MessageType { actual: u16 },
74    #[error("invalid info message type: {actual:x}")]
75    InfoMessageType { actual: u16 },
76
77    // Protocol version handling
78    #[error("invalid protocol version string: {actual:x?}")]
79    ProtocolVersion { actual: [u8; 4] },
80    #[error("unsupported protocol version: {actual}")]
81    ProtocolVersionUnsupported { actual: u8 },
82}
83
84#[derive(thiserror::Error, Debug)]
85pub enum Error {
86    #[error(transparent)]
87    Invalid(#[from] Invalid),
88
89    #[error("unexpected end of buffer, requested {requested} more bytes but only {available} are available")]
90    UnexpectedEnd { available: usize, requested: usize },
91}
92
93impl From<bytes::TryGetError> for Error {
94    fn from(
95        bytes::TryGetError {
96            available,
97            requested,
98        }: bytes::TryGetError,
99    ) -> Self {
100        Self::UnexpectedEnd {
101            available,
102            requested,
103        }
104    }
105}
106
107/// Things that can be encoded as binary.
108pub trait Encode {
109    /// Encode self by writing it to the given buffer.
110    fn encode(&self, buffer: &mut impl BufMut);
111
112    /// A convenience wrapper around [`Encode::encode`]
113    /// that allocates a [`Vec`].
114    fn encode_to_vec(&self) -> Vec<u8> {
115        let mut buf = Vec::new();
116        self.encode(&mut buf);
117        buf
118    }
119}
120
121/// Things that can be decoded from binary.
122pub trait Decode: Sized {
123    fn decode(buffer: &mut impl Buf) -> Result<Self, Error>;
124
125    /// A convenience wrapper around [`Decode::decode`] to decode
126    /// from a slice exactly.
127    ///
128    /// # Panics
129    ///
130    ///  - If decoding failed because there were not enough bytes.
131    ///  - If there are any bytes left after decoding.
132    #[cfg(test)]
133    fn decode_exact(mut data: &[u8]) -> Result<Self, Invalid> {
134        match Self::decode(&mut data) {
135            Ok(value) => {
136                if !data.is_empty() {
137                    panic!("{} bytes left in buffer", data.len());
138                }
139                Ok(value)
140            }
141            Err(err @ Error::UnexpectedEnd { .. }) => {
142                panic!("{}", err);
143            }
144            Err(Error::Invalid(e)) => Err(e),
145        }
146    }
147}
148
149impl Encode for u8 {
150    fn encode(&self, buf: &mut impl BufMut) {
151        buf.put_u8(*self);
152    }
153}
154
155impl Encode for u16 {
156    fn encode(&self, buf: &mut impl BufMut) {
157        buf.put_u16(*self);
158    }
159}
160
161impl Encode for u32 {
162    fn encode(&self, buf: &mut impl BufMut) {
163        buf.put_u32(*self);
164    }
165}
166
167impl Encode for u64 {
168    fn encode(&self, buf: &mut impl BufMut) {
169        buf.put_u64(*self);
170    }
171}
172
173impl Encode for PublicKey {
174    fn encode(&self, buf: &mut impl BufMut) {
175        self.deref().encode(buf)
176    }
177}
178
179impl<const T: usize> Encode for &[u8; T] {
180    fn encode(&self, buf: &mut impl BufMut) {
181        buf.put_slice(&**self);
182    }
183}
184
185impl<const T: usize> Encode for [u8; T] {
186    fn encode(&self, buf: &mut impl BufMut) {
187        buf.put_slice(self);
188    }
189}
190
191impl<T> Encode for &[T]
192where
193    T: Encode,
194{
195    fn encode(&self, buf: &mut impl BufMut) {
196        (self.len() as Size).encode(buf);
197
198        for item in self.iter() {
199            item.encode(buf);
200        }
201    }
202}
203
204impl<T, const N: usize> Encode for BoundedVec<T, N>
205where
206    T: Encode,
207{
208    fn encode(&self, buf: &mut impl BufMut) {
209        self.as_slice().encode(buf)
210    }
211}
212
213impl Encode for &str {
214    fn encode(&self, buf: &mut impl BufMut) {
215        assert!(self.len() <= u8::MAX as usize);
216
217        (self.len() as u8).encode(buf);
218        let bytes = self.as_bytes();
219
220        // Nb. Don't use the [`Encode`] instance here for &[u8], because we are prefixing the
221        // length ourselves.
222        buf.put_slice(bytes);
223    }
224}
225
226impl Encode for String {
227    fn encode(&self, buf: &mut impl BufMut) {
228        self.as_str().encode(buf)
229    }
230}
231
232impl Encode for git::Url {
233    fn encode(&self, buf: &mut impl BufMut) {
234        self.to_string().encode(buf)
235    }
236}
237
238impl Encode for RepoId {
239    fn encode(&self, buf: &mut impl BufMut) {
240        self.deref().encode(buf)
241    }
242}
243
244impl Encode for Refs {
245    fn encode(&self, buf: &mut impl BufMut) {
246        let len: Size = self
247            .len()
248            .try_into()
249            .expect("`Refs::len()` must be less than or equal to `Size::MAX`");
250        len.encode(buf);
251
252        for (name, oid) in self.iter() {
253            name.as_str().encode(buf);
254            oid.encode(buf);
255        }
256    }
257}
258
259impl Encode for cyphernet::addr::tor::OnionAddrV3 {
260    fn encode(&self, buf: &mut impl BufMut) {
261        self.into_raw_bytes().encode(buf)
262    }
263}
264
265impl Encode for UserAgent {
266    fn encode(&self, buf: &mut impl BufMut) {
267        self.as_ref().encode(buf)
268    }
269}
270
271impl Encode for Alias {
272    fn encode(&self, buf: &mut impl BufMut) {
273        self.as_ref().encode(buf)
274    }
275}
276
277impl<A, B> Encode for (A, B)
278where
279    A: Encode,
280    B: Encode,
281{
282    fn encode(&self, buf: &mut impl BufMut) {
283        self.0.encode(buf);
284        self.1.encode(buf);
285    }
286}
287
288impl Encode for git::RefString {
289    fn encode(&self, buf: &mut impl BufMut) {
290        self.as_str().encode(buf)
291    }
292}
293
294impl Encode for Signature {
295    fn encode(&self, buf: &mut impl BufMut) {
296        self.deref().encode(buf)
297    }
298}
299
300impl Encode for git::Oid {
301    fn encode(&self, buf: &mut impl BufMut) {
302        // Nb. We use length-encoding here to support future SHA-2 object ids.
303        self.as_bytes().encode(buf)
304    }
305}
306
307////////////////////////////////////////////////////////////////////////////////
308
309impl Decode for PublicKey {
310    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
311        let buf: [u8; 32] = Decode::decode(buf)?;
312
313        Ok(PublicKey::from(buf))
314    }
315}
316
317impl Decode for Refs {
318    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
319        let len = Size::decode(buf)?;
320        let mut refs = BTreeMap::new();
321
322        for _ in 0..len {
323            let name = String::decode(buf)?;
324            let name = git::RefString::try_from(name).map_err(Invalid::from)?;
325            let oid = git::Oid::decode(buf)?;
326
327            refs.insert(name, oid);
328        }
329        Ok(refs.into())
330    }
331}
332
333impl Decode for git::RefString {
334    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
335        let ref_str = String::decode(buf)?;
336        Ok(git::RefString::try_from(ref_str).map_err(Invalid::from)?)
337    }
338}
339
340impl Decode for UserAgent {
341    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
342        let user_agent = String::decode(buf)?;
343        Ok(UserAgent::from_str(&user_agent).map_err(|err| Invalid::InvalidUserAgent { err })?)
344    }
345}
346
347impl Decode for Alias {
348    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
349        let alias = String::decode(buf)?;
350        Ok(Alias::from_str(&alias).map_err(Invalid::from)?)
351    }
352}
353
354impl<A, B> Decode for (A, B)
355where
356    A: Decode,
357    B: Decode,
358{
359    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
360        let a = A::decode(buf)?;
361        let b = B::decode(buf)?;
362        Ok((a, b))
363    }
364}
365
366impl Decode for git::Oid {
367    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
368        const LEN_EXPECTED: usize = mem::size_of::<git::raw::Oid>();
369
370        let len = Size::decode(buf)? as usize;
371
372        if len != LEN_EXPECTED {
373            return Err(Invalid::Oid {
374                expected: LEN_EXPECTED,
375                actual: len,
376            }
377            .into());
378        }
379
380        let buf: [u8; LEN_EXPECTED] = Decode::decode(buf)?;
381        let oid = git::raw::Oid::from_bytes(&buf).expect("the buffer is exactly the right size");
382        let oid = git::Oid::from(oid);
383
384        Ok(oid)
385    }
386}
387
388impl Decode for Signature {
389    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
390        let bytes: [u8; 64] = Decode::decode(buf)?;
391
392        Ok(Signature::from(bytes))
393    }
394}
395
396impl Decode for u8 {
397    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
398        Ok(buf.try_get_u8()?)
399    }
400}
401
402impl Decode for u16 {
403    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
404        Ok(buf.try_get_u16()?)
405    }
406}
407
408impl Decode for u32 {
409    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
410        Ok(buf.try_get_u32()?)
411    }
412}
413
414impl Decode for u64 {
415    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
416        Ok(buf.try_get_u64()?)
417    }
418}
419
420impl<const N: usize> Decode for [u8; N] {
421    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
422        let mut ary = [0; N];
423        buf.try_copy_to_slice(&mut ary).map_err(Error::from)?;
424
425        Ok(ary)
426    }
427}
428
429impl<T, const N: usize> Decode for BoundedVec<T, N>
430where
431    T: Decode,
432{
433    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
434        let len: usize = Size::decode(buf)? as usize;
435        let mut items = Self::with_capacity(len).map_err(Invalid::from)?;
436
437        for _ in 0..items.capacity() {
438            let item = T::decode(buf)?;
439            items.push(item).ok();
440        }
441        Ok(items)
442    }
443}
444
445impl Decode for String {
446    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
447        let len = u8::decode(buf)?;
448        let mut bytes = vec![0; len as usize];
449
450        buf.try_copy_to_slice(&mut bytes)?;
451
452        let string = String::from_utf8(bytes).map_err(Invalid::from)?;
453
454        Ok(string)
455    }
456}
457
458impl Decode for RepoId {
459    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
460        let oid: git::Oid = Decode::decode(buf)?;
461
462        Ok(Self::from(oid))
463    }
464}
465
466impl Encode for filter::Filter {
467    fn encode(&self, buf: &mut impl BufMut) {
468        self.deref().as_bytes().encode(buf);
469    }
470}
471
472impl Decode for filter::Filter {
473    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
474        let size: usize = Size::decode(buf)? as usize;
475        if !filter::FILTER_SIZES.contains(&size) {
476            return Err(Invalid::FilterSize { actual: size }.into());
477        }
478
479        let mut bytes = vec![0; size];
480
481        buf.try_copy_to_slice(&mut bytes)?;
482
483        let f = filter::BloomFilter::from(bytes);
484        debug_assert_eq!(f.hashes(), filter::FILTER_HASHES);
485
486        Ok(Self::from(f))
487    }
488}
489
490impl<V> Encode for SignedRefs<V> {
491    fn encode(&self, buf: &mut impl BufMut) {
492        self.id.encode(buf);
493        self.refs.encode(buf);
494        self.signature.encode(buf);
495    }
496}
497
498impl Decode for SignedRefs<Unverified> {
499    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
500        let id = NodeId::decode(buf)?;
501        let refs = Refs::decode(buf)?;
502        let signature = Signature::decode(buf)?;
503
504        Ok(Self::new(refs, id, signature))
505    }
506}
507
508impl Encode for RefsAt {
509    fn encode(&self, buf: &mut impl BufMut) {
510        self.remote.encode(buf);
511        self.at.encode(buf);
512    }
513}
514
515impl Decode for RefsAt {
516    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
517        let remote = NodeId::decode(buf)?;
518        let at = git::Oid::decode(buf)?;
519        Ok(Self { remote, at })
520    }
521}
522
523impl Encode for node::Features {
524    fn encode(&self, buf: &mut impl BufMut) {
525        self.deref().encode(buf)
526    }
527}
528
529impl Decode for node::Features {
530    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
531        let features = u64::decode(buf)?;
532
533        Ok(Self::from(features))
534    }
535}
536
537impl Decode for tor::OnionAddrV3 {
538    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
539        let bytes: [u8; tor::ONION_V3_RAW_LEN] = Decode::decode(buf)?;
540        let addr = tor::OnionAddrV3::from_raw_bytes(bytes).map_err(Invalid::from)?;
541
542        Ok(addr)
543    }
544}
545
546impl Encode for Timestamp {
547    fn encode(&self, buf: &mut impl BufMut) {
548        self.deref().encode(buf)
549    }
550}
551
552impl Decode for Timestamp {
553    fn decode(buf: &mut impl Buf) -> Result<Self, Error> {
554        let millis = u64::decode(buf)?;
555        let ts = Timestamp::try_from(millis).map_err(|value| Invalid::Timestamp {
556            actual_millis: value,
557        })?;
558
559        Ok(ts)
560    }
561}
562
563#[cfg(test)]
564mod tests {
565    use super::*;
566    use qcheck;
567    use qcheck_macros::quickcheck;
568
569    use radicle::assert_matches;
570    use radicle::crypto::Unverified;
571    use radicle::storage::refs::SignedRefs;
572
573    #[quickcheck]
574    fn prop_u8(input: u8) {
575        assert_eq!(u8::decode_exact(&input.encode_to_vec()).unwrap(), input);
576    }
577
578    #[quickcheck]
579    fn prop_u16(input: u16) {
580        assert_eq!(u16::decode_exact(&input.encode_to_vec()).unwrap(), input);
581    }
582
583    #[quickcheck]
584    fn prop_u32(input: u32) {
585        assert_eq!(u32::decode_exact(&input.encode_to_vec()).unwrap(), input);
586    }
587
588    #[quickcheck]
589    fn prop_u64(input: u64) {
590        assert_eq!(u64::decode_exact(&input.encode_to_vec()).unwrap(), input);
591    }
592
593    #[quickcheck]
594    fn prop_string(input: String) -> qcheck::TestResult {
595        if input.len() > u8::MAX as usize {
596            return qcheck::TestResult::discard();
597        }
598        assert_eq!(String::decode_exact(&input.encode_to_vec()).unwrap(), input);
599
600        qcheck::TestResult::passed()
601    }
602
603    #[quickcheck]
604    fn prop_vec(input: BoundedVec<String, 16>) {
605        assert_eq!(
606            BoundedVec::<String, 16>::decode_exact(&input.encode_to_vec()).unwrap(),
607            input
608        );
609    }
610
611    #[quickcheck]
612    fn prop_pubkey(input: PublicKey) {
613        assert_eq!(
614            PublicKey::decode_exact(&input.encode_to_vec()).unwrap(),
615            input
616        );
617    }
618
619    #[quickcheck]
620    fn prop_filter(input: filter::Filter) {
621        assert_eq!(
622            filter::Filter::decode_exact(&input.encode_to_vec()).unwrap(),
623            input
624        );
625    }
626
627    #[quickcheck]
628    fn prop_id(input: RepoId) {
629        assert_eq!(RepoId::decode_exact(&input.encode_to_vec()).unwrap(), input);
630    }
631
632    #[quickcheck]
633    fn prop_refs(input: Refs) {
634        assert_eq!(Refs::decode_exact(&input.encode_to_vec()).unwrap(), input);
635    }
636
637    #[quickcheck]
638    fn prop_tuple(input: (String, String)) {
639        assert_eq!(
640            <(String, String)>::decode_exact(&input.encode_to_vec()).unwrap(),
641            input
642        );
643    }
644
645    #[quickcheck]
646    fn prop_signature(input: [u8; 64]) {
647        let signature = Signature::from(input);
648
649        assert_eq!(
650            Signature::decode_exact(&signature.encode_to_vec()).unwrap(),
651            signature
652        );
653    }
654
655    #[quickcheck]
656    fn prop_oid(input: [u8; 20]) {
657        let oid = git::Oid::try_from(input.as_slice()).unwrap();
658
659        assert_eq!(git::Oid::decode_exact(&oid.encode_to_vec()).unwrap(), oid);
660    }
661
662    #[quickcheck]
663    fn prop_signed_refs(input: SignedRefs<Unverified>) {
664        assert_eq!(
665            SignedRefs::<Unverified>::decode_exact(&input.encode_to_vec()).unwrap(),
666            input
667        );
668    }
669
670    #[test]
671    fn test_string() {
672        assert_eq!(
673            String::from("hello").encode_to_vec(),
674            vec![5, b'h', b'e', b'l', b'l', b'o']
675        );
676    }
677
678    #[test]
679    fn test_alias() {
680        assert_eq!(
681            Alias::from_str("hello").unwrap().encode_to_vec(),
682            vec![5, b'h', b'e', b'l', b'l', b'o']
683        );
684    }
685
686    #[test]
687    fn test_filter_invalid() {
688        let b = bloomy::BloomFilter::with_size(filter::FILTER_SIZE_M / 3);
689        let f = filter::Filter::from(b);
690        let bytes = f.encode_to_vec();
691
692        assert_matches!(
693            filter::Filter::decode_exact(&bytes).unwrap_err(),
694            Invalid::FilterSize { .. }
695        );
696    }
697
698    #[test]
699    fn test_bounded_vec_limit() {
700        let v: BoundedVec<u8, 2> = vec![1, 2].try_into().unwrap();
701        let buf = &v.encode_to_vec();
702
703        assert_matches!(
704            BoundedVec::<u8, 1>::decode_exact(buf),
705            Err(Invalid::Bounded(crate::bounded::Error::InvalidSize {
706                expected: 1,
707                actual: 2
708            })),
709            "fail when vector is too small for buffer",
710        );
711
712        assert!(
713            BoundedVec::<u8, 2>::decode_exact(buf).is_ok(),
714            "successfully decode vector of same size",
715        );
716    }
717}