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
36pub 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 #[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 #[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
107pub trait Encode {
109 fn encode(&self, buffer: &mut impl BufMut);
111
112 fn encode_to_vec(&self) -> Vec<u8> {
115 let mut buf = Vec::new();
116 self.encode(&mut buf);
117 buf
118 }
119}
120
121pub trait Decode: Sized {
123 fn decode(buffer: &mut impl Buf) -> Result<Self, Error>;
124
125 #[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 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 self.as_bytes().encode(buf)
304 }
305}
306
307impl 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}