aboutsummaryrefslogtreecommitdiffstats
path: root/src/text.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/text.rs')
-rw-r--r--src/text.rs208
1 files changed, 127 insertions, 81 deletions
diff --git a/src/text.rs b/src/text.rs
index df02822..5d89870 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -1,9 +1,11 @@
use bytes::{Buf, Bytes};
use chrono::{DateTime, Utc};
-use crate::string_helper::{MessageString, NameString, message_string_from_slice, name_string_from_slice};
#[cfg(feature = "std")]
-use crate::{packet_content::PeerToPeerCipher};
+use crate::packet_content::PeerToPeerCipher;
+use crate::string_helper::{
+ MessageString, NameString, message_string_from_slice, name_string_from_slice,
+};
#[cfg(not(feature = "std"))]
use crate::no_std_identity::Keystore;
@@ -21,32 +23,32 @@ impl From<Bytes> for Text {
fn from(value: Bytes) -> Self {
Text {
cipher: PeerToPeerCipher::from(value),
- cleartext: None
+ cleartext: None,
}
}
}
impl core::fmt::Display for Text {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ",
- self.cipher.source,
- self.cipher.destination,
- self.cipher.mac
+ f.write_fmt(format_args!(
+ "({:2x?}) -> ({:2x?}) MAC: {:4x?} ",
+ self.cipher.source, self.cipher.destination, self.cipher.mac
))?;
if let Some(cleartext) = &self.cleartext {
- f.write_fmt(format_args!("at: {}, {} attempts, from {}: {}",
+ f.write_fmt(format_args!(
+ "at: {}, {} attempts, from {}: {}",
cleartext.timestamp,
cleartext.attempts,
cleartext.sender,
- cleartext.message.replace("\n", "\\n")))
+ cleartext.message.replace("\n", "\\n")
+ ))
} else {
f.write_str("ENCRYPTED")
}
}
}
-
#[derive(PartialEq, Debug, Clone)]
pub struct ClearText {
pub timestamp: DateTime<Utc>,
@@ -74,7 +76,9 @@ impl From<Bytes> for ClearText {
};
// Just check for the whole fixed-size part at once
- if bytes.len() < 5 { return clear_text }
+ if bytes.len() < 5 {
+ return clear_text;
+ }
if let Some(timestamp) = DateTime::from_timestamp(bytes.get_u32_le() as i64, 0) {
clear_text.timestamp = timestamp;
}
@@ -83,8 +87,7 @@ impl From<Bytes> for ClearText {
clear_text.message_type = MessageType::from(flags);
clear_text.attempts = flags & 0x03;
- if clear_text.message_type == MessageType::SignedPlain &&
- bytes.len() > 4 {
+ if clear_text.message_type == MessageType::SignedPlain && bytes.len() > 4 {
clear_text.sender_hash = bytes.get_u32();
}
@@ -97,7 +100,7 @@ impl From<Bytes> for ClearText {
let splits_iter = bytes.splitn(2, |c| *c == b':');
let mut splits: [Option<&[u8]>; 2] = [None; 2];
-
+
for (index, split) in splits_iter.enumerate() {
splits[index] = Some(split);
}
@@ -106,13 +109,13 @@ impl From<Bytes> for ClearText {
(Some(message), None) => {
clear_text.sender = name_string_from_slice(b"Unknown");
clear_text.message = message_string_from_slice(message);
- },
+ }
(Some(sender), Some(message)) => {
clear_text.sender = name_string_from_slice(sender);
clear_text.message = message_string_from_slice(message);
- },
-
+ }
+
_ => {}
}
@@ -122,7 +125,7 @@ impl From<Bytes> for ClearText {
#[derive(PartialEq, Debug, Clone)]
pub struct GroupData {
- pub(crate) payload: Bytes
+ pub(crate) payload: Bytes,
}
impl From<Bytes> for GroupData {
@@ -145,7 +148,7 @@ pub struct GroupText {
cleartext: Option<ClearText>,
- incomplete: bool
+ incomplete: bool,
}
impl From<Bytes> for GroupText {
@@ -161,7 +164,9 @@ impl From<Bytes> for GroupText {
};
// Just check for the whole fixed-size part at once
- if bytes.len() < 3 { return group_text }
+ if bytes.len() < 3 {
+ return group_text;
+ }
group_text.hash = bytes.get_u8();
group_text.mac = bytes.get_u16();
@@ -174,11 +179,7 @@ impl From<Bytes> for GroupText {
impl GroupText {
#[cfg(feature = "std")]
pub fn try_decrypt(&mut self, keysore: &Keystore) -> bool {
- let decrypt_result = keysore.decrypt_and_id_group(
- self.hash,
- self.mac,
- &self.ciphertext
- );
+ let decrypt_result = keysore.decrypt_and_id_group(self.hash, self.mac, &self.ciphertext);
if let Some((cleartext, group)) = decrypt_result {
let mut cleartext = ClearText::from(cleartext);
@@ -194,17 +195,17 @@ impl GroupText {
impl core::fmt::Display for GroupText {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
if let Some(cleartext) = &self.cleartext {
-
let message = cleartext.message.replace("\n", "\\n");
- f.write_fmt(format_args!("({:2x?}) Mac: {:4x?} Group {}: {}",
- self.hash,
- self.mac,
- cleartext.crypto_recipient,
- message)
- )
+ f.write_fmt(format_args!(
+ "({:2x?}) Mac: {:4x?} Group {}: {}",
+ self.hash, self.mac, cleartext.crypto_recipient, message
+ ))
} else {
- f.write_fmt(format_args!("({:2x?}) Mac: {:4x?} ENCRYPTED", self.hash, self.mac))
+ f.write_fmt(format_args!(
+ "({:2x?}) Mac: {:4x?} ENCRYPTED",
+ self.hash, self.mac
+ ))
}
}
}
@@ -224,7 +225,7 @@ impl From<u8> for MessageType {
0x00 => MessageType::Plain,
0x01 => MessageType::CLI,
0x02 => MessageType::SignedPlain,
- _ => MessageType::Invalid
+ _ => MessageType::Invalid,
}
}
}
@@ -235,11 +236,17 @@ impl From<u8> for MessageType {
mod tests {
use std::{collections::HashMap, str::FromStr};
+ use crate::{
+ packet::*,
+ packet_content::{PacketContent, PeerToPeerCipher},
+ std_identity::KeystoreInput,
+ string_helper::{NameString, message_string_from_slice, name_string_from_slice},
+ text::{ClearText, GroupData, GroupText, MessageType, Text},
+ };
+ use bytes::Bytes;
use chrono::DateTime;
use hex::decode;
- use bytes::Bytes;
use tinyvec::{ArrayVec, array_vec};
- use crate::{packet::*, packet_content::{PacketContent, PeerToPeerCipher}, std_identity::KeystoreInput, string_helper::{NameString, message_string_from_slice, name_string_from_slice}, text::{ClearText, GroupData, GroupText, MessageType, Text}};
#[test]
fn text_encrypted() {
@@ -250,15 +257,21 @@ mod tests {
version: PayloadVersion::VersionOne,
path: ArrayVec::new(),
transport: [0, 0],
- raw_content: Bytes::copy_from_slice(&decode("1234e91c8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9").unwrap()),
+ 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: None
- },
+ destination: 0x12,
+ source: 0x34,
+ mac: 0xe91c,
+ ciphertext: Bytes::copy_from_slice(
+ &decode("8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9")
+ .unwrap(),
+ ),
+ cleartext: None,
+ },
cleartext: None,
}),
incomplete: false,
@@ -266,10 +279,13 @@ mod tests {
let rhs_packet = Packet::from_str(sample).unwrap();
assert_eq!(lhs_packet, rhs_packet);
- assert_eq!(format!("{}", lhs_packet), " Direct | v1 | | [] | | TEXT | (34) -> (12) MAC: e91c ENCRYPTED");
+ assert_eq!(
+ format!("{}", lhs_packet),
+ " Direct | v1 | | [] | | TEXT | (34) -> (12) MAC: e91c ENCRYPTED"
+ );
}
- #[test]
+ #[test]
fn text_decrypted() {
let sample = "0a001234e91c8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9";
@@ -278,26 +294,32 @@ mod tests {
version: PayloadVersion::VersionOne,
path: ArrayVec::new(),
transport: [0, 0],
- raw_content: Bytes::copy_from_slice(&decode("1234e91c8eb2b815e0eccf6781a3ff1820d0fb130fcfc87b914244fae227d4ad4c752fb9").unwrap()),
+ 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: name_string_from_slice(b"Unknown"),
- message: message_string_from_slice(b"01|get radio"),
- crypto_recipient: 0,
- }
- ),
+ 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: name_string_from_slice(b"Unknown"),
+ message: message_string_from_slice(b"01|get radio"),
+ crypto_recipient: 0,
+ }),
}),
incomplete: false,
};
@@ -309,7 +331,10 @@ mod tests {
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: 01|get radio");
+ assert_eq!(
+ format!("{}", rhs_packet),
+ " Direct | v1 | | [] | | TEXT | (34) -> (12) MAC: e91c at: 2025-11-02 19:38:21 UTC, 0 attempts, from Unknown: 01|get radio"
+ );
}
#[test]
@@ -334,7 +359,10 @@ mod tests {
let rhs_packet = Packet::from_str(sample).unwrap();
assert_eq!(lhs_packet, rhs_packet);
- assert_eq!(format!("{}", lhs_packet), " Flood | v1 | | [7b, 2c, ... ac, b7] | | GROUP TXT | (11) Mac: 76b8 ENCRYPTED");
+ assert_eq!(
+ format!("{}", lhs_packet),
+ " Flood | v1 | | [7b, 2c, ... ac, b7] | | GROUP TXT | (11) Mac: 76b8 ENCRYPTED"
+ );
}
#[test]
@@ -346,11 +374,17 @@ mod tests {
version: PayloadVersion::VersionOne,
path: ArrayVec::new(),
transport: [0, 0],
- raw_content: Bytes::copy_from_slice(&decode("11C3C1354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap()),
+ raw_content: Bytes::copy_from_slice(
+ &decode("11C3C1354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D")
+ .unwrap(),
+ ),
content: PacketContent::GroupText(GroupText {
hash: 0x11,
mac: 0xC3C1,
- ciphertext: Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap()),
+ ciphertext: Bytes::copy_from_slice(
+ &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D")
+ .unwrap(),
+ ),
cleartext: Some(ClearText {
sender: name_string_from_slice(b"\xF0\x9F\x8C\xB2 Tree"),
message: message_string_from_slice(b"\xE2\x98\x81\xEF\xB8\x8F"),
@@ -360,9 +394,9 @@ mod tests {
sender_hash: 0,
crypto_recipient: 0,
}),
- incomplete: false
+ incomplete: false,
}),
- incomplete: false
+ incomplete: false,
};
let mut rhs_packet = Packet::from_str(sample).unwrap();
@@ -370,17 +404,22 @@ mod tests {
let keystore = KeystoreInput {
identities: HashMap::new(),
contacts: HashMap::new(),
- groups: HashMap::from([
- ("Public".to_owned(), "8b3387e9c5cdea6ac9e5edbaa115cd72".to_owned())
- ])
- }.compile();
-
+ groups: HashMap::from([(
+ "Public".to_owned(),
+ "8b3387e9c5cdea6ac9e5edbaa115cd72".to_owned(),
+ )]),
+ }
+ .compile();
+
_ = rhs_packet.try_decrypt(&keystore);
assert_eq!(lhs_packet, rhs_packet);
- assert_eq!(format!("{}", lhs_packet), " Flood | v1 | | [] | | GROUP TXT | (11) Mac: c3c1 Group 0: ☁\u{fe0f}");
+ assert_eq!(
+ format!("{}", lhs_packet),
+ " Flood | v1 | | [] | | GROUP TXT | (11) Mac: c3c1 Group 0: ☁\u{fe0f}"
+ );
}
-
+
#[test]
fn group_data() {
let sample = "18079DBB163F3C88707DF4C430C8A06A587CF7E827641C6521A5DE85581C8800793AF4A5497196CB5F24B92A33A9C8AA3BAE4F8C94E8E464849BCBF6333509C3941C47B7ABF85ECFD2FF06DA1A39575D155941F152F63300D2C31B5FAFBDA79637";
@@ -390,15 +429,22 @@ mod tests {
version: PayloadVersion::VersionOne,
path: array_vec!([u16; 64] => 0x3C, 0x88, 0x70, 0x7D, 0xF4, 0xC4, 0x30, 0xC8, 0xA0, 0x6A, 0x58, 0x7C, 0xF7, 0xE8, 0x27, 0x64, 0x1C, 0x65, 0x21, 0xA5, 0xDE, 0x85, 0x58, 0x1C, 0x88, 0x00, 0x79, 0x3A, 0xF4, 0xA5, 0x49, 0x71, 0x96, 0xCB, 0x5F, 0x24, 0xB9, 0x2A, 0x33, 0xA9, 0xC8, 0xAA, 0x3B, 0xAE, 0x4F, 0x8C, 0x94, 0xE8, 0xE4, 0x64, 0x84, 0x9B, 0xCB, 0xF6, 0x33, 0x35, 0x09, 0xC3, 0x94, 0x1C, 0x47, 0xB7, 0xAB),
transport: [0x9d07, 0x16bb],
- raw_content: Bytes::copy_from_slice(&decode("F85ECFD2FF06DA1A39575D155941F152F63300D2C31B5FAFBDA79637").unwrap()),
+ raw_content: Bytes::copy_from_slice(
+ &decode("F85ECFD2FF06DA1A39575D155941F152F63300D2C31B5FAFBDA79637").unwrap(),
+ ),
content: PacketContent::GroupData(GroupData {
- payload: Bytes::copy_from_slice(&decode("F85ECFD2FF06DA1A39575D155941F152F63300D2C31B5FAFBDA79637").unwrap())
+ payload: Bytes::copy_from_slice(
+ &decode("F85ECFD2FF06DA1A39575D155941F152F63300D2C31B5FAFBDA79637").unwrap(),
+ ),
}),
- incomplete: false
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
assert_eq!(lhs_packet, rhs_packet);
- assert_eq!(format!("{}", lhs_packet), "T-Flood | v1 | 9d07, 16bb | [3c, 88, ... b7, ab] | | GRP. DATA | Payload: f85ecfd2ff06da1a39575d155941f152f63300d2c31b5fafbda79637");
+ assert_eq!(
+ format!("{}", lhs_packet),
+ "T-Flood | v1 | 9d07, 16bb | [3c, 88, ... b7, ab] | | GRP. DATA | Payload: f85ecfd2ff06da1a39575d155941f152f63300d2c31b5fafbda79637"
+ );
}
-} \ No newline at end of file
+}