aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authors-ol <s+removethis@s-ol.nu>2025-12-16 17:36:57 +0000
committers-ol <s+removethis@s-ol.nu>2025-12-16 17:36:57 +0000
commitc03281d1f8f856cfc68c2b06dede6b7306b4fea5 (patch)
treeee7d10732669bcfb71e9c4ce240c00f8407231fb
parentGetting closer to no-std being done (diff)
downloadmeshcore-rs-main.tar.gz
meshcore-rs-main.zip
run cargo fmtHEADmain
-rw-r--r--src/ack.rs24
-rw-r--r--src/advert.rs65
-rw-r--r--src/anon_req.rs64
-rw-r--r--src/bin/packet_analyzer.rs14
-rw-r--r--src/crypto.rs236
-rw-r--r--src/lib.rs10
-rw-r--r--src/multipart.rs18
-rw-r--r--src/no_std_identity.rs43
-rw-r--r--src/packet.rs197
-rw-r--r--src/packet_content.rs120
-rw-r--r--src/path.rs39
-rw-r--r--src/request.rs89
-rw-r--r--src/response.rs79
-rw-r--r--src/std_identity.rs260
-rw-r--r--src/string_helper.rs15
-rw-r--r--src/text.rs208
-rw-r--r--src/trace.rs34
17 files changed, 950 insertions, 565 deletions
diff --git a/src/ack.rs b/src/ack.rs
index 236ddc4..0cbef5b 100644
--- a/src/ack.rs
+++ b/src/ack.rs
@@ -1,15 +1,16 @@
-
use bytes::{Buf, Bytes};
#[derive(PartialEq, Debug, Clone)]
pub struct Ack {
- checksum: u32
+ checksum: u32,
}
impl From<Bytes> for Ack {
fn from(value: Bytes) -> Self {
let mut bytes = value;
- Ack { checksum: bytes.get_u32() }
+ Ack {
+ checksum: bytes.get_u32(),
+ }
}
}
@@ -21,11 +22,11 @@ impl core::fmt::Display for Ack {
#[cfg(test)]
mod tests {
+ use crate::{ack::Ack, packet::*, packet_content::PacketContent};
+ use bytes::Bytes;
use core::str::FromStr;
use hex::decode;
- use bytes::Bytes;
use tinyvec::array_vec;
- use crate::{ack::Ack, packet::*, packet_content::PacketContent};
#[test]
fn ack() {
@@ -38,9 +39,9 @@ mod tests {
transport: [0, 0],
raw_content: Bytes::copy_from_slice(&decode("24F3214D").unwrap()),
content: PacketContent::Ack(Ack {
- checksum: 0x24F3214D
- }),
- incomplete: false
+ checksum: 0x24F3214D,
+ }),
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
@@ -49,9 +50,10 @@ mod tests {
#[test]
fn display() {
- let ack = Ack { checksum: 0x24F3214D };
+ let ack = Ack {
+ checksum: 0x24F3214D,
+ };
println!("{}", ack);
assert_eq!(format!("{}", ack), "Checksum: 24f3214d");
}
-
-} \ No newline at end of file
+}
diff --git a/src/advert.rs b/src/advert.rs
index 24533cf..c37b491 100644
--- a/src/advert.rs
+++ b/src/advert.rs
@@ -23,7 +23,6 @@ impl Advert {
let mut name_split = bytes.chunk().split(|c| *c == 0);
if let Some(name) = name_split.next() {
-
if let Ok(name) = NameString::from_utf8(name.to_vec()) {
Some(name)
} else {
@@ -39,7 +38,6 @@ impl Advert {
let mut name_split = bytes.chunk().split(|c| *c == 0);
if let Some(name) = name_split.next() {
-
if let Ok(name) = NameString::from_utf8(name) {
Some(name)
} else {
@@ -78,42 +76,56 @@ impl From<Bytes> for Advert {
let mut advert = Advert::default();
- if bytes.len() < 32 { return advert }
+ if bytes.len() < 32 {
+ return advert;
+ }
if let Ok(key) = PublicKey::try_from(bytes.split_to(32)) {
advert.public_key = key;
} else {
- return advert
+ return advert;
}
- if bytes.len() < 4 { return advert }
+ if bytes.len() < 4 {
+ return advert;
+ }
if let Some(time) = DateTime::from_timestamp(bytes.get_u32_le() as i64, 0) {
advert.timestamp = time;
}
- if bytes.len() < 64 { return advert }
+ if bytes.len() < 64 {
+ return advert;
+ }
_ = bytes.try_copy_to_slice(&mut advert.signature);
- if bytes.is_empty() { return advert }
+ if bytes.is_empty() {
+ return advert;
+ }
let flags = bytes.get_u8();
advert.node_type = NodeType::from(flags);
if (flags & 0x10) != 0 {
// The location is 8 bytes (4 each for lat and lon)
- if bytes.len() < 8 { return advert }
+ if bytes.len() < 8 {
+ return advert;
+ }
- advert.latitude = Some(bytes.get_i32_le() as f32 / 1_000_000.0);
+ advert.latitude = Some(bytes.get_i32_le() as f32 / 1_000_000.0);
advert.longitude = Some(bytes.get_i32_le() as f32 / 1_000_000.0);
}
if (flags & 0x20) != 0 {
// Feature 1 is 2 bytes when it's included
- if bytes.len() < 2 { return advert }
+ if bytes.len() < 2 {
+ return advert;
+ }
advert.feature1 = Some(bytes.get_u16_le());
}
if (flags & 0x40) != 0 {
// Feature 2 is the same
- if bytes.len() < 2 { return advert }
+ if bytes.len() < 2 {
+ return advert;
+ }
advert.feature2 = Some(bytes.get_u16_le());
}
@@ -124,7 +136,7 @@ impl From<Bytes> for Advert {
// Find only the bytes (characters) before the first null.
advert.name = Self::name_from_bytes(bytes);
-
+
advert
}
}
@@ -140,14 +152,17 @@ impl core::fmt::Display for Advert {
f.write_str("<no name>")?;
}
- f.write_fmt(format_args!("\" ({:2x?}) at: ", self.public_key.hash_prefix() >> 24))?;
+ f.write_fmt(format_args!(
+ "\" ({:2x?}) at: ",
+ self.public_key.hash_prefix() >> 24
+ ))?;
core::fmt::Display::fmt(&self.timestamp, f)?;
match (self.latitude, self.longitude) {
(Some(lat), Some(lon)) => {
f.write_fmt(format_args!(" location: {}, {}", lat, lon))?;
- },
- _ => {},
+ }
+ _ => {}
}
Ok(())
@@ -163,8 +178,8 @@ mod tests {
use hex::decode;
use tinyvec::ArrayVec;
- use crate::packet::*;
use crate::crypto::*;
+ use crate::packet::*;
use crate::packet_content::PacketContent;
use crate::string_helper::name_string_from_slice;
@@ -202,7 +217,7 @@ mod tests {
feature2: None,
name: Some(name_string_from_slice(b"HOWL")),
}),
- incomplete: false,
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
@@ -234,21 +249,23 @@ mod tests {
feature2: None,
name: Some(name_string_from_slice(b"hpux735")),
}),
- incomplete: false,
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
assert_eq!(lhs_packet, rhs_packet);
}
-
#[test]
fn display() {
let mut signature_slice = [0 as u8; 64];
hex::decode_to_slice("d2d976b687a506dd5325ef526bf3eb52ae687277fcbde9969a5b0087e0eb0f7c1760a50c6a88bec13cc30a2a9b681d713166515e3bbc2bc27f20c0e4d7b67e08", &mut signature_slice).unwrap();
let advert = Advert {
- public_key: PublicKey::from_str("460728508c17ef336412a223144d3a623215162682045c44fef7241af0161923").unwrap(),
+ public_key: PublicKey::from_str(
+ "460728508c17ef336412a223144d3a623215162682045c44fef7241af0161923",
+ )
+ .unwrap(),
timestamp: DateTime::from_timestamp(1762111443, 0).unwrap(),
signature: signature_slice,
node_type: NodeType::Chat,
@@ -260,7 +277,9 @@ mod tests {
};
#[cfg(feature = "std")]
- assert_eq!(format!("{}", advert), "Chat \"HOWL\" (46) at: 2025-11-02 19:24:03 UTC location: 47.98286, -122.132286");
+ assert_eq!(
+ format!("{}", advert),
+ "Chat \"HOWL\" (46) at: 2025-11-02 19:24:03 UTC location: 47.98286, -122.132286"
+ );
}
-
-} \ No newline at end of file
+}
diff --git a/src/anon_req.rs b/src/anon_req.rs
index 60d58e4..acc27b6 100644
--- a/src/anon_req.rs
+++ b/src/anon_req.rs
@@ -1,6 +1,10 @@
-use chrono::{DateTime, Utc};
+use crate::{
+ MeshcoreStringError,
+ crypto::PublicKey,
+ string_helper::{PasswordString, password_string_from_slice},
+};
use bytes::{Buf, Bytes};
-use crate::{MeshcoreStringError, crypto::PublicKey, string_helper::{PasswordString, password_string_from_slice}};
+use chrono::{DateTime, Utc};
#[derive(PartialEq, Clone, core::fmt::Debug)]
pub struct AnonReq {
@@ -9,7 +13,7 @@ pub struct AnonReq {
pub mac: u16,
pub ciphertext: Bytes,
pub request: Option<ClearAnonRequest>,
- incomplete: bool
+ incomplete: bool,
}
impl AnonReq {
@@ -36,15 +40,21 @@ impl From<Bytes> for AnonReq {
incomplete: false,
};
- if bytes.is_empty() { return anon_req; }
+ if bytes.is_empty() {
+ return anon_req;
+ }
anon_req.dest = bytes.get_u8();
- if bytes.len() < 32 { return anon_req; }
+ if bytes.len() < 32 {
+ return anon_req;
+ }
if let Ok(pub_key) = PublicKey::try_from(bytes.split_to(32)) {
anon_req.public_key = pub_key;
}
- if bytes.len() < 2 { return anon_req; }
+ if bytes.len() < 2 {
+ return anon_req;
+ }
anon_req.mac = bytes.get_u16();
anon_req.ciphertext = bytes;
@@ -55,10 +65,18 @@ impl From<Bytes> for AnonReq {
impl core::fmt::Display for AnonReq {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.write_fmt(format_args!("({:2x?}) -> ({:2x?}) MAC: {:4x?} ", self.public_key.hash_prefix() >> 24, self.dest, self.mac))?;
+ f.write_fmt(format_args!(
+ "({:2x?}) -> ({:2x?}) MAC: {:4x?} ",
+ self.public_key.hash_prefix() >> 24,
+ self.dest,
+ self.mac
+ ))?;
if let Some(cleartext) = &self.request {
- f.write_fmt(format_args!("at: {} password: \"{}\"", cleartext.timestamp, cleartext.password))
+ f.write_fmt(format_args!(
+ "at: {} password: \"{}\"",
+ cleartext.timestamp, cleartext.password
+ ))
} else {
f.write_str("ENCRYPTED")
}
@@ -81,16 +99,18 @@ impl From<Bytes> for ClearAnonRequest {
// and never changes, and it exercised extensively in tests.
timestamp: DateTime::from_timestamp(0, 0).unwrap(),
sync_timestamp: None,
- password: PasswordString::new()
+ password: PasswordString::new(),
};
// Just check for the whole fixed-size part at once
- if bytes.len() < 4 { return anon_req }
+ if bytes.len() < 4 {
+ return anon_req;
+ }
if let Some(timestamp) = DateTime::from_timestamp(bytes.get_u32_le() as i64, 0) {
anon_req.timestamp = timestamp;
}
- // Strip-off any null characters after the password
+ // Strip-off any null characters after the password
if let Some(pass) = bytes.split(|b| *b == 0).next() {
anon_req.password = password_string_from_slice(pass);
}
@@ -102,15 +122,15 @@ impl From<Bytes> for ClearAnonRequest {
// Tests for std operations
#[cfg(test)]
mod tests {
+ use super::*;
+ use crate::crypto::*;
+ use crate::packet::*;
+ use crate::packet_content::PacketContent;
+ use crate::std_identity::KeystoreInput;
+ use hex::decode;
use std::collections::HashMap;
use std::str::FromStr;
- use hex::decode;
use tinyvec::ArrayVec;
- use crate::std_identity::KeystoreInput;
- use crate::packet::*;
- use crate::crypto::*;
- use crate::packet_content::PacketContent;
- use super::*;
#[test]
fn anon_req() {
@@ -155,13 +175,15 @@ mod tests {
assert_eq!(lhs_packet, rhs_packet);
println!("\"{}\"", rhs_packet);
- assert_eq!(format!("{}", rhs_packet), " Flood | v1 | | [] | | ANON REQ. | (12) -> (34) MAC: 4e7b ENCRYPTED");
+ assert_eq!(
+ format!("{}", rhs_packet),
+ " Flood | v1 | | [] | | ANON REQ. | (12) -> (34) MAC: 4e7b ENCRYPTED"
+ );
rhs_packet.try_decrypt(&keystore);
-
+
let lhs_string = format!("{}", rhs_packet);
let rhs_string = " Flood | v1 | | [] | | ANON REQ. | (12) -> (34) MAC: 4e7b at: 2025-11-13 17:21:13 UTC password: \"12345\"";
assert_eq!(lhs_string, rhs_string);
}
-
-} \ No newline at end of file
+}
diff --git a/src/bin/packet_analyzer.rs b/src/bin/packet_analyzer.rs
index 54d2f5b..323abbe 100644
--- a/src/bin/packet_analyzer.rs
+++ b/src/bin/packet_analyzer.rs
@@ -1,15 +1,17 @@
-use std::{borrow::Cow, path::PathBuf};
+use bytes::Bytes;
use hex::encode;
use log::{error, trace};
+use std::{borrow::Cow, path::PathBuf};
use tokio::fs::File;
-use bytes::Bytes;
use clap::Parser;
use color_eyre::eyre::Result;
-use meshcore::{std_identity::{Keystore, KeystoreInput}, packet::Packet};
-use pretty_env_logger;
+use meshcore::{
+ packet::Packet,
+ std_identity::{Keystore, KeystoreInput},
+};
use pcap_file_tokio::pcapng::PcapNgReader;
-
+use pretty_env_logger;
#[derive(Parser)]
struct AnalyzerArguments {
@@ -87,4 +89,4 @@ async fn main() -> Result<()> {
}
Ok(())
-} \ No newline at end of file
+}
diff --git a/src/crypto.rs b/src/crypto.rs
index cd184dc..acbb464 100644
--- a/src/crypto.rs
+++ b/src/crypto.rs
@@ -1,27 +1,42 @@
-
// This seems to be an absolute nightmare. GenericArray sucks
// but I can't seem to figure out how to pull it out of this
// stack of software
+use aes::Aes128;
#[allow(deprecated)]
-use aes::cipher::{BlockEncrypt, BlockDecrypt, generic_array::GenericArray};
+use aes::cipher::{BlockDecrypt, BlockEncrypt, generic_array::GenericArray};
+use bytes::{Buf, BufMut, Bytes, BytesMut};
use curve25519_dalek::MontgomeryPoint;
-use aes::Aes128;
-use sha2::{Sha256};
-use hmac::{Hmac, Mac};
use ed25519_dalek::{VerifyingKey, hazmat::ExpandedSecretKey};
-use bytes::{Buf, BufMut, Bytes, BytesMut};
+use hmac::{Hmac, Mac};
+use sha2::Sha256;
use crate::string_helper::NameString;
-
type HmacSha256 = Hmac<Sha256>;
pub trait Keystore {
- fn decrypt_and_id_p2p(&self, source: u8, _dest: u8, mac: u16, data: &Bytes) -> Option<(Bytes, u32, u32)>;
-
- fn decrypt_and_id_group(&self, group_hash_prefix: u8, mac: u16, data: &Bytes) -> Option<(Bytes, Option<NameString>)>;
-
- fn decrypt_anon(&self, dest: u8, pub_key: &PublicKey, mac: u16, data: &Bytes) -> Option<(Bytes, u32)>;
+ fn decrypt_and_id_p2p(
+ &self,
+ source: u8,
+ _dest: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, u32, u32)>;
+
+ fn decrypt_and_id_group(
+ &self,
+ group_hash_prefix: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, Option<NameString>)>;
+
+ fn decrypt_anon(
+ &self,
+ dest: u8,
+ pub_key: &PublicKey,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, u32)>;
}
#[derive(Debug, PartialEq)]
@@ -32,7 +47,6 @@ pub enum MeshcoreCryptoError {
KeyCreationError,
}
-
impl core::error::Error for MeshcoreCryptoError {}
impl core::fmt::Display for MeshcoreCryptoError {
@@ -51,7 +65,9 @@ pub struct PrivateKey(ExpandedSecretKey);
impl core::fmt::Debug for PrivateKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_tuple("PrivateKey").field(&hex::encode(self.0.scalar.as_bytes())).finish()
+ f.debug_tuple("PrivateKey")
+ .field(&hex::encode(self.0.scalar.as_bytes()))
+ .finish()
}
}
@@ -59,7 +75,7 @@ impl Clone for PrivateKey {
fn clone(&self) -> Self {
Self(ExpandedSecretKey {
scalar: self.0.scalar,
- hash_prefix: self.0.hash_prefix
+ hash_prefix: self.0.hash_prefix,
})
}
}
@@ -68,8 +84,8 @@ impl Default for PrivateKey {
fn default() -> Self {
// To make a key whole-cloth, we need to start with a SigningKey made
// using a good RNG. Then we can use that to make an ExpandedSecretKey.
- use rand::rngs::OsRng;
use ed25519_dalek::SigningKey;
+ use rand::rngs::OsRng;
// This seems like the same sequence of steps that's used with ed25519 itself.
// I have to copy-pasta it because I don't see a way to do it directly with
@@ -97,7 +113,9 @@ pub struct PublicKey(ed25519_dalek::VerifyingKey);
impl core::fmt::Debug for PublicKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_tuple("PublicKey").field(&hex::encode(self.0.as_bytes())).finish()
+ f.debug_tuple("PublicKey")
+ .field(&hex::encode(self.0.as_bytes()))
+ .finish()
}
}
@@ -116,7 +134,7 @@ impl PartialEq for SharedSecret {
fn eq(&self, other: &Self) -> bool {
self.0.as_bytes() == other.0.as_bytes()
}
-
+
fn ne(&self, other: &Self) -> bool {
!self.eq(other)
}
@@ -124,7 +142,9 @@ impl PartialEq for SharedSecret {
impl core::fmt::Debug for SharedSecret {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
- f.debug_tuple("SharedSecret").field(&hex::encode(self.0.as_bytes())).finish()
+ f.debug_tuple("SharedSecret")
+ .field(&hex::encode(self.0.as_bytes()))
+ .finish()
}
}
@@ -138,7 +158,7 @@ impl core::str::FromStr for SharedSecret {
// but they're zero-paded to be 32. So, we're
// going to get the hex from the string and copy it in.
if hex::decode_to_slice(s, &mut array[0..16]).is_err() {
- return Err(MeshcoreCryptoError::TryFromSliceError)
+ return Err(MeshcoreCryptoError::TryFromSliceError);
} else {
Ok(SharedSecret(MontgomeryPoint(array)))
}
@@ -149,8 +169,9 @@ impl TryFrom<Bytes> for SharedSecret {
type Error = MeshcoreCryptoError;
fn try_from(value: Bytes) -> Result<Self, Self::Error> {
- if value.len() != 32 { Err(MeshcoreCryptoError::KeyLengthError) }
- else {
+ if value.len() != 32 {
+ Err(MeshcoreCryptoError::KeyLengthError)
+ } else {
let mut value = value;
let mut retval = Self(MontgomeryPoint([0_u8; 32]));
value.copy_to_slice(&mut retval.0.0);
@@ -190,8 +211,8 @@ impl SharedSecret {
// At this point, we're sure that the key is an appropriate size for
// the Hmac. So, I don't think we should complicate the API with making
// this failable.
- let mut mac = HmacSha256::new_from_slice(self.0.as_bytes())
- .expect("Programming error in hmac");
+ let mut mac =
+ HmacSha256::new_from_slice(self.0.as_bytes()).expect("Programming error in hmac");
mac.update(&ciphertext);
let result = mac.finalize();
let mut bytes = Bytes::copy_from_slice(&result.into_bytes());
@@ -219,7 +240,7 @@ impl SharedSecret {
text.reserve(padding);
text.put_bytes(0, padding);
}
-
+
let chunks = text.chunks_exact_mut(chunk_size);
for chunk in chunks {
#[allow(deprecated)]
@@ -262,7 +283,7 @@ impl SharedSecret {
text.reserve(padding);
text.put_bytes(0, padding);
}
-
+
let chunks = text.chunks_exact_mut(chunk_size);
for chunk in chunks {
#[allow(deprecated)]
@@ -300,13 +321,13 @@ impl TryFrom<Bytes> for PublicKey {
fn try_from(mut value: Bytes) -> Result<Self, Self::Error> {
if value.len() < 32 {
- return Err(MeshcoreCryptoError::KeyLengthError)
+ return Err(MeshcoreCryptoError::KeyLengthError);
}
let mut slice = [0_u8; 32];
if value.try_copy_to_slice(&mut slice).is_err() {
- return Err(MeshcoreCryptoError::KeyLengthError)
+ return Err(MeshcoreCryptoError::KeyLengthError);
}
if let Ok(key) = VerifyingKey::from_bytes(&slice) {
@@ -315,7 +336,6 @@ impl TryFrom<Bytes> for PublicKey {
Err(MeshcoreCryptoError::KeyCreationError)
}
}
-
}
impl core::str::FromStr for PublicKey {
@@ -371,7 +391,9 @@ impl SharedSecret {
pub fn mac_then_decrypt(&self, mac: u16, data: &Bytes) -> Option<Bytes> {
// Get the MAC of the message and key to check vailidity
let our_mac = self.get_hmac(&data);
- if our_mac != mac { return None }
+ if our_mac != mac {
+ return None;
+ }
// Attempt to decrypt the packet itself
Some(self.decrypt(&data))
@@ -387,16 +409,24 @@ impl SharedSecret {
// Tests for std operations
#[cfg(test)]
mod tests {
- use core::str::FromStr;
- use hex::{decode_to_slice, encode, decode};
use super::*;
+ use core::str::FromStr;
+ use hex::{decode, decode_to_slice, encode};
#[test]
fn public_key() {
let mut slice = [0_u8; 32];
- decode_to_slice("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec", &mut slice).unwrap();
- let public_key = PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec");
- assert_eq!(Ok(PublicKey(VerifyingKey::from_bytes(&slice).unwrap())), public_key);
+ decode_to_slice(
+ "12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec",
+ &mut slice,
+ )
+ .unwrap();
+ let public_key =
+ PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec");
+ assert_eq!(
+ Ok(PublicKey(VerifyingKey::from_bytes(&slice).unwrap())),
+ public_key
+ );
}
#[test]
@@ -404,7 +434,11 @@ mod tests {
let private_key = PrivateKey::from_str("38DAA98490B7284697C7ADA6175FD1F8DAD12032AD7ABAE625B7EAD8FEC6444CA281C3370B97155D9C8CECD89A929FDDE0FBF3A9D5C92A1B3C24D711934CD69D").unwrap();
let public_key = PublicKey::from(&private_key);
println!("Public key: {:#?}", public_key);
- assert_eq!(PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap(), public_key);
+ assert_eq!(
+ PublicKey::from_str("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec")
+ .unwrap(),
+ public_key
+ );
}
#[test]
@@ -416,19 +450,31 @@ mod tests {
let alice_public = PublicKey::from(&alice_private);
let bob_public = PublicKey::from(&bob_private);
- assert_eq!(alice_public.0.as_bytes().to_vec(), decode("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap());
- assert_eq!( bob_public.0.as_bytes().to_vec(), decode("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap());
+ assert_eq!(
+ alice_public.0.as_bytes().to_vec(),
+ decode("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap()
+ );
+ assert_eq!(
+ bob_public.0.as_bytes().to_vec(),
+ decode("12349bdc1f76a0c12149bb15f791dbe42fde02c209b04a85c6f512990c8cedec").unwrap()
+ );
println!("Alice's public key: {}", encode(&alice_public.0.to_bytes()));
println!("Bob's public key: {}", encode(&bob_public.0.to_bytes()));
- let left_secret = alice_private.create_secret(&bob_public);
+ let left_secret = alice_private.create_secret(&bob_public);
let right_secret = bob_private.create_secret(&alice_public);
- assert_eq!(left_secret.0.as_bytes().to_vec(), decode("eb7a365363bd8548ee2b54b9234247be5e42e96be9625adcdf3a55b6c1d04850").unwrap());
+ assert_eq!(
+ left_secret.0.as_bytes().to_vec(),
+ decode("eb7a365363bd8548ee2b54b9234247be5e42e96be9625adcdf3a55b6c1d04850").unwrap()
+ );
println!("Left shared secret: {}", encode(&left_secret.0.as_bytes()));
- println!("Right shared secret: {}", encode(&right_secret.0.as_bytes()));
+ println!(
+ "Right shared secret: {}",
+ encode(&right_secret.0.as_bytes())
+ );
assert_eq!(left_secret, right_secret);
}
@@ -436,28 +482,39 @@ mod tests {
#[test]
fn hmac() {
// Test using a group secret
- let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap()));
- let test_group_secret =SharedSecret::from_str("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap();
+ let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(
+ &decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(),
+ ));
+ let test_group_secret = SharedSecret::from_str("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap();
assert_eq!(group_secret, test_group_secret);
// Test using the secret and ciphertext to make a MAC and ensure it matches an example for a group secret
- let sample_data = Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap());
+ let sample_data = Bytes::copy_from_slice(
+ &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap(),
+ );
let mac = group_secret.get_hmac(&sample_data);
assert_eq!(0xC3C1, mac);
}
#[test]
fn decrypt() {
- let ciphertext = Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap());
- let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap()));
+ let ciphertext = Bytes::copy_from_slice(
+ &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap(),
+ );
+ let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(
+ &decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(),
+ ));
let cleartext = secret.decrypt(&ciphertext);
println!("Cleartext: {}", encode(&cleartext));
}
#[test]
fn decrypt_online_example() {
- let ciphertext = Bytes::copy_from_slice(&decode("9A1FD57EDFE7E4369F9FD9420C48FFAD").unwrap());
- let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("949E911CA6A6196275FF319B28C3A143").unwrap()));
+ let ciphertext =
+ Bytes::copy_from_slice(&decode("9A1FD57EDFE7E4369F9FD9420C48FFAD").unwrap());
+ let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(
+ &decode("949E911CA6A6196275FF319B28C3A143").unwrap(),
+ ));
let cleartext = secret.decrypt(&ciphertext);
let vec = cleartext.to_vec();
let string = String::from_utf8_lossy(&vec);
@@ -467,9 +524,14 @@ mod tests {
#[test]
fn encrypt_online_example() {
let plaintext = Bytes::copy_from_slice("Meshcore!".as_bytes());
- let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("44A6F78DAD2E54D73A32CDE3ECAA9E75").unwrap()));
+ let secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(
+ &decode("44A6F78DAD2E54D73A32CDE3ECAA9E75").unwrap(),
+ ));
let ciphertext = secret.encrypt(plaintext);
- assert_eq!(ciphertext, decode("62374852B6A11405A081F87356C88861").unwrap());
+ assert_eq!(
+ ciphertext,
+ decode("62374852B6A11405A081F87356C88861").unwrap()
+ );
}
#[test]
@@ -486,11 +548,13 @@ mod tests {
let padding = chunk_size - (length % chunk_size);
text.reserve(padding);
text.put_bytes(0, padding);
-
+
let chunks = text.chunks_exact_mut(4);
{
for chunk in chunks {
- for item in chunk { *item = *item << 4; }
+ for item in chunk {
+ *item = *item << 4;
+ }
}
}
@@ -500,7 +564,6 @@ mod tests {
println!("Result: {:#?}", encode(&text));
assert_eq!(text, decode("102030405060708090A0B0C0D0E0F0").unwrap());
-
}
// Example from the crate we're using
@@ -508,13 +571,19 @@ mod tests {
fn aes_test() {
use aes::Aes128;
#[allow(deprecated)]
- use aes::cipher::{BlockEncrypt, BlockDecrypt, KeyInit};
+ use aes::cipher::{BlockDecrypt, BlockEncrypt, KeyInit};
// Initialize cipher
- let key: [u8; 16] = decode("0A1BB8C05063D9941F0F1019D001B743").unwrap().try_into().unwrap();
+ let key: [u8; 16] = decode("0A1BB8C05063D9941F0F1019D001B743")
+ .unwrap()
+ .try_into()
+ .unwrap();
let cipher = Aes128::new(&key.into());
- let message: [u8; 16] = decode("7D69AB072E09AF74EBA47EB95BF00AE3").unwrap().try_into().unwrap();
+ let message: [u8; 16] = decode("7D69AB072E09AF74EBA47EB95BF00AE3")
+ .unwrap()
+ .try_into()
+ .unwrap();
let message_copy = message.clone();
// Encrypt block in-place
@@ -533,10 +602,18 @@ mod tests {
#[test]
fn shared_secrets_example() {
- use x25519_dalek::{StaticSecret, PublicKey};
+ use x25519_dalek::{PublicKey, StaticSecret};
- let a_s: [u8; 32] = decode("58f5052c13275c8a3f4863a082555fed7ea08b9dec2eb00dd86f6b5412174458").unwrap().try_into().unwrap();
- let b_s: [u8; 32] = decode("586c4cc29635af5865abe4f231bafbd373969725493c07271e02c7fec8ff3b5f").unwrap().try_into().unwrap();
+ let a_s: [u8; 32] =
+ decode("58f5052c13275c8a3f4863a082555fed7ea08b9dec2eb00dd86f6b5412174458")
+ .unwrap()
+ .try_into()
+ .unwrap();
+ let b_s: [u8; 32] =
+ decode("586c4cc29635af5865abe4f231bafbd373969725493c07271e02c7fec8ff3b5f")
+ .unwrap()
+ .try_into()
+ .unwrap();
let alice_secret = StaticSecret::from(a_s);
let alice_public = PublicKey::from(&alice_secret);
@@ -545,26 +622,45 @@ mod tests {
let alice_shared_secret = alice_secret.diffie_hellman(&bob_public);
let bob_shared_secret = bob_secret.diffie_hellman(&alice_public);
-
+
assert_eq!(alice_shared_secret.as_bytes(), bob_shared_secret.as_bytes());
}
#[test]
fn mac_then_decrypt() {
- let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(&decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap()));
- let sample_data = Bytes::copy_from_slice(&decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap());
+ let group_secret = SharedSecret::new_from_group_secret(Bytes::copy_from_slice(
+ &decode("8b3387e9c5cdea6ac9e5edbaa115cd72").unwrap(),
+ ));
+ let sample_data = Bytes::copy_from_slice(
+ &decode("354D619BAE9590E4D177DB7EEAF982F5BDCF78005D75157D9535FA90178F785D").unwrap(),
+ );
let mac = 0xC3C1;
let cleartext = group_secret.mac_then_decrypt(mac, &sample_data).unwrap();
- assert_eq!(cleartext, decode("3757d06800f09f8cb220547265653a20e29881efb88f00000000000000000000").unwrap());
+ assert_eq!(
+ cleartext,
+ decode("3757d06800f09f8cb220547265653a20e29881efb88f00000000000000000000").unwrap()
+ );
}
#[test]
fn test_error_display() {
- assert_eq!(format!("{}", MeshcoreCryptoError::KeyLengthError), "Key Length Error");
- assert_eq!(format!("{}", MeshcoreCryptoError::TryFromSliceError), "Try From Slice Error");
- assert_eq!(format!("{}", MeshcoreCryptoError::HexDecodeError), "Hex Decode Error");
- assert_eq!(format!("{}", MeshcoreCryptoError::KeyCreationError), "Key Creation Error");
+ assert_eq!(
+ format!("{}", MeshcoreCryptoError::KeyLengthError),
+ "Key Length Error"
+ );
+ assert_eq!(
+ format!("{}", MeshcoreCryptoError::TryFromSliceError),
+ "Try From Slice Error"
+ );
+ assert_eq!(
+ format!("{}", MeshcoreCryptoError::HexDecodeError),
+ "Hex Decode Error"
+ );
+ assert_eq!(
+ format!("{}", MeshcoreCryptoError::KeyCreationError),
+ "Key Creation Error"
+ );
}
#[test]
@@ -578,7 +674,8 @@ mod tests {
let cleartext = "Hi Bob. This is alice. How are you?";
let alice_secret = alice_private.create_secret(&bob_public);
- let (mac, ciphertext) = alice_secret.encrypt_then_mac(Bytes::copy_from_slice(cleartext.as_bytes()));
+ let (mac, ciphertext) =
+ alice_secret.encrypt_then_mac(Bytes::copy_from_slice(cleartext.as_bytes()));
let bob_secret = bob_private.create_secret(&alice_public);
let decrypted_data = bob_secret.mac_then_decrypt(mac, &ciphertext);
@@ -600,6 +697,5 @@ mod tests {
} else {
assert!(false, "Unable to decrypt");
}
-
}
-} \ No newline at end of file
+}
diff --git a/src/lib.rs b/src/lib.rs
index 621dcf4..d74cfd1 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -19,14 +19,14 @@ pub mod std_identity;
#[cfg(not(feature = "std"))]
pub(crate) mod no_std_identity;
+pub mod ack;
+pub mod advert;
+pub mod anon_req;
+pub mod multipart;
pub mod packet;
pub mod packet_content;
+pub mod path;
pub mod request;
pub mod response;
pub mod text;
-pub mod ack;
-pub mod advert;
-pub mod anon_req;
-pub mod path;
pub mod trace;
-pub mod multipart; \ No newline at end of file
diff --git a/src/multipart.rs b/src/multipart.rs
index ced4aaa..d9facf1 100644
--- a/src/multipart.rs
+++ b/src/multipart.rs
@@ -1,9 +1,8 @@
-
use bytes::Bytes;
#[derive(PartialEq, Debug, Clone)]
pub struct MultiPart {
- payload: Bytes
+ payload: Bytes,
}
impl From<Bytes> for MultiPart {
@@ -21,11 +20,11 @@ impl core::fmt::Display for MultiPart {
// Tests for std operations
#[cfg(test)]
mod tests {
+ use crate::{packet::*, packet_content::PacketContent};
use core::str::FromStr;
use hex::decode;
use tinyvec::ArrayVec;
- use crate::{packet::*, packet_content::PacketContent};
-
+
use super::*;
#[test]
@@ -39,15 +38,18 @@ mod tests {
transport: [0, 0],
raw_content: Bytes::copy_from_slice(&decode("13E8C59624").unwrap()),
content: PacketContent::Multipart(MultiPart {
- payload: Bytes::copy_from_slice(&decode("13E8C59624").unwrap())
+ payload: Bytes::copy_from_slice(&decode("13E8C59624").unwrap()),
}),
- incomplete: false
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
assert_eq!(lhs_packet, rhs_packet);
#[cfg(feature = "std")]
- assert_eq!(format!("{}", lhs_packet), " Direct | v1 | | [] | | MULTIPART | Multipart isn't defined.");
+ assert_eq!(
+ format!("{}", lhs_packet),
+ " Direct | v1 | | [] | | MULTIPART | Multipart isn't defined."
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/no_std_identity.rs b/src/no_std_identity.rs
index 2a0018e..aac3253 100644
--- a/src/no_std_identity.rs
+++ b/src/no_std_identity.rs
@@ -1,5 +1,8 @@
+use crate::{
+ NameString,
+ crypto::{Keystore, PrivateKey, PublicKey, SharedSecret},
+};
use bytes::Bytes;
-use crate::{NameString, crypto::{Keystore, PrivateKey, PublicKey, SharedSecret}};
use tinyvec::ArrayVec;
#[derive(PartialEq, Clone, Debug)]
@@ -17,7 +20,7 @@ impl Default for Identity {
Self {
private_key,
hash_prefix,
- secrets: Default::default()
+ secrets: Default::default(),
}
}
}
@@ -29,7 +32,13 @@ pub struct StaticKeystore {
}
impl Keystore for StaticKeystore {
- fn decrypt_and_id_p2p(&self, _source: u8, _dest: u8, mac: u16, data: &Bytes) -> Option<(Bytes, u32, u32)> {
+ fn decrypt_and_id_p2p(
+ &self,
+ _source: u8,
+ _dest: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, u32, u32)> {
// Just brute-force all the secrets until one matches...
for identity in self.identities.iter() {
for (peer_prefix, secret) in identity.secrets.iter() {
@@ -42,7 +51,12 @@ impl Keystore for StaticKeystore {
None
}
- fn decrypt_and_id_group(&self, _group_hash_prefix: u8, mac: u16, data: &Bytes) -> Option<(Bytes, Option<NameString>)> {
+ fn decrypt_and_id_group(
+ &self,
+ _group_hash_prefix: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, Option<NameString>)> {
for group in self.groups.iter() {
let result = group.mac_then_decrypt(mac, data);
if let Some(result) = result {
@@ -53,7 +67,13 @@ impl Keystore for StaticKeystore {
None
}
- fn decrypt_anon(&self, _dest: u8, pub_key: &PublicKey, mac: u16, data: &Bytes) -> Option<(Bytes, u32)> {
+ fn decrypt_anon(
+ &self,
+ _dest: u8,
+ pub_key: &PublicKey,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, u32)> {
// For each identity, create a shared secret against the provided public key and check it.
for identity in self.identities.iter() {
let secret = identity.private_key.create_secret(pub_key);
@@ -77,7 +97,7 @@ impl StaticKeystoreInput {
pub fn compile(self) -> StaticKeystore {
let mut retval = StaticKeystore {
identities: ArrayVec::new(),
- groups: ArrayVec::new(),
+ groups: ArrayVec::new(),
};
for identity_in in self.identities {
@@ -85,7 +105,10 @@ impl StaticKeystoreInput {
identity.private_key = identity_in;
identity.hash_prefix = PublicKey::from(&identity.private_key).hash_prefix();
for contact_in in self.contacts.iter() {
- identity.secrets.push((contact_in.hash_prefix(), identity.private_key.create_secret(&contact_in)));
+ identity.secrets.push((
+ contact_in.hash_prefix(),
+ identity.private_key.create_secret(&contact_in),
+ ));
}
retval.identities.push(identity);
@@ -102,7 +125,5 @@ impl StaticKeystoreInput {
#[cfg(test)]
mod tests {
#[test]
- fn test_compile() {
-
- }
-} \ No newline at end of file
+ fn test_compile() {}
+}
diff --git a/src/packet.rs b/src/packet.rs
index 50374a7..4cd7365 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -4,9 +4,12 @@ use crate::std_identity::Keystore;
#[cfg(not(feature = "std"))]
use crate::no_std_identity::Keystore;
+use crate::{
+ anon_req::ClearAnonRequest, packet_content::PacketContent, request::ClearRequest,
+ response::ClearResponse, text::ClearText,
+};
use bytes::{Buf, Bytes};
use tinyvec::ArrayVec;
-use crate::{anon_req::ClearAnonRequest, packet_content::PacketContent, request::ClearRequest, response::ClearResponse, text::ClearText};
#[derive(PartialEq, Clone, core::fmt::Debug)]
pub struct Packet {
@@ -16,7 +19,7 @@ pub struct Packet {
pub transport: [u16; 2],
pub raw_content: Bytes,
pub content: PacketContent,
- pub incomplete: bool
+ pub incomplete: bool,
}
impl core::str::FromStr for Packet {
@@ -36,7 +39,7 @@ impl From<Bytes> for Packet {
let mut packet = Packet::default();
if bytes.len() < 2 {
- return packet
+ return packet;
}
let header = bytes.get_u8();
@@ -49,25 +52,29 @@ impl From<Bytes> for Packet {
packet.transport = match packet.route_type {
RouteType::TransportFlood | RouteType::TransportDirect => {
// The packet isn't long enough to contain the transport
- if bytes.len() < 4 { return packet; }
+ if bytes.len() < 4 {
+ return packet;
+ }
let t1 = bytes.get_u16_le();
let t2 = bytes.get_u16_le();
[t1, t2]
- },
- _ => {
- [0, 0]
}
+ _ => [0, 0],
};
// Get the route
- if bytes.is_empty() { return packet; }
+ if bytes.is_empty() {
+ return packet;
+ }
let path_length = bytes.get_u8() as usize;
packet.path = match packet.version {
PayloadVersion::VersionOne => {
// The packet isn't long enough for the indicated route
- if bytes.len() < path_length { return packet; }
+ if bytes.len() < path_length {
+ return packet;
+ }
let mut route = ArrayVec::new();
for _ in 0..path_length {
@@ -76,11 +83,13 @@ impl From<Bytes> for Packet {
}
route
- },
+ }
PayloadVersion::VersionTwo => {
// The packet isn't long enough for the indicated route
- if bytes.len() < path_length * 2 { return packet; }
+ if bytes.len() < path_length * 2 {
+ return packet;
+ }
let mut route = ArrayVec::new();
for i in 0..path_length {
@@ -89,7 +98,7 @@ impl From<Bytes> for Packet {
}
route
- },
+ }
_ => {
return packet;
}
@@ -121,7 +130,7 @@ impl From<Bytes> for Packet {
// when it prints the SNR results in its Display function.
packet.content = PacketContent::Trace(trace);
}
-
+
// Mark the packet as complete and valid
packet.incomplete = false;
@@ -138,7 +147,7 @@ impl Default for Packet {
transport: [0, 0],
raw_content: Bytes::new(),
content: PacketContent::Invalid,
- incomplete: true
+ incomplete: true,
}
}
}
@@ -149,8 +158,13 @@ impl core::fmt::Display for Packet {
f.write_str(" | ")?;
core::fmt::Display::fmt(&self.version, f)?;
- if self.route_type == RouteType::TransportDirect || self.route_type == RouteType::TransportFlood {
- f.write_fmt(format_args!(" | {:4x?}, {:4x?} | ", self.transport[0], self.transport[1]))?
+ if self.route_type == RouteType::TransportDirect
+ || self.route_type == RouteType::TransportFlood
+ {
+ f.write_fmt(format_args!(
+ " | {:4x?}, {:4x?} | ",
+ self.transport[0], self.transport[1]
+ ))?
} else {
f.write_fmt(format_args!(" | |"))?
}
@@ -159,9 +173,21 @@ impl core::fmt::Display for Packet {
match self.path.len() {
0 => f.write_fmt(format_args!(" [] | ")),
1 => f.write_fmt(format_args!(" [{:02x?}] | ", self.path[0])),
- 2 => f.write_fmt(format_args!(" [{:02x?}, {:02x?}] | ", self.path[0], self.path[1])),
- 3 => f.write_fmt(format_args!(" [{:02x?}, {:02x?}, {:02x?}] | ", self.path[0], self.path[1], self.path[2])),
- _ => f.write_fmt(format_args!(" [{:02x?}, {:02x?}, ... {:02x?}, {:02x?}] | ", self.path[0], self.path[1], self.path[len - 2], self.path[len -1])),
+ 2 => f.write_fmt(format_args!(
+ " [{:02x?}, {:02x?}] | ",
+ self.path[0], self.path[1]
+ )),
+ 3 => f.write_fmt(format_args!(
+ " [{:02x?}, {:02x?}, {:02x?}] | ",
+ self.path[0], self.path[1], self.path[2]
+ )),
+ _ => f.write_fmt(format_args!(
+ " [{:02x?}, {:02x?}, ... {:02x?}, {:02x?}] | ",
+ self.path[0],
+ self.path[1],
+ self.path[len - 2],
+ self.path[len - 1]
+ )),
}?;
if self.incomplete {
@@ -179,21 +205,19 @@ impl Packet {
pub fn try_decrypt(&mut self, keystore: &Keystore) -> bool {
match self.content {
// Encrypted packet types
- PacketContent::Path(ref mut path) => {
- path.cipher.try_decrypt(keystore)
- },
+ PacketContent::Path(ref mut path) => path.cipher.try_decrypt(keystore),
PacketContent::Request(ref mut request) => {
let result = request.cipher.try_decrypt(keystore);
if let Some(cleartext) = &request.cipher.cleartext {
let cleartext = ClearRequest::from(cleartext.clone());
request.cleartext = Some(cleartext);
-
+
result
} else {
false
}
- },
+ }
PacketContent::Response(ref mut response) => {
response.cipher.try_decrypt(keystore);
@@ -203,7 +227,7 @@ impl Packet {
} else {
false
}
- },
+ }
PacketContent::Text(ref mut text) => {
text.cipher.try_decrypt(keystore);
@@ -214,14 +238,14 @@ impl Packet {
} else {
false
}
- },
+ }
PacketContent::AnonReq(ref mut anon_req) => {
let decrypt_result = keystore.decrypt_anon(
anon_req.dest,
&anon_req.public_key,
anon_req.mac,
- &anon_req.ciphertext
+ &anon_req.ciphertext,
);
if let Some(cleartext) = decrypt_result {
@@ -232,14 +256,12 @@ impl Packet {
}
}
- PacketContent::GroupText(ref mut group_text) => {
- group_text.try_decrypt(keystore)
- }
+ PacketContent::GroupText(ref mut group_text) => group_text.try_decrypt(keystore),
// None of the other packets implement any encryption
- _ => false
+ _ => false,
}
- }
+ }
}
#[derive(PartialEq, Debug, Clone)]
@@ -254,11 +276,11 @@ pub enum RouteType {
impl core::fmt::Display for RouteType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
- RouteType::TransportFlood => f.write_str("T-Flood "),
- RouteType::Flood => f.write_str(" Flood "),
- RouteType::Direct => f.write_str(" Direct"),
+ RouteType::TransportFlood => f.write_str("T-Flood "),
+ RouteType::Flood => f.write_str(" Flood "),
+ RouteType::Direct => f.write_str(" Direct"),
RouteType::TransportDirect => f.write_str("T-Direct"),
- RouteType::Invalid => f.write_str("INVALID "),
+ RouteType::Invalid => f.write_str("INVALID "),
}
}
}
@@ -270,7 +292,7 @@ impl From<u8> for RouteType {
0x01 => RouteType::Flood,
0x02 => RouteType::Direct,
0x03 => RouteType::TransportDirect,
- _ => RouteType::Invalid
+ _ => RouteType::Invalid,
}
}
}
@@ -294,7 +316,7 @@ impl From<u8> for PayloadVersion {
0x01 => PayloadVersion::VersionTwo,
0x02 => PayloadVersion::VersionThree,
0x03 => PayloadVersion::VersionFour,
- _ => PayloadVersion::Invalid
+ _ => PayloadVersion::Invalid,
}
}
}
@@ -302,11 +324,11 @@ impl From<u8> for PayloadVersion {
impl core::fmt::Display for PayloadVersion {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
- PayloadVersion::VersionOne => f.write_str("v1"),
- PayloadVersion::VersionTwo => f.write_str("v2"),
+ PayloadVersion::VersionOne => f.write_str("v1"),
+ PayloadVersion::VersionTwo => f.write_str("v2"),
PayloadVersion::VersionThree => f.write_str("v3"),
- PayloadVersion::VersionFour => f.write_str("v4"),
- PayloadVersion::Invalid => f.write_str("xx"),
+ PayloadVersion::VersionFour => f.write_str("v4"),
+ PayloadVersion::Invalid => f.write_str("xx"),
}
}
}
@@ -316,50 +338,53 @@ mod tests {
use core::str::FromStr;
use tinyvec::array_vec;
- use crate::packet_content::{PacketContent, Raw};
use super::*;
+ use crate::packet_content::{PacketContent, Raw};
#[test]
fn header_route_type() {
// The route type is the lowest-order two bits
- assert_eq!(RouteType::TransportFlood, RouteType::from(0x00));
- assert_eq!(RouteType::TransportFlood, RouteType::from(0xFC));
- assert_eq!(RouteType::Flood, RouteType::from(0x01));
- assert_eq!(RouteType::Flood, RouteType::from(0xFD));
- assert_eq!(RouteType::Direct, RouteType::from(0x02));
- assert_eq!(RouteType::Direct, RouteType::from(0xFE));
+ assert_eq!(RouteType::TransportFlood, RouteType::from(0x00));
+ assert_eq!(RouteType::TransportFlood, RouteType::from(0xFC));
+ assert_eq!(RouteType::Flood, RouteType::from(0x01));
+ assert_eq!(RouteType::Flood, RouteType::from(0xFD));
+ assert_eq!(RouteType::Direct, RouteType::from(0x02));
+ assert_eq!(RouteType::Direct, RouteType::from(0xFE));
assert_eq!(RouteType::TransportDirect, RouteType::from(0x03));
assert_eq!(RouteType::TransportDirect, RouteType::from(0xFF));
- assert_eq!(format!("{}", RouteType::TransportFlood), "T-Flood ");
- assert_eq!(format!("{}", RouteType::Flood), " Flood ");
- assert_eq!(format!("{}", RouteType::Direct), " Direct");
+ assert_eq!(format!("{}", RouteType::TransportFlood), "T-Flood ");
+ assert_eq!(format!("{}", RouteType::Flood), " Flood ");
+ assert_eq!(format!("{}", RouteType::Direct), " Direct");
assert_eq!(format!("{}", RouteType::TransportDirect), "T-Direct");
- assert_eq!(format!("{}", RouteType::Invalid), "INVALID ");
+ assert_eq!(format!("{}", RouteType::Invalid), "INVALID ");
}
#[test]
fn header_version() {
- assert_eq!(PayloadVersion::VersionOne, PayloadVersion::from(0x00));
- assert_eq!(PayloadVersion::VersionOne, PayloadVersion::from(0x3F));
- assert_eq!(PayloadVersion::VersionTwo, PayloadVersion::from(0x40));
- assert_eq!(PayloadVersion::VersionTwo, PayloadVersion::from(0x7F));
+ assert_eq!(PayloadVersion::VersionOne, PayloadVersion::from(0x00));
+ assert_eq!(PayloadVersion::VersionOne, PayloadVersion::from(0x3F));
+ assert_eq!(PayloadVersion::VersionTwo, PayloadVersion::from(0x40));
+ assert_eq!(PayloadVersion::VersionTwo, PayloadVersion::from(0x7F));
assert_eq!(PayloadVersion::VersionThree, PayloadVersion::from(0x80));
assert_eq!(PayloadVersion::VersionThree, PayloadVersion::from(0xBF));
- assert_eq!(PayloadVersion::VersionFour, PayloadVersion::from(0xC0));
- assert_eq!(PayloadVersion::VersionFour, PayloadVersion::from(0xFF));
+ assert_eq!(PayloadVersion::VersionFour, PayloadVersion::from(0xC0));
+ assert_eq!(PayloadVersion::VersionFour, PayloadVersion::from(0xFF));
- assert_eq!(format!("{}", PayloadVersion::VersionOne), "v1");
- assert_eq!(format!("{}", PayloadVersion::VersionTwo), "v2");
+ assert_eq!(format!("{}", PayloadVersion::VersionOne), "v1");
+ assert_eq!(format!("{}", PayloadVersion::VersionTwo), "v2");
assert_eq!(format!("{}", PayloadVersion::VersionThree), "v3");
- assert_eq!(format!("{}", PayloadVersion::VersionFour), "v4");
- assert_eq!(format!("{}", PayloadVersion::Invalid), "xx");
+ assert_eq!(format!("{}", PayloadVersion::VersionFour), "v4");
+ assert_eq!(format!("{}", PayloadVersion::Invalid), "xx");
}
#[test]
fn packet() {
// Check the hex decode errors
- assert_eq!(Err(hex::FromHexError::InvalidHexCharacter { c: 's', index: 0 }), Packet::from_str("s0"));
+ assert_eq!(
+ Err(hex::FromHexError::InvalidHexCharacter { c: 's', index: 0 }),
+ Packet::from_str("s0")
+ );
assert_eq!(Err(hex::FromHexError::OddLength), Packet::from_str("0"));
// Check errors related to packet length issues
@@ -387,7 +412,7 @@ mod tests {
lhs_packet.version = PayloadVersion::VersionTwo;
let rhs_packet = Packet::from_str("420102").unwrap();
assert_eq!(lhs_packet, rhs_packet);
-
+
// Ensure packet remainder is captured. This
// will test version 1 plus transport
let lhs_packet = Packet {
@@ -395,12 +420,19 @@ mod tests {
version: PayloadVersion::VersionOne,
path: array_vec!([u16; 64] => 0x06, 0x07, 0x08, 0x09, 0x0A),
transport: [0x0102, 0x0304],
- raw_content: Bytes::copy_from_slice(&[0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19]),
- content: PacketContent::Raw(Raw { bytes: Bytes::copy_from_slice(&[0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19])}),
+ raw_content: Bytes::copy_from_slice(&[
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ ]),
+ content: PacketContent::Raw(Raw {
+ bytes: Bytes::copy_from_slice(&[
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
+ ]),
+ }),
incomplete: false,
};
- let rhs_packet: Packet = Packet::from_str("3F0201040305060708090A10111213141516171819").unwrap();
+ let rhs_packet: Packet =
+ Packet::from_str("3F0201040305060708090A10111213141516171819").unwrap();
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_eq!(format!("{}", rhs_packet), compare_string);
@@ -417,21 +449,36 @@ mod tests {
transport: [0, 1],
raw_content: Bytes::new(),
content: PacketContent::Invalid,
- incomplete: false
+ incomplete: false,
};
- assert_eq!(format!("{}", packet), " Direct | v1 | | [] | | INVALID | INVALID");
+ assert_eq!(
+ format!("{}", packet),
+ " Direct | v1 | | [] | | INVALID | INVALID"
+ );
packet.path.push(0x01);
- assert_eq!(format!("{}", packet), " Direct | v1 | | [01] | | INVALID | INVALID");
+ assert_eq!(
+ format!("{}", packet),
+ " Direct | v1 | | [01] | | INVALID | INVALID"
+ );
packet.path.push(0x02);
- assert_eq!(format!("{}", packet), " Direct | v1 | | [01, 02] | | INVALID | INVALID");
+ assert_eq!(
+ format!("{}", packet),
+ " Direct | v1 | | [01, 02] | | INVALID | INVALID"
+ );
packet.path.push(0xff);
- assert_eq!(format!("{}", packet), " Direct | v1 | | [01, 02, ff] | | INVALID | INVALID");
+ assert_eq!(
+ format!("{}", packet),
+ " Direct | v1 | | [01, 02, ff] | | INVALID | INVALID"
+ );
packet.incomplete = true;
- assert_eq!(format!("{}", packet), " Direct | v1 | | [01, 02, ff] | x | INVALID | INVALID");
+ assert_eq!(
+ format!("{}", packet),
+ " Direct | v1 | | [01, 02, ff] | x | INVALID | INVALID"
+ );
}
-} \ No newline at end of file
+}
diff --git a/src/packet_content.rs b/src/packet_content.rs
index 26230e1..a6fa914 100644
--- a/src/packet_content.rs
+++ b/src/packet_content.rs
@@ -1,5 +1,15 @@
+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};
-use crate::{ack::Ack, advert::Advert, anon_req::AnonReq, multipart::MultiPart, path::Path, request::Request, response::Response, text::{GroupData, GroupText, Text}, trace::Trace};
#[cfg(feature = "std")]
use crate::std_identity::Keystore;
@@ -23,41 +33,41 @@ pub enum PacketContent {
}
impl PacketContent {
- fn justified_name(&self) -> &str{
+ fn justified_name(&self) -> &str {
match self {
- PacketContent::Request(_) => " REQUEST | ",
- PacketContent::Response(_) => " RESPONSE | ",
- PacketContent::Text(_) => " TEXT | ",
- PacketContent::Ack(_) => " ACK | ",
- PacketContent::Advert(_) => " ADVERT | ",
+ 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::AnonReq(_) => " ANON REQ. | ",
+ PacketContent::Path(_) => " PATH | ",
+ PacketContent::Trace(_) => " TRACE | ",
PacketContent::Multipart(_) => " MULTIPART | ",
- PacketContent::Raw(_) => " RAW | ",
- PacketContent::Invalid => " INVALID | ",
+ 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)),
+ 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)),
+ 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 }),
+ 0x0F => PacketContent::Raw(Raw { bytes }),
- _ => PacketContent::Invalid
+ _ => PacketContent::Invalid,
}
}
}
@@ -67,19 +77,19 @@ impl core::fmt::Display for PacketContent {
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::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::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")
+ PacketContent::Raw(c) => core::fmt::Display::fmt(&c, f),
+ PacketContent::Invalid => f.write_str("INVALID"),
}
}
}
@@ -90,7 +100,7 @@ pub enum NodeType {
Room,
Repeater,
Sensor,
- Invalid
+ Invalid,
}
impl From<u8> for NodeType {
@@ -101,7 +111,7 @@ impl From<u8> for NodeType {
0x02 => NodeType::Repeater,
0x03 => NodeType::Room,
0x04 => NodeType::Sensor,
- _ => NodeType::Invalid
+ _ => NodeType::Invalid,
}
}
}
@@ -112,7 +122,7 @@ pub struct PeerToPeerCipher {
pub source: u8,
pub mac: u16,
pub ciphertext: Bytes,
- pub cleartext: Option<Bytes>
+ pub cleartext: Option<Bytes>,
}
impl From<Bytes> for PeerToPeerCipher {
@@ -124,11 +134,13 @@ impl From<Bytes> for PeerToPeerCipher {
source: 0x00,
mac: 0x0000,
ciphertext: Bytes::new(),
- cleartext: None
+ cleartext: None,
};
// Just check for the whole fixed-size part at once
- if bytes.len() < 4 { return response }
+ if bytes.len() < 4 {
+ return response;
+ }
response.destination = bytes.get_u8();
response.source = bytes.get_u8();
response.mac = bytes.get_u16();
@@ -141,14 +153,10 @@ impl From<Bytes> for PeerToPeerCipher {
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
- );
-
+ 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
@@ -160,7 +168,7 @@ impl PeerToPeerCipher {
#[derive(PartialEq, Debug, Clone)]
pub struct Raw {
- pub(crate) bytes: Bytes
+ pub(crate) bytes: Bytes,
}
impl core::fmt::Display for Raw {
@@ -176,16 +184,16 @@ mod tests {
#[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::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));
+ 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));
}
-} \ No newline at end of file
+}
diff --git a/src/path.rs b/src/path.rs
index a2eb1c9..a1aaedd 100644
--- a/src/path.rs
+++ b/src/path.rs
@@ -1,5 +1,5 @@
-use bytes::Bytes;
use crate::packet_content::PeerToPeerCipher;
+use bytes::Bytes;
#[derive(PartialEq, Debug, Clone)]
pub struct Path {
@@ -9,25 +9,31 @@ pub struct Path {
impl From<Bytes> for Path {
fn from(value: Bytes) -> Self {
Path {
- cipher: PeerToPeerCipher::from(value)
+ cipher: PeerToPeerCipher::from(value),
}
}
}
impl core::fmt::Display for Path {
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
+ ))
}
}
// Tests for std operations
#[cfg(test)]
mod tests {
+ use crate::{
+ packet::*,
+ packet_content::{PacketContent, PeerToPeerCipher},
+ };
use core::str::FromStr;
use hex::decode;
use tinyvec::array_vec;
- use crate::{packet::*, packet_content::{PacketContent, PeerToPeerCipher}};
-
+
use super::*;
#[test]
@@ -39,23 +45,32 @@ mod tests {
version: PayloadVersion::VersionOne,
path: array_vec!([u16; 64] => 0xBA, 0x03, 0x12, 0x7F, 0x7E, 0xA9, 0x22),
transport: [0, 0],
- raw_content: Bytes::copy_from_slice(&decode("1351768DD2DF32E1D02F5851379F5AFCC667AB273442FAB2943673F26DDBEB9595027474").unwrap()),
+ raw_content: Bytes::copy_from_slice(
+ &decode("1351768DD2DF32E1D02F5851379F5AFCC667AB273442FAB2943673F26DDBEB9595027474")
+ .unwrap(),
+ ),
content: PacketContent::Path(Path {
cipher: PeerToPeerCipher {
destination: 0x13,
source: 0x51,
mac: 0x768D,
- ciphertext: Bytes::copy_from_slice(&decode("D2DF32E1D02F5851379F5AFCC667AB273442FAB2943673F26DDBEB9595027474").unwrap()),
- cleartext: None
- }
+ ciphertext: Bytes::copy_from_slice(
+ &decode("D2DF32E1D02F5851379F5AFCC667AB273442FAB2943673F26DDBEB9595027474")
+ .unwrap(),
+ ),
+ cleartext: None,
+ },
}),
- incomplete: false
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
assert_eq!(lhs_packet, rhs_packet);
#[cfg(feature = "std")]
- assert_eq!(format!("{}", lhs_packet), " Flood | v1 | | [ba, 03, ... a9, 22] | | PATH | (51) -> (13) MAC: 768d ");
+ 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 fcf6278..0880c41 100644
--- a/src/request.rs
+++ b/src/request.rs
@@ -1,10 +1,10 @@
-use chrono::{DateTime, Utc};
use crate::packet_content::PeerToPeerCipher;
use bytes::{Buf, Bytes};
+use chrono::{DateTime, Utc};
#[derive(PartialEq, Debug, Clone)]
pub struct Request {
- pub cipher: PeerToPeerCipher,
+ pub cipher: PeerToPeerCipher,
pub cleartext: Option<ClearRequest>,
}
@@ -12,7 +12,7 @@ pub struct Request {
pub struct ClearRequest {
pub timestamp: DateTime<Utc>,
pub request_type: RequestType,
- pub request_data: Bytes
+ pub request_data: Bytes,
}
impl From<Bytes> for ClearRequest {
@@ -22,11 +22,13 @@ impl From<Bytes> for ClearRequest {
let mut clear_request = ClearRequest {
timestamp: DateTime::from_timestamp(0, 0).unwrap(),
request_type: RequestType::Invalid,
- request_data: Bytes::new()
+ request_data: Bytes::new(),
};
// Just check for the whole fixed-size part at once
- if bytes.len() < 5 { return clear_request }
+ if bytes.len() < 5 {
+ return clear_request;
+ }
if let Some(timestamp) = DateTime::from_timestamp(bytes.get_u32() as i64, 0) {
clear_request.timestamp = timestamp;
}
@@ -59,7 +61,7 @@ impl From<u8> for RequestType {
0x04 => RequestType::MinMaxAvg,
0x05 => RequestType::ACL,
0x06 => RequestType::Neighbors,
- _ => RequestType::Invalid
+ _ => RequestType::Invalid,
}
}
}
@@ -67,13 +69,13 @@ impl From<u8> for RequestType {
impl core::fmt::Display for RequestType {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
- RequestType::Stats => f.write_str("STATS"),
+ RequestType::Stats => f.write_str("STATS"),
RequestType::Keepalive => f.write_str("KEEP ALIVE"),
RequestType::Telemetry => f.write_str("TELEMETRY"),
RequestType::MinMaxAvg => f.write_str("MIN/MAX/AVG"),
- RequestType::ACL => f.write_str("ACL"),
+ RequestType::ACL => f.write_str("ACL"),
RequestType::Neighbors => f.write_str("NEIGHBORS"),
- RequestType::Invalid => f.write_str("INVALID"),
+ RequestType::Invalid => f.write_str("INVALID"),
}
}
}
@@ -82,17 +84,16 @@ impl From<Bytes> for Request {
fn from(value: Bytes) -> Self {
Request {
cipher: PeerToPeerCipher::from(value),
- cleartext: None
+ cleartext: None,
}
}
}
impl core::fmt::Display for Request {
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 {
@@ -108,11 +109,16 @@ impl core::fmt::Display for Request {
mod tests {
use std::str::FromStr;
+ use crate::{
+ packet::*,
+ packet_content::{PacketContent, PeerToPeerCipher},
+ request::{ClearRequest, Request, RequestType},
+ std_identity::KeystoreInput,
+ };
+ use bytes::Bytes;
use chrono::DateTime;
use hex::decode;
- use bytes::Bytes;
use tinyvec::ArrayVec;
- use crate::{std_identity::KeystoreInput, packet::*, packet_content::{PacketContent, PeerToPeerCipher}, request::{ClearRequest, Request, RequestType}};
#[test]
fn request_type() {
@@ -125,14 +131,13 @@ mod tests {
assert_eq!(RequestType::from(0x07), RequestType::Invalid);
assert_eq!(RequestType::from(0xFF), RequestType::Invalid);
-
- assert_eq!(format!("{}", RequestType::Stats), "STATS");
+ assert_eq!(format!("{}", RequestType::Stats), "STATS");
assert_eq!(format!("{}", RequestType::Keepalive), "KEEP ALIVE");
assert_eq!(format!("{}", RequestType::Telemetry), "TELEMETRY");
assert_eq!(format!("{}", RequestType::MinMaxAvg), "MIN/MAX/AVG");
- assert_eq!(format!("{}", RequestType::ACL), "ACL");
+ assert_eq!(format!("{}", RequestType::ACL), "ACL");
assert_eq!(format!("{}", RequestType::Neighbors), "NEIGHBORS");
- assert_eq!(format!("{}", RequestType::Invalid), "INVALID");
+ assert_eq!(format!("{}", RequestType::Invalid), "INVALID");
}
#[test]
@@ -144,20 +149,26 @@ mod tests {
version: PayloadVersion::VersionOne,
path: ArrayVec::new(),
transport: [0, 0],
- raw_content: Bytes::copy_from_slice(&decode("12341d87ccaac89563cbb39d2333b725e407a1a6").unwrap()),
+ raw_content: Bytes::copy_from_slice(
+ &decode("12341d87ccaac89563cbb39d2333b725e407a1a6").unwrap(),
+ ),
content: PacketContent::Request(Request {
cipher: PeerToPeerCipher {
destination: 0x12,
source: 0x34,
mac: 0x1d87,
- ciphertext: Bytes::copy_from_slice(&decode("ccaac89563cbb39d2333b725e407a1a6").unwrap()),
- cleartext: Some(Bytes::copy_from_slice(b"\x9d\xd9\x16\xd2\x01\0\0\0\0\x9d0\x96\xbb\0\0\0")),
+ ciphertext: Bytes::copy_from_slice(
+ &decode("ccaac89563cbb39d2333b725e407a1a6").unwrap(),
+ ),
+ cleartext: Some(Bytes::copy_from_slice(
+ b"\x9d\xd9\x16\xd2\x01\0\0\0\0\x9d0\x96\xbb\0\0\0",
+ )),
},
cleartext: Some(ClearRequest {
timestamp: DateTime::from_timestamp_secs(3524712861).unwrap(),
request_type: crate::request::RequestType::Stats,
request_data: Bytes::copy_from_slice(b"\0\0\0\0\x9d0\x96\xbb\0\0\0"),
- })
+ }),
}),
incomplete: false,
};
@@ -167,7 +178,10 @@ mod tests {
let file_contents = include_str!("../test_identities_file.toml");
let keystore_in: KeystoreInput = toml::from_str(file_contents).unwrap();
let keystore = keystore_in.compile();
- assert_eq!(format!("{}", rhs_packet.content), " REQUEST | (34) -> (12) MAC: 1d87 ENCRYPTED");
+ assert_eq!(
+ format!("{}", rhs_packet.content),
+ " REQUEST | (34) -> (12) MAC: 1d87 ENCRYPTED"
+ );
rhs_packet.try_decrypt(&keystore);
@@ -179,26 +193,32 @@ mod tests {
#[test]
fn neighbors_request() {
let sample = "02001234EB5862E311F3321EB6EE9BEB75E060342CF8";
-
- let lhs_packet = Packet {
+
+ let lhs_packet = Packet {
route_type: RouteType::Direct,
version: PayloadVersion::VersionOne,
path: ArrayVec::new(),
transport: [0, 0],
- raw_content: Bytes::copy_from_slice(&decode("1234EB5862E311F3321EB6EE9BEB75E060342CF8").unwrap()),
+ raw_content: Bytes::copy_from_slice(
+ &decode("1234EB5862E311F3321EB6EE9BEB75E060342CF8").unwrap(),
+ ),
content: PacketContent::Request(Request {
cipher: PeerToPeerCipher {
destination: 0x12,
source: 0x34,
mac: 0xEB58,
- ciphertext: Bytes::copy_from_slice(&decode("62E311F3321EB6EE9BEB75E060342CF8").unwrap()),
- cleartext: Some(Bytes::copy_from_slice(b"\x9d\xd9\x16\xd2\x01\0\0\0\0\x9d0\x96\xbb\0\0\0")),
+ ciphertext: Bytes::copy_from_slice(
+ &decode("62E311F3321EB6EE9BEB75E060342CF8").unwrap(),
+ ),
+ cleartext: Some(Bytes::copy_from_slice(
+ b"\x9d\xd9\x16\xd2\x01\0\0\0\0\x9d0\x96\xbb\0\0\0",
+ )),
},
cleartext: Some(ClearRequest {
timestamp: DateTime::from_timestamp_secs(3524712861).unwrap(),
request_type: crate::request::RequestType::Neighbors,
- request_data: Bytes::copy_from_slice( b"\0\n\0\0\0\x04\x07v\x95\xb1\0"),
- })
+ request_data: Bytes::copy_from_slice(b"\0\n\0\0\0\x04\x07v\x95\xb1\0"),
+ }),
}),
incomplete: false,
};
@@ -216,6 +236,5 @@ mod tests {
// assert!(format!("{}", rhs_packet.content) == " REQUEST | (34) -> (12) MAC: 1d87 at: 2081-09-10 06:54:21 UTC STATS");
// assert_eq!(lhs_packet, rhs_packet);
- }
-
-} \ No newline at end of file
+ }
+}
diff --git a/src/response.rs b/src/response.rs
index f68e881..9e95c19 100644
--- a/src/response.rs
+++ b/src/response.rs
@@ -1,19 +1,18 @@
-
+use crate::packet_content::PeerToPeerCipher;
use bytes::{Buf, Bytes};
use chrono::{DateTime, Utc};
-use crate::packet_content::PeerToPeerCipher;
#[derive(PartialEq, Debug, Clone)]
pub struct Response {
pub(crate) cipher: PeerToPeerCipher,
- pub cleartext: Option<ClearResponse>
+ pub cleartext: Option<ClearResponse>,
}
impl From<Bytes> for Response {
fn from(value: Bytes) -> Self {
Response {
cipher: PeerToPeerCipher::from(value),
- cleartext: None
+ cleartext: None,
}
}
}
@@ -34,29 +33,27 @@ pub enum ResponseContent {
#[repr(C)]
#[derive(PartialEq, Debug, Clone)]
pub struct RepeaterStats {
- pub batt_milli_volts: u16,
- pub curr_tx_queue_len: u16,
- pub noise_floor: i16,
- pub last_rssi: i16,
- pub n_packets_recv: u32,
- pub n_packets_sent: u32,
- pub total_air_time_secs: u32,
- pub total_up_time_secs: u32,
- pub n_sent_flood: u32,
- pub n_sent_direct: u32,
- pub n_recv_flood: u32,
- pub n_recv_direct: u32,
- pub err_events: u16,
- pub last_snr: i16,
- pub n_direct_dups: u16,
- pub n_flood_dups: u16,
- pub total_rx_air_time_secs: u32,
+ pub batt_milli_volts: u16,
+ pub curr_tx_queue_len: u16,
+ pub noise_floor: i16,
+ pub last_rssi: i16,
+ pub n_packets_recv: u32,
+ pub n_packets_sent: u32,
+ pub total_air_time_secs: u32,
+ pub total_up_time_secs: u32,
+ pub n_sent_flood: u32,
+ pub n_sent_direct: u32,
+ pub n_recv_flood: u32,
+ pub n_recv_direct: u32,
+ pub err_events: u16,
+ pub last_snr: i16,
+ pub n_direct_dups: u16,
+ pub n_flood_dups: u16,
+ pub total_rx_air_time_secs: u32,
}
#[derive(PartialEq, Debug, Clone)]
-pub struct Telemetry {
-
-}
+pub struct Telemetry {}
impl From<Bytes> for ClearResponse {
fn from(value: Bytes) -> Self {
@@ -64,10 +61,12 @@ impl From<Bytes> for ClearResponse {
let mut clear_response = ClearResponse {
timestamp: DateTime::from_timestamp(0, 0).unwrap(),
- content: ResponseContent::Invalid
+ content: ResponseContent::Invalid,
};
- if bytes.len() < 4 { return clear_response }
+ if bytes.len() < 4 {
+ return clear_response;
+ }
if let Some(timestamp) = DateTime::from_timestamp(bytes.get_u32_le() as i64, 0) {
clear_response.timestamp = timestamp;
}
@@ -78,9 +77,9 @@ impl From<Bytes> for ClearResponse {
// are exactly 0x0174 then we'll assume it's a telemetry packet.
// let maybe_cayenne = bytes.clone().get_u16();
// if maybe_cayenne == 0x0174 {
- // println!("CayenneLPP: {} bytes: {}", bytes.len(), encode(&bytes));
+ // println!("CayenneLPP: {} bytes: {}", bytes.len(), encode(&bytes));
// } else {
- // println!("{} bytes: {}", value.len(), encode(&value));
+ // println!("{} bytes: {}", value.len(), encode(&value));
// }
clear_response
@@ -89,10 +88,9 @@ impl From<Bytes> for ClearResponse {
impl core::fmt::Display for Response {
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.cipher.cleartext {
@@ -105,11 +103,16 @@ impl core::fmt::Display for Response {
#[cfg(test)]
mod tests {
- use std::str::FromStr;
+ use crate::{
+ packet::*,
+ packet_content::{PacketContent, PeerToPeerCipher},
+ response::Response,
+ std_identity::KeystoreInput,
+ };
use bytes::Bytes;
use hex::decode;
+ use std::str::FromStr;
use tinyvec::ArrayVec;
- use crate::{std_identity::KeystoreInput, packet::*, packet_content::{PacketContent, PeerToPeerCipher}, response::Response};
#[test]
fn response_encrypted() {
@@ -136,7 +139,10 @@ mod tests {
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")
+ assert_eq!(
+ format!("{}", lhs_packet),
+ " Direct | v1 | | [] | | RESPONSE | (12) -> (34) MAC: b900 ENCRYPTED"
+ )
}
#[test]
@@ -269,7 +275,6 @@ mod tests {
// assert_eq!(lhs_packet, rhs_packet);
}
-
#[test]
fn telemetry_response() {
let sample = "06003412187C3AE03E52D347B957D634221DB5E86815";
@@ -301,4 +306,4 @@ mod tests {
println!("{:#?}", rhs_packet);
// assert_eq!(lhs_packet, rhs_packet);
}
-} \ No newline at end of file
+}
diff --git a/src/std_identity.rs b/src/std_identity.rs
index fdc8dff..80c1651 100644
--- a/src/std_identity.rs
+++ b/src/std_identity.rs
@@ -1,14 +1,18 @@
-use std::{collections::{HashMap, HashSet}, rc::Rc, str::FromStr};
+use crate::crypto::{PrivateKey, PublicKey, SharedSecret};
use bytes::Bytes;
use log::warn;
-use crate::{crypto::{PrivateKey, PublicKey, SharedSecret}};
+use std::{
+ collections::{HashMap, HashSet},
+ rc::Rc,
+ str::FromStr,
+};
use serde::{Deserialize, de};
#[derive(PartialEq, Clone, Deserialize, Debug)]
/// The Identity structure contains the information to decrypt
/// incoming messages and sign and encrypt outgoing messages.
-///
+///
/// It has the necessary cryptographic material needed to appear
/// as this identity when creating messages.
pub struct Identity {
@@ -34,14 +38,14 @@ pub struct Identity {
/// used because there are many many hash collisions
/// when using just the 1-byte hash prefix.
#[serde(skip)]
- pub secrets: HashSet<(Rc<String>, SharedSecret)>
+ pub secrets: HashSet<(Rc<String>, SharedSecret)>,
}
#[derive(PartialEq, Clone, Deserialize, Debug)]
/// The Contact structure contains the information needed
/// to decrypt messages from a remote user intended for
/// either an identity or a channel.
-///
+///
/// It's cryptographic material is also needed to uniquely
/// identify the origin of a message. Most source values
/// are only one byte, so that information just limits the
@@ -53,7 +57,7 @@ pub struct Contact {
/// The provided public key of the remote contact
#[serde(deserialize_with = "deserialize_public_key")]
- pub public_key: PublicKey
+ pub public_key: PublicKey,
}
#[derive(PartialEq, Clone, Deserialize, Debug)]
@@ -68,7 +72,7 @@ pub struct Group {
/// The group's shared secret
#[serde(deserialize_with = "deserialize_secret")]
- pub secret: SharedSecret
+ pub secret: SharedSecret,
}
#[derive(PartialEq, Clone, Deserialize, Debug)]
@@ -87,7 +91,13 @@ impl Keystore {
}
}
- pub fn decrypt_and_id_p2p(&self, _source: u8, _dest: u8, mac: u16, data: &Bytes) -> Option<(Bytes, Rc<String>, Rc<String>)> {
+ pub fn decrypt_and_id_p2p(
+ &self,
+ _source: u8,
+ _dest: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, Rc<String>, Rc<String>)> {
// Just brute-force all the secrets until one matches...
for identity in self.identities.iter() {
for secret in identity.1.secrets.iter() {
@@ -100,7 +110,12 @@ impl Keystore {
None
}
- pub fn decrypt_and_id_group(&self, _group_hash_prefix: u8, mac: u16, data: &Bytes) -> Option<(Bytes, u32)> {
+ pub fn decrypt_and_id_group(
+ &self,
+ _group_hash_prefix: u8,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, u32)> {
for group in self.groups.iter() {
let result = group.1.secret.mac_then_decrypt(mac, data);
if let Some(result) = result {
@@ -111,7 +126,13 @@ impl Keystore {
None
}
- pub fn decrypt_anon(&self, _dest: u8, pub_key: &PublicKey, mac: u16, data: &Bytes) -> Option<(Bytes, Rc<String>)> {
+ pub fn decrypt_anon(
+ &self,
+ _dest: u8,
+ pub_key: &PublicKey,
+ mac: u16,
+ data: &Bytes,
+ ) -> Option<(Bytes, Rc<String>)> {
// For each identity, create a shared secret against the provided public key and check it.
for identity in self.identities.iter() {
let secret = identity.1.private_key.create_secret(pub_key);
@@ -136,7 +157,7 @@ impl KeystoreInput {
let mut retval = Keystore {
identities: HashMap::new(),
contacts: HashMap::new(),
- groups: HashMap::new()
+ groups: HashMap::new(),
};
// Iterate through the input keystore file
@@ -152,15 +173,18 @@ impl KeystoreInput {
for name in contact_names {
if let Some(key_string) = self.contacts.get(name) {
match PublicKey::from_str(&key_string) {
- Ok(pub_key) => {
- contacts.push(Contact {
- name: Rc::new(name.to_string()),
- public_key: pub_key
- });
- },
- Err(e) => {
- warn!("Unable to add contact named \"{}\" because there was a problem with the public key: {}", name, e);
- }
+ Ok(pub_key) => {
+ contacts.push(Contact {
+ name: Rc::new(name.to_string()),
+ public_key: pub_key,
+ });
+ }
+ Err(e) => {
+ warn!(
+ "Unable to add contact named \"{}\" because there was a problem with the public key: {}",
+ name, e
+ );
+ }
}
}
}
@@ -177,18 +201,21 @@ impl KeystoreInput {
name: Rc::new(name.to_string()),
private_key,
public_key,
- secrets: HashSet::new()
+ secrets: HashSet::new(),
};
- i.secrets = contacts.iter().map(|c| {
- (c.name.clone(), i.private_key.create_secret(&c.public_key))
- }).collect();
-
+ i.secrets = contacts
+ .iter()
+ .map(|c| (c.name.clone(), i.private_key.create_secret(&c.public_key)))
+ .collect();
identities.push((i.name.clone(), i));
- },
+ }
Err(e) => {
- warn!("Unable to add identity named \"{}\" because there was a problem with the private key: {}", name, e);
+ warn!(
+ "Unable to add identity named \"{}\" because there was a problem with the private key: {}",
+ name, e
+ );
}
}
}
@@ -197,9 +224,7 @@ impl KeystoreInput {
retval.identities = HashMap::from_iter(identities);
// Create a hash of contacts
- let contacts = contacts.into_iter().map(|c| {
- (c.name.clone(), c)
- });
+ let contacts = contacts.into_iter().map(|c| (c.name.clone(), c));
retval.contacts = HashMap::from_iter(contacts);
@@ -218,136 +243,179 @@ impl KeystoreInput {
});
retval.groups = HashMap::from_iter(groups);
-
+
retval
}
}
fn deserialize_private_key<'de, D>(deserializer: D) -> Result<PrivateKey, D::Error>
- where D: de::Deserializer<'de> {
-
+where
+ D: de::Deserializer<'de>,
+{
+ use crate::crypto::PrivateKey;
use std::str::FromStr;
- use crate::crypto::{PrivateKey};
let s: String = de::Deserialize::deserialize(deserializer)?;
match PrivateKey::from_str(&s) {
Ok(key) => Ok(key),
- Err(e) => {
- Err(de::Error::custom(format!("{}", e)))
- }
+ Err(e) => Err(de::Error::custom(format!("{}", e))),
}
}
fn deserialize_public_key<'de, D>(deserializer: D) -> Result<PublicKey, D::Error>
- where D: de::Deserializer<'de> {
-
- use hex::decode;
+where
+ D: de::Deserializer<'de>,
+{
use crate::crypto::{MeshcoreCryptoError, PublicKey};
+ use hex::decode;
let s: String = de::Deserialize::deserialize(deserializer)?;
match decode(s) {
Err(hex::FromHexError::InvalidHexCharacter { c, index }) => {
- Err(de::Error::custom(format!("Invalid hex character {} at {} when decoding Public Key.", c, index)))
- },
- Err(hex::FromHexError::OddLength) => {
- Err(de::Error::custom(format!("Odd number of characters when decoding Public Key.")))
- },
- Err(hex::FromHexError::InvalidStringLength) => {
- Err(de::Error::custom(format!("Invalid hex string length when decoding Public Key.")))
+ Err(de::Error::custom(format!(
+ "Invalid hex character {} at {} when decoding Public Key.",
+ c, index
+ )))
}
+ Err(hex::FromHexError::OddLength) => Err(de::Error::custom(format!(
+ "Odd number of characters when decoding Public Key."
+ ))),
+ Err(hex::FromHexError::InvalidStringLength) => Err(de::Error::custom(format!(
+ "Invalid hex string length when decoding Public Key."
+ ))),
Ok(hex) => {
let key = PublicKey::try_from(hex.as_slice());
match key {
Ok(key) => Ok(key),
- Err(MeshcoreCryptoError::KeyCreationError) => {
- Err(de::Error::custom(format!("Unable to decompress public key points")))
- }
- Err(_) => {
- Err(de::Error::custom(format!("Invalid hex string length when decoding Public Key.")))
- }
+ Err(MeshcoreCryptoError::KeyCreationError) => Err(de::Error::custom(format!(
+ "Unable to decompress public key points"
+ ))),
+ Err(_) => Err(de::Error::custom(format!(
+ "Invalid hex string length when decoding Public Key."
+ ))),
}
}
}
}
fn deserialize_secret<'de, D>(deserializer: D) -> Result<SharedSecret, D::Error>
- where D: de::Deserializer<'de> {
-
- use std::str::FromStr;
+where
+ D: de::Deserializer<'de>,
+{
use crate::crypto::SharedSecret;
+ use std::str::FromStr;
let s: String = de::Deserialize::deserialize(deserializer)?;
match SharedSecret::from_str(&s) {
Ok(secret) => Ok(secret),
- Err(e) => {
- Err(de::Error::custom(format!("{}", e)))
- }
+ Err(e) => Err(de::Error::custom(format!("{}", e))),
}
}
// Tests for std operations
#[cfg(test)]
mod tests {
+ use hex::decode;
+ use log::LevelFilter;
+ use serde::de::IntoDeserializer;
+ use serde::de::value::{Error as ValueError, StrDeserializer};
use std::io;
use std::str::FromStr;
use std::sync::mpsc::{Sender, channel};
use std::vec;
- use hex::decode;
- use log::{LevelFilter};
- use serde::de::IntoDeserializer;
- use serde::de::value::{StrDeserializer, Error as ValueError};
- use crate::std_identity::KeystoreInput;
- use crate::crypto::*;
use super::*;
+ use crate::crypto::*;
+ use crate::std_identity::KeystoreInput;
#[test]
fn secret_deserializer() {
- let deserializer: StrDeserializer<ValueError> = "eb50a1bcb3e4e5d7bf69a57c9dada211".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "eb50a1bcb3e4e5d7bf69a57c9dada211".into_deserializer();
let result = deserialize_secret(deserializer);
match result {
- Ok(result) => assert_eq!(result, SharedSecret::from_str("eb50a1bcb3e4e5d7bf69a57c9dada211").unwrap()),
+ Ok(result) => assert_eq!(
+ result,
+ SharedSecret::from_str("eb50a1bcb3e4e5d7bf69a57c9dada211").unwrap()
+ ),
Err(err) => assert!(false, "Shouldn't have had an error, but got one: {}", err),
}
// Test failure conditions
- let deserializer: StrDeserializer<ValueError> = "eb50a1bcb3e4e5d7bf69a57c9dada21".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "eb50a1bcb3e4e5d7bf69a57c9dada21".into_deserializer();
let result = deserialize_secret(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Try From Slice Error", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Try From Slice Error",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
}
#[test]
fn public_key_deserializer() {
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f".into_deserializer();
let result = deserialize_public_key(deserializer);
match result {
- Ok(result) => assert_eq!(result, PublicKey::from_str("34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f").unwrap()),
+ Ok(result) => assert_eq!(
+ result,
+ PublicKey::from_str(
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219c8b8f"
+ )
+ .unwrap()
+ ),
Err(err) => assert!(false, "Shouldn't have had an error, but got one: {}", err),
}
// Test failure conditions
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec219".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Odd number of characters when decoding Public Key.", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Odd number of characters when decoding Public Key.",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec21".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4c164fec21".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Invalid hex string length when decoding Public Key.", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Invalid hex string length when decoding Public Key.",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8025eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8025eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Unable to decompress public key points", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Unable to decompress public key points",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
- let deserializer: StrDeserializer<ValueError> = "34569df1f9661916901669666fb8z25eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
+ let deserializer: StrDeserializer<ValueError> =
+ "34569df1f9661916901669666fb8z25eccb9ddb0499cddad4b164f4c219a8b8f".into_deserializer();
let result = deserialize_public_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Invalid hex character z at 28 when decoding Public Key.", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Invalid hex character z at 28 when decoding Public Key.",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
}
#[test]
@@ -363,12 +431,22 @@ mod tests {
let deserializer: StrDeserializer<ValueError> = "4885CF25975EA09742EF76DA587D0957E74EE02AAA34A001458E207E63CF7E6C4940C8C42C335862C71CC2F139633057D1FEE5687B172B27E1E0302A1D480E0".into_deserializer();
let result = deserialize_private_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Hex Decode Error", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Hex Decode Error",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
let deserializer: StrDeserializer<ValueError> = "4885CF25975EA09742EF76DA587D0957E74EE02AAA34A001458E207E63CF7E6C4940C8C42C335862C71CC2F139633057D1FEE5687B172B27E1E0302A1D480E".into_deserializer();
let result = deserialize_private_key(deserializer);
let error = result.unwrap_err();
- assert_eq!(error.to_string(), "Try From Slice Error", "Unexpected error response: {}", error.to_string());
+ assert_eq!(
+ error.to_string(),
+ "Try From Slice Error",
+ "Unexpected error response: {}",
+ error.to_string()
+ );
}
#[test]
@@ -394,7 +472,6 @@ mod tests {
])
};
assert_eq!(lhs, rhs);
-
}
// This struct is used as an adaptor, it implements io::Write and forwards the buffer to a mpsc::Sender
@@ -432,7 +509,9 @@ mod tests {
let _ = pretty_env_logger::env_logger::builder()
.is_test(true)
.filter_level(LevelFilter::max())
- .target(pretty_env_logger::env_logger::Target::Pipe(Box::new(WriteAdapter { sender: rx })))
+ .target(pretty_env_logger::env_logger::Target::Pipe(Box::new(
+ WriteAdapter { sender: rx },
+ )))
.try_init();
// Test failure conditions
@@ -459,11 +538,12 @@ mod tests {
.zip(expect.into_iter())
.for_each(|(got, expect)| {
println!("{}", &got);
- assert!(got.contains(expect), "Got log line: \"{}\" and didn't find \"{}\" within it as expected.", got, expect);
- }
- );
-
+ assert!(
+ got.contains(expect),
+ "Got log line: \"{}\" and didn't find \"{}\" within it as expected.",
+ got,
+ expect
+ );
+ });
}
-
-
-} \ No newline at end of file
+}
diff --git a/src/string_helper.rs b/src/string_helper.rs
index e5af42b..a18bfcd 100644
--- a/src/string_helper.rs
+++ b/src/string_helper.rs
@@ -1,5 +1,8 @@
#[cfg(not(feature = "std"))]
-use arraystring::{ArrayString, typenum::{U32, U160}};
+use arraystring::{
+ ArrayString,
+ typenum::{U32, U160},
+};
#[cfg(feature = "std")]
pub(crate) type NameString = String;
@@ -8,7 +11,7 @@ pub(crate) type NameString = String;
pub(crate) fn name_string_from_slice(s: &[u8]) -> NameString {
match String::from_utf8(s.to_vec()) {
Ok(s) => s,
- Err(_) => "Unable to create string".to_string()
+ Err(_) => "Unable to create string".to_string(),
}
}
@@ -32,10 +35,8 @@ pub(crate) fn message_string_from_slice(s: &[u8]) -> MessageString {
if let Some(s) = split.next() {
match String::from_utf8(s.to_vec()) {
- Ok(s) => {
- s.trim().to_string()
- }
- Err(_) => "Unable to create string".to_string()
+ Ok(s) => s.trim().to_string(),
+ Err(_) => "Unable to create string".to_string(),
}
} else {
"".to_string()
@@ -60,7 +61,7 @@ pub(crate) type PasswordString = ArrayString<U160>;
pub(crate) fn password_string_from_slice(s: &[u8]) -> PasswordString {
match String::from_utf8(s.to_vec()) {
Ok(s) => s,
- Err(_) => "".to_string()
+ Err(_) => "".to_string(),
}
}
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
+}
diff --git a/src/trace.rs b/src/trace.rs
index 3770702..b25aad7 100644
--- a/src/trace.rs
+++ b/src/trace.rs
@@ -9,7 +9,7 @@ pub struct Trace {
pub(crate) path_snr: ArrayVec<[f32; 64]>,
invalid: bool,
- pub(crate) temp_path: ArrayVec<[u16; 64]>
+ pub(crate) temp_path: ArrayVec<[u16; 64]>,
}
impl From<Bytes> for Trace {
@@ -25,17 +25,19 @@ impl From<Bytes> for Trace {
temp_path: ArrayVec::new(),
};
- if bytes.len() < 10 { return trace; }
+ if bytes.len() < 10 {
+ return trace;
+ }
- trace.tag = bytes.get_u32();
- trace.auth = bytes.get_u32();
- trace.flags = bytes.get_u8();
+ trace.tag = bytes.get_u32();
+ trace.auth = bytes.get_u32();
+ trace.flags = bytes.get_u8();
for byte in bytes.iter() {
trace.temp_path.push(*byte as u16);
}
- trace.invalid = false;
+ trace.invalid = false;
trace
}
}
@@ -53,13 +55,12 @@ impl core::fmt::Display for Trace {
// Tests for std operations
#[cfg(test)]
mod tests {
+ use crate::{packet::*, packet_content::PacketContent};
use core::str::FromStr;
use hex::decode;
use tinyvec::array_vec;
- use crate::{packet::*, packet_content::PacketContent};
-
- use super::*;
+ use super::*;
#[test]
fn trace() {
@@ -78,9 +79,8 @@ mod tests {
path_snr: array_vec!([f32; 64] => 11.0, -8.0, -3.75),
invalid: false,
temp_path: array_vec!([u16; 64] => 0xAC, 0xA0, 0x79),
- }
- ),
- incomplete: false
+ }),
+ incomplete: false,
};
let rhs_packet = Packet::from_str(sample).unwrap();
@@ -88,9 +88,9 @@ mod tests {
// We can only check the description in std mode
#[cfg(feature = "std")]
- assert_eq!(format!("{}", rhs_packet), " Direct | v1 | | [ac, a0, 79] | | TRACE | (ac): 11dB (a0): -8dB (79): -3.75dB ")
-
+ assert_eq!(
+ format!("{}", rhs_packet),
+ " Direct | v1 | | [ac, a0, 79] | | TRACE | (ac): 11dB (a0): -8dB (79): -3.75dB "
+ )
}
-
-
-} \ No newline at end of file
+}