#![forbid(unsafe_code)]
pub mod message;
pub mod packet;
pub use message::{CallMeMaybe, Message, Ping, Pong, TxId};
pub use packet::{MAX_PACKET, open, seal};
pub const MAGIC: [u8; 6] = [0x54, 0x53, 0xf0, 0x9f, 0x92, 0xac];
pub const NONCE_LEN: usize = 24;
pub const TAG_LEN: usize = 16;
pub const HEADER_LEN: usize = MAGIC.len() + 32 + NONCE_LEN;
pub fn is_disco(datagram: &[u8]) -> bool {
datagram.starts_with(&MAGIC)
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Error {
Malformed,
Decryption,
Unsupported,
BufferTooSmall,
}
impl core::fmt::Display for Error {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str(match self {
Self::Malformed => "malformed disco packet",
Self::Decryption => "the disco box did not open",
Self::Unsupported => "unsupported disco message",
Self::BufferTooSmall => "output buffer too small",
})
}
}
impl core::error::Error for Error {}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_magic_is_the_bytes_of_ts_and_a_speech_bubble() {
assert_eq!(MAGIC.len(), 6);
assert_eq!(&MAGIC, "TS\u{1f4ac}".as_bytes());
assert_eq!(&MAGIC[..2], b"TS");
}
#[test]
fn disco_is_told_from_wireguard_by_its_first_byte() {
assert!(is_disco(&MAGIC));
for wireguard_type in 1u8..=4 {
let datagram = [wireguard_type, 0, 0, 0, 0, 0, 0, 0];
assert!(!is_disco(&datagram), "type {wireguard_type} read as disco");
}
assert!(!is_disco(b"TS"), "a prefix of the magic is not the magic");
assert!(!is_disco(&[]));
}
}