use crate::{ ack::Ack, advert::Advert, anon_req::AnonReq, multipart::MultiPart, path::Path, request::Request, response::Response, text::{GroupData, GroupText, Text}, trace::Trace, }; use bytes::{Buf, Bytes}; #[cfg(feature = "std")] use crate::std_identity::Keystore; #[derive(PartialEq, Clone, core::fmt::Debug)] pub enum PacketContent { Request(Request), Response(Response), Text(Text), Ack(Ack), Advert(Advert), GroupText(GroupText), GroupData(GroupData), AnonReq(AnonReq), Path(Path), Trace(Trace), Multipart(MultiPart), Raw(Raw), Invalid, } impl PacketContent { fn justified_name(&self) -> &str { match self { PacketContent::Request(_) => " REQUEST | ", PacketContent::Response(_) => " RESPONSE | ", PacketContent::Text(_) => " TEXT | ", PacketContent::Ack(_) => " ACK | ", PacketContent::Advert(_) => " ADVERT | ", PacketContent::GroupText(_) => " GROUP TXT | ", PacketContent::GroupData(_) => " GRP. DATA | ", PacketContent::AnonReq(_) => " ANON REQ. | ", PacketContent::Path(_) => " PATH | ", PacketContent::Trace(_) => " TRACE | ", PacketContent::Multipart(_) => " MULTIPART | ", PacketContent::Raw(_) => " RAW | ", PacketContent::Invalid => " INVALID | ", } } pub fn new(header: u8, bytes: Bytes) -> PacketContent { // Specialize based on the Payload Type from the header match (header & 0x3C) >> 2 { 0x00 => PacketContent::Request(Request::from(bytes)), 0x01 => PacketContent::Response(Response::from(bytes)), 0x02 => PacketContent::Text(Text::from(bytes)), 0x03 => PacketContent::Ack(Ack::from(bytes)), 0x04 => PacketContent::Advert(Advert::from(bytes)), 0x05 => PacketContent::GroupText(GroupText::from(bytes)), 0x06 => PacketContent::GroupData(GroupData::from(bytes)), 0x07 => PacketContent::AnonReq(AnonReq::from(bytes)), 0x08 => PacketContent::Path(Path::from(bytes)), 0x09 => PacketContent::Trace(Trace::from(bytes)), 0x0A => PacketContent::Multipart(MultiPart::from(bytes)), 0x0F => PacketContent::Raw(Raw { bytes }), _ => PacketContent::Invalid, } } } impl core::fmt::Display for PacketContent { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.write_str(self.justified_name())?; match self { PacketContent::Request(c) => core::fmt::Display::fmt(&c, f), PacketContent::Response(c) => core::fmt::Display::fmt(&c, f), PacketContent::Text(c) => core::fmt::Display::fmt(&c, f), PacketContent::Ack(c) => core::fmt::Display::fmt(&c, f), PacketContent::Advert(c) => core::fmt::Display::fmt(&c, f), PacketContent::GroupText(c) => core::fmt::Display::fmt(&c, f), PacketContent::GroupData(c) => core::fmt::Display::fmt(&c, f), PacketContent::AnonReq(c) => core::fmt::Display::fmt(&c, f), PacketContent::Path(c) => core::fmt::Display::fmt(&c, f), PacketContent::Trace(c) => core::fmt::Display::fmt(&c, f), PacketContent::Multipart(c) => core::fmt::Display::fmt(&c, f), PacketContent::Raw(c) => core::fmt::Display::fmt(&c, f), PacketContent::Invalid => f.write_str("INVALID"), } } } #[derive(PartialEq, Debug, Clone)] pub enum NodeType { Chat, Room, Repeater, Sensor, Invalid, } impl From for NodeType { fn from(value: u8) -> NodeType { match value & 0x07 { 0x00 => NodeType::Invalid, 0x01 => NodeType::Chat, 0x02 => NodeType::Repeater, 0x03 => NodeType::Room, 0x04 => NodeType::Sensor, _ => NodeType::Invalid, } } } #[derive(PartialEq, Debug, Clone)] pub struct PeerToPeerCipher { pub destination: u8, pub source: u8, pub mac: u16, pub ciphertext: Bytes, pub cleartext: Option, } impl From for PeerToPeerCipher { fn from(value: Bytes) -> Self { let mut bytes = value; let mut response = PeerToPeerCipher { destination: 0x00, source: 0x00, mac: 0x0000, ciphertext: Bytes::new(), cleartext: None, }; // Just check for the whole fixed-size part at once if bytes.len() < 4 { return response; } response.destination = bytes.get_u8(); response.source = bytes.get_u8(); response.mac = bytes.get_u16(); response.ciphertext = bytes; response } } impl PeerToPeerCipher { #[cfg(feature = "std")] pub fn try_decrypt(&mut self, keystore: &Keystore) -> bool { let decrypt = keystore.decrypt_and_id_p2p(self.source, self.destination, self.mac, &self.ciphertext); if let Some((cleartext, _, _)) = decrypt { self.cleartext = Some(cleartext); true } else { false } } } #[derive(PartialEq, Debug, Clone)] pub struct Raw { pub(crate) bytes: Bytes, } impl core::fmt::Display for Raw { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { core::fmt::Debug::fmt(&self, f) } } // Tests for std operations #[cfg(test)] mod tests { use super::*; #[test] fn node_type() { assert_eq!(NodeType::Invalid, NodeType::from(0x00)); assert_eq!(NodeType::Invalid, NodeType::from(0xF8)); assert_eq!(NodeType::Chat, NodeType::from(0x01)); assert_eq!(NodeType::Chat, NodeType::from(0xF9)); assert_eq!(NodeType::Repeater, NodeType::from(0x02)); assert_eq!(NodeType::Repeater, NodeType::from(0xFA)); assert_eq!(NodeType::Room, NodeType::from(0x03)); assert_eq!(NodeType::Room, NodeType::from(0xFB)); assert_eq!(NodeType::Sensor, NodeType::from(0x04)); assert_eq!(NodeType::Sensor, NodeType::from(0xFC)); assert_eq!(NodeType::Invalid, NodeType::from(0x05)); } }