aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorWill Dillon <william@housedillon.com>2025-11-17 06:26:07 +0000
committerWill Dillon <william@housedillon.com>2025-11-17 06:26:07 +0000
commitfb0ff8ae7977d68a5711c03fcc662bdb57d926c6 (patch)
tree5a90f2e51bbb060c809afbfc6a729aed6f811cc1 /src
parentGot identity to 95% (diff)
downloadmeshcore-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.rs2
-rw-r--r--src/advert.rs4
-rw-r--r--src/anon_req.rs3
-rw-r--r--src/identity.rs6
-rw-r--r--src/multipart.rs4
-rw-r--r--src/packet.rs33
-rw-r--r--src/path.rs4
-rw-r--r--src/request.rs2
-rw-r--r--src/response.rs88
-rw-r--r--src/text.rs61
-rw-r--r--src/trace.rs4
11 files changed, 167 insertions, 44 deletions
diff --git a/src/ack.rs b/src/ack.rs
index a5c4b63..7b30205 100644
--- a/src/ack.rs
+++ b/src/ack.rs
@@ -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 ")
}