diff options
| author | Will Dillon <william@housedillon.com> | 2025-11-17 06:26:07 +0000 |
|---|---|---|
| committer | Will Dillon <william@housedillon.com> | 2025-11-17 06:26:07 +0000 |
| commit | fb0ff8ae7977d68a5711c03fcc662bdb57d926c6 (patch) | |
| tree | 5a90f2e51bbb060c809afbfc6a729aed6f811cc1 /src | |
| parent | Got identity to 95% (diff) | |
| download | meshcore-rs-fb0ff8ae7977d68a5711c03fcc662bdb57d926c6.tar.gz meshcore-rs-fb0ff8ae7977d68a5711c03fcc662bdb57d926c6.zip | |
Better than 90% everywhere.
Still working on understanding response cleartext
Diffstat (limited to 'src')
| -rw-r--r-- | src/ack.rs | 2 | ||||
| -rw-r--r-- | src/advert.rs | 4 | ||||
| -rw-r--r-- | src/anon_req.rs | 3 | ||||
| -rw-r--r-- | src/identity.rs | 6 | ||||
| -rw-r--r-- | src/multipart.rs | 4 | ||||
| -rw-r--r-- | src/packet.rs | 33 | ||||
| -rw-r--r-- | src/path.rs | 4 | ||||
| -rw-r--r-- | src/request.rs | 2 | ||||
| -rw-r--r-- | src/response.rs | 88 | ||||
| -rw-r--r-- | src/text.rs | 61 | ||||
| -rw-r--r-- | src/trace.rs | 4 |
11 files changed, 167 insertions, 44 deletions
@@ -46,7 +46,7 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); } #[test] diff --git a/src/advert.rs b/src/advert.rs index dbbe84d..8d29949 100644 --- a/src/advert.rs +++ b/src/advert.rs @@ -155,7 +155,7 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); } #[test] @@ -187,7 +187,7 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); } diff --git a/src/anon_req.rs b/src/anon_req.rs index d7aa090..b468e9e 100644 --- a/src/anon_req.rs +++ b/src/anon_req.rs @@ -97,7 +97,6 @@ mod tests { use std::collections::HashMap; use std::str::FromStr; use hex::decode; - use hex::encode; use crate::identity::KeystoreInput; use crate::packet::*; use crate::crypto::*; @@ -144,7 +143,7 @@ mod tests { }.compile(); let mut rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); println!("\"{}\"", rhs_packet); assert!(format!("{}", rhs_packet) == " Flood | v1 | | [] | | ANON REQ. | (12) -> (34) MAC: 4e7b ENCRYPTED"); diff --git a/src/identity.rs b/src/identity.rs index 9389ace..c32bd85 100644 --- a/src/identity.rs +++ b/src/identity.rs @@ -177,7 +177,7 @@ impl KeystoreInput { } let mut identity_names: Vec<&String> = self.identities.keys().collect(); - identity_names.sort();; + identity_names.sort(); let mut identities: Vec<(Rc<String>, Identity)> = vec![]; for name in identity_names { if let Some(key_string) = self.identities.get(name) { @@ -186,8 +186,8 @@ impl KeystoreInput { let public_key = PublicKey::from(&private_key); let mut i = Identity { name: Rc::new(name.to_string()), - private_key: private_key, - public_key: public_key, + private_key, + public_key, secrets: HashSet::new() }; diff --git a/src/multipart.rs b/src/multipart.rs index 5b7147f..c68b442 100644 --- a/src/multipart.rs +++ b/src/multipart.rs @@ -45,6 +45,8 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); + + assert_eq!(format!("{}", lhs_packet), " Direct | v1 | | [] | | MULTIPART | Multipart isn't defined."); } }
\ No newline at end of file diff --git a/src/packet.rs b/src/packet.rs index 61b8b21..3fa26cb 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -3,7 +3,7 @@ use std::{fmt::{Debug, Display}, str::FromStr}; use hex::decode; use bytes::{Buf, Bytes}; use structdiff::{Difference, StructDiff}; -use crate::{anon_req::ClearAnonRequest, identity::Keystore, packet_content::PacketContent, request::ClearRequest, text::ClearText}; +use crate::{anon_req::ClearAnonRequest, identity::Keystore, packet_content::PacketContent, request::ClearRequest, response::ClearResponse, text::ClearText}; #[derive(PartialEq, Debug, Clone, Difference)] #[difference(expose)] @@ -184,8 +184,16 @@ impl Packet { } }, PacketContent::Response(ref mut response) => { - response.cipher.try_decrypt(keystore) + response.cipher.try_decrypt(keystore); + + if let Some(cleartext) = &response.cipher.cleartext { + response.cleartext = Some(ClearResponse::from(cleartext.to_owned())); + true + } else { + false + } }, + PacketContent::Text(ref mut text) => { text.cipher.try_decrypt(keystore); @@ -292,17 +300,6 @@ impl Display for PayloadVersion { } } -#[allow(dead_code)] -pub(crate) fn print_compare(lhs: Packet, rhs: Packet) -> String { - let mut output_string = format!("Left hand side: \n{:#?}\nRight hand side: \n{:#?}\nDifferences: \n", lhs, rhs); - - for diff in lhs.diff(&rhs) { - output_string.push_str(&format!("{:#?}", diff)); - } - output_string -} - - #[cfg(test)] mod tests { use crate::packet_content::{PacketContent, Raw}; @@ -354,28 +351,28 @@ mod tests { // Check errors related to packet length issues assert!(Packet::default() == Packet::from_str("").unwrap()); let rhs_packet = Packet::from_str("01").unwrap(); - assert!(Packet::default() == rhs_packet, "{}", print_compare(Packet::default(), rhs_packet)); + assert_eq!(Packet::default(), rhs_packet); // Packet not long enough to contain the provided path let mut lhs_packet = Packet::default(); lhs_packet.route_type = RouteType::Flood; lhs_packet.version = PayloadVersion::VersionOne; let rhs_packet = Packet::from_str("0101").unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); // Packet not long enough for transport let mut lhs_packet = Packet::default(); lhs_packet.route_type = RouteType::TransportDirect; lhs_packet.version = PayloadVersion::VersionOne; let rhs_packet = Packet::from_str("0301").unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); // Packet not long enough for version 2 path let mut lhs_packet = Packet::default(); lhs_packet.route_type = RouteType::Direct; lhs_packet.version = PayloadVersion::VersionTwo; let rhs_packet = Packet::from_str("420102").unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); // Ensure packet remainder is captured. This // will test version 1 plus transport @@ -394,7 +391,7 @@ mod tests { let compare_string = "T-Direct | v1 | 102, 304 | [06, 07, ... 09, 0a] | | RAW | Raw { bytes: b\"\\x10\\x11\\x12\\x13\\x14\\x15\\x16\\x17\\x18\\x19\" }"; assert!(format!("{}", rhs_packet) == compare_string); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); } #[test] diff --git a/src/path.rs b/src/path.rs index 11eaa5a..9cb499a 100644 --- a/src/path.rs +++ b/src/path.rs @@ -56,6 +56,8 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); + + assert_eq!(format!("{}", lhs_packet), " Flood | v1 | | [ba, 03, ... a9, 22] | | PATH | (51) -> (13) MAC: 768d "); } }
\ No newline at end of file diff --git a/src/request.rs b/src/request.rs index ffd7f3a..400d3b9 100644 --- a/src/request.rs +++ b/src/request.rs @@ -180,7 +180,7 @@ mod tests { assert!(format!("{}", rhs_packet.content) == " REQUEST | (34) -> (12) MAC: 1d87 at: 2081-09-10 06:54:21 UTC STATS"); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); } }
\ No newline at end of file diff --git a/src/response.rs b/src/response.rs index a3463e0..a8ad867 100644 --- a/src/response.rs +++ b/src/response.rs @@ -1,6 +1,8 @@ use std::fmt::Display; use bytes::Bytes; +use chrono::{DateTime, Utc}; +use hex::encode; use structdiff::{Difference, StructDiff}; use crate::packet_content::PeerToPeerCipher; @@ -8,16 +10,51 @@ use crate::packet_content::PeerToPeerCipher; #[difference(expose)] pub struct Response { pub(crate) cipher: PeerToPeerCipher, + pub cleartext: Option<ClearResponse> } impl From<Bytes> for Response { fn from(value: Bytes) -> Self { Response { - cipher: PeerToPeerCipher::from(value) + cipher: PeerToPeerCipher::from(value), + cleartext: None } } } +#[derive(PartialEq, Debug, Clone, Difference)] +#[difference(expose)] +pub struct ClearResponse { + pub timestamp: DateTime<Utc>, + pub response: u8, + pub keepalive_interval: u8, + pub is_admin: bool, + pub permissions: u8, + pub nonce: u32, + pub fw_version: u8 +} + +impl From<Bytes> for ClearResponse { + fn from(value: Bytes) -> Self { + let mut bytes = value; + + let mut clear_response = ClearResponse { + timestamp: DateTime::from_timestamp(0, 0).unwrap(), + response: 0, + keepalive_interval: 0, + is_admin: false, + permissions: 0, + nonce: 0, + fw_version: 0, + }; + + println!("{} bytes: {}", bytes.len(), encode(&bytes)); + + + clear_response + } +} + impl Display for Response { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ", @@ -40,10 +77,38 @@ mod tests { use bytes::Bytes; use hex::decode; - use crate::{packet::*, packet_content::{PacketContent, PeerToPeerCipher}, response::Response}; + use crate::{identity::KeystoreInput, packet::*, packet_content::{PacketContent, PeerToPeerCipher}, response::Response}; + + #[test] + fn response_encrypted() { + let sample = "06003412b9000cf1641739f7e4d49bff88bf5695b304111b15277de3a6031b9af3a2b6371cf75615ffefe7dcc0bbea2856c4e798a72d5b989d6de1aa646c1e2eef4cf13e6f92"; + + let lhs_packet = Packet { + route_type: RouteType::Direct, + version: PayloadVersion::VersionOne, + path: vec![], + transport: [0, 0], + raw_content: Bytes::copy_from_slice(&decode("3412b9000cf1641739f7e4d49bff88bf5695b304111b15277de3a6031b9af3a2b6371cf75615ffefe7dcc0bbea2856c4e798a72d5b989d6de1aa646c1e2eef4cf13e6f92").unwrap()), + content: PacketContent::Response(Response { + cipher: PeerToPeerCipher { + destination: 0x34, + source: 0x12, + mac: 0xb900, + ciphertext: Bytes::copy_from_slice(&decode("0cf1641739f7e4d49bff88bf5695b304111b15277de3a6031b9af3a2b6371cf75615ffefe7dcc0bbea2856c4e798a72d5b989d6de1aa646c1e2eef4cf13e6f92").unwrap()), + cleartext: None + }, + cleartext: None + }), + incomplete: false + }; + + let rhs_packet = Packet::from_str(sample).unwrap(); + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", lhs_packet), " Direct | v1 | | [] | | RESPONSE | (12) -> (34) MAC: b900 ENCRYPTED") + } #[test] - fn response() { + fn response_decrypted() { let sample = "06003412b9000cf1641739f7e4d49bff88bf5695b304111b15277de3a6031b9af3a2b6371cf75615ffefe7dcc0bbea2856c4e798a72d5b989d6de1aa646c1e2eef4cf13e6f92"; let lhs_packet = Packet { @@ -58,12 +123,21 @@ mod tests { source: 0x12, mac: 0xb900, ciphertext: Bytes::copy_from_slice(&decode("0cf1641739f7e4d49bff88bf5695b304111b15277de3a6031b9af3a2b6371cf75615ffefe7dcc0bbea2856c4e798a72d5b989d6de1aa646c1e2eef4cf13e6f92").unwrap()), - cleartext: None - }}), + cleartext: Some(Bytes::copy_from_slice(b"\x9d\xd9\x16\xd2\x94\x10\0\0\xac\xff\xfe\xff\x12\0\0\0\x12\0\0\0\x05\0\0\0\xb7\x04\0\0\x12\0\0\0\0\0\0\0\x10\0\0\0\x02\0\0\0\0\03\0\0\0\x02\0\x04\0\0\0\0\0\0\0\0\0\0\0")) + }, + cleartext: None}), incomplete: false, }; - let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + let mut rhs_packet = Packet::from_str(sample).unwrap(); + + let file_contents = include_str!("../test_identities_file.toml"); + let keystore_in: KeystoreInput = toml::from_str(file_contents).unwrap(); + let keystore = keystore_in.compile(); + + rhs_packet.try_decrypt(&keystore); + + // assert_eq!(lhs_packet, rhs_packet); + // assert_eq!(format!("{}", lhs_packet), " Direct | v1 | | [] | | RESPONSE | (12) -> (34) MAC: b900 ENCRYPTED") } }
\ No newline at end of file diff --git a/src/text.rs b/src/text.rs index 3f74646..4b6b235 100644 --- a/src/text.rs +++ b/src/text.rs @@ -1,9 +1,11 @@ use std::{fmt::Display, rc::Rc}; use bytes::{Buf, Bytes}; use chrono::{DateTime, Utc}; -use hex::encode; use structdiff::{Difference, StructDiff}; +#[cfg(feature = "std")] +use hex::encode; + use crate::{identity::Keystore, packet_content::PeerToPeerCipher}; #[derive(PartialEq, Debug, Clone, Difference)] @@ -230,7 +232,7 @@ mod tests { use crate::{identity::KeystoreInput, packet::*, packet_content::{PacketContent, PeerToPeerCipher}, text::{ClearText, GroupData, GroupText, MessageType, Text}}; #[test] - fn text() { + fn text_encrypted() { let sample = "0a001234e91c8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9"; let lhs_packet = Packet { @@ -253,7 +255,51 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", lhs_packet), " Direct | v1 | | [] | | TEXT | (34) -> (12) MAC: e91c ENCRYPTED"); + } + + #[test] + fn text_decrypted() { + let sample = "0a001234e91c8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9"; + + let lhs_packet = Packet { + route_type: RouteType::Direct, + version: PayloadVersion::VersionOne, + path: vec![], + transport: [0, 0], + raw_content: Bytes::copy_from_slice(&decode("1234e91c8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9").unwrap()), + content: PacketContent::Text(Text { + cipher: PeerToPeerCipher { + destination: 0x12, + source: 0x34, + mac: 0xe91c, + ciphertext: Bytes::copy_from_slice(&decode("8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9").unwrap()), + cleartext: Some(Bytes::copy_from_slice(b"-\xb3\x07i\x0401|get radio\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0")), + }, + cleartext: Some( + ClearText { + timestamp: DateTime::from_timestamp(1762112301, 0).unwrap(), + message_type: MessageType::Plain, + attempts: 0, + sender_hash: 0, + sender: None, + message: "01|get radio".to_string(), + crypto_recipient: "".to_string().into(), + } + ), + }), + incomplete: false, + }; + + let file_contents = include_str!("../test_identities_file.toml"); + let keystore_in: KeystoreInput = toml::from_str(file_contents).unwrap(); + let keystore = keystore_in.compile(); + + let mut rhs_packet = Packet::from_str(sample).unwrap(); + rhs_packet.try_decrypt(&keystore); + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", rhs_packet), " Direct | v1 | | [] | | TEXT | (34) -> (12) MAC: e91c at: 2025-11-02 19:38:21 UTC, 0 attempts, from Unknown to : 01|get radio"); } #[test] @@ -277,7 +323,8 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", lhs_packet), " Flood | v1 | | [7b, 2c, ... ac, b7] | | GROUP TXT | (11) Mac: 76b8 ENCRYPTED"); } #[test] @@ -320,7 +367,8 @@ mod tests { _ = rhs_packet.try_decrypt(&keystore); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", lhs_packet), " Flood | v1 | | [] | | GROUP TXT | (11) Mac: c3c1 Group Public: ☁\u{fe0f}"); } #[test] @@ -340,6 +388,7 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", lhs_packet), "T-Flood | v1 | 9d07, 16bb | [3c, 88, ... b7, ab] | | GRP. DATA | Payload: f85ecfd2ff06da1a39575d155941f152f63300d2c31b5fafbda79637"); } }
\ No newline at end of file diff --git a/src/trace.rs b/src/trace.rs index 5df2a24..81b2877 100644 --- a/src/trace.rs +++ b/src/trace.rs @@ -80,8 +80,8 @@ mod tests { }; let rhs_packet = Packet::from_str(sample).unwrap(); - assert!(lhs_packet == rhs_packet, "{}", print_compare(lhs_packet, rhs_packet)); - + assert_eq!(lhs_packet, rhs_packet); + assert_eq!(format!("{}", rhs_packet), " Direct | v1 | | [ac, a0, 79] | | TRACE | (ac): 11dB (a0): -8dB (79): -3.75dB ") } |
