From 45a6339c4cc078c608f36210512b9d7fbb1e4fb6 Mon Sep 17 00:00:00 2001 From: Vecna Date: Sat, 27 Apr 2024 17:28:33 -0400 Subject: [PATCH] Start testing simulated extra-infos --- src/extra_info.rs | 40 ++++++++++++++++++++++-- src/tests.rs | 77 +++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 113 insertions(+), 4 deletions(-) diff --git a/src/extra_info.rs b/src/extra_info.rs index 0886cd4..4cfdee9 100644 --- a/src/extra_info.rs +++ b/src/extra_info.rs @@ -5,10 +5,13 @@ Note, this is NOT a complete implementation of the document format. use chrono::DateTime; use julianday::JulianDay; use serde::{Deserialize, Serialize}; -use std::collections::{BTreeMap, HashMap, HashSet}; +use std::{ + collections::{BTreeMap, HashMap, HashSet}, + fmt, +}; /// Fields we need from extra-info document -#[derive(Eq, PartialEq, Hash, Serialize, Deserialize)] +#[derive(Clone, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] pub struct ExtraInfo { /// Bridge nickname, probably unused pub nickname: String, @@ -137,3 +140,36 @@ impl ExtraInfo { set } } + +/// Convert the ExtraInfo object to a string record, as in a downloaded file +impl fmt::Display for ExtraInfo { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut str = String::from("@type bridge-extra-info 1.3"); + str.push_str( + format!( + "\nextra-info {} {}", + self.nickname, + array_bytes::bytes2hex("", self.fingerprint).to_uppercase() + ) + .as_str(), + ); + let date = JulianDay::new(self.date.try_into().unwrap()).to_date(); + str.push_str(format!("\nbridge-stats-end {} 23:59:59 (86400 s)", date).as_str()); + str.push_str(format!("\npublished {} 23:59:59", date).as_str()); + + // These should be sorted in descending order by count, but that's not + // necessary for our purposes. + str.push_str("\nbridge-ips "); + let mut first_cc = true; + for (cc, count) in &self.bridge_ips { + if !first_cc { + str.push(','); + } + str.push_str(format!("{}={}", cc, count,).as_str()); + first_cc = false; + } + str.push_str("\n"); + + write!(f, "{}", str) + } +} diff --git a/src/tests.rs b/src/tests.rs index d0e0acc..97c3248 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -150,12 +150,12 @@ pub fn random() -> BridgeLine { } #[tokio::test] -async fn test_extra_infos() { +async fn test_download_extra_infos() { let bridge_to_test = array_bytes::hex2array("72E12B89136B45BBC81D1EF0AC7DDDBB91B148DB").unwrap(); // Open test database - let db: Db = sled::open("test_db_ei").unwrap(); + let db: Db = sled::open("test_db_dei").unwrap(); // Delete all data in test DB db.clear().unwrap(); @@ -180,6 +180,79 @@ async fn test_extra_infos() { bincode::deserialize(&db.get(bridge_to_test).unwrap().unwrap()).unwrap(); } +#[test] +fn test_simulate_extra_infos() { + let extra_info_str = r#"@type bridge-extra-info 1.3 +extra-info ElephantBridgeDE2 72E12B89136B45BBC81D1EF0AC7DDDBB91B148DB +master-key-ed25519 eWxjRwAWW7n8BGG9fNa6rApmBFbe3f0xcD7dqwOICW8 +published 2024-04-06 03:51:04 +transport obfs4 +write-history 2024-04-05 04:55:22 (86400 s) 31665735680,14918491136,15423603712,36168353792,40396827648 +read-history 2024-04-05 04:55:22 (86400 s) 31799622656,15229917184,15479115776,36317251584,40444155904 +ipv6-write-history 2024-04-05 04:55:22 (86400 s) 5972127744,610078720,516897792,327949312,640708608 +ipv6-read-history 2024-04-05 04:55:22 (86400 s) 4156158976,4040448000,2935756800,4263080960,6513532928 +dirreq-write-history 2024-04-05 04:55:22 (86400 s) 625217536,646188032,618014720,584386560,600778752 +dirreq-read-history 2024-04-05 04:55:22 (86400 s) 18816000,19000320,18484224,17364992,18443264 +geoip-db-digest 44073997E1ED63E183B79DE2A1757E9997A834E3 +geoip6-db-digest C0BF46880C6C132D746683279CC90DD4B2D31786 +dirreq-stats-end 2024-04-05 06:51:23 (86400 s) +dirreq-v3-ips ru=16,au=8,by=8,cn=8,gb=8,ir=8,mt=8,nl=8,pl=8,tn=8,tr=8,us=8 +dirreq-v3-reqs ru=72,gb=64,pl=32,cn=16,ir=16,us=16,au=8,by=8,mt=8,nl=8,tn=8,tr=8 +dirreq-v3-resp ok=216,not-enough-sigs=0,unavailable=0,not-found=0,not-modified=328,busy=0 +dirreq-v3-direct-dl complete=0,timeout=0,running=0 +dirreq-v3-tunneled-dl complete=212,timeout=4,running=0,min=21595,d1=293347,d2=1624137,q1=1911800,d3=2066929,d4=2415000,md=2888500,d6=3264000,d7=3851333,q3=41> +hidserv-stats-end 2024-04-05 06:51:23 (86400 s) +hidserv-rend-relayed-cells 7924 delta_f=2048 epsilon=0.30 bin_size=1024 +hidserv-dir-onions-seen -12 delta_f=8 epsilon=0.30 bin_size=8 +hidserv-v3-stats-end 2024-04-05 12:00:00 (86400 s) +hidserv-rend-v3-relayed-cells -4785 delta_f=2048 epsilon=0.30 bin_size=1024 +hidserv-dir-v3-onions-seen 5 delta_f=8 epsilon=0.30 bin_size=8 +padding-counts 2024-04-05 06:51:42 (86400 s) bin-size=10000 write-drop=0 write-pad=80000 write-total=79980000 read-drop=0 read-pad=1110000 read-total=7989000> +bridge-stats-end 2024-04-05 06:51:44 (86400 s) +bridge-ips ru=40,us=32,??=8,au=8,br=8,by=8,cn=8,de=8,eg=8,eu=8,gb=8,ge=8,hr=8,ie=8,ir=8,kp=8,lt=8,mt=8,nl=8,pl=8,ro=8,sg=8,tn=8,tr=8,vn=8 +bridge-ip-versions v4=104,v6=8 +bridge-ip-transports =56,obfs4=56 +router-digest-sha256 zK0VMl3i0B2eaeQTR03e2hZ0i8ytkuhK/psgD2J1/lQ +router-digest F30B38390C375E1EE74BFED844177804442569E0"#; + + let extra_info_set = ExtraInfo::parse_file(&extra_info_str); + assert_eq!(extra_info_set.len(), 1); + + let extra_info = extra_info_set.iter().next().unwrap().clone(); + + let extra_info_str = extra_info.to_string(); + + let extra_info_2 = ExtraInfo::parse_file(&extra_info_str) + .into_iter() + .next() + .unwrap() + .clone(); + assert_eq!(extra_info, extra_info_2); + + let bridge_to_test: [u8; 20] = + array_bytes::hex2array("72E12B89136B45BBC81D1EF0AC7DDDBB91B148DB").unwrap(); + + // Open test database + let db: Db = sled::open("test_db_sei").unwrap(); + + // Delete all data in test DB + db.clear().unwrap(); + assert!(!db.contains_key("bridges").unwrap()); + assert!(!db.contains_key(bridge_to_test).unwrap()); + + // TODO: Run local web server and change this to update_extra_infos + add_extra_info_to_db(&db, extra_info_2); + + // Check that DB contains information on a bridge with high uptime + assert!(db.contains_key("bridges").unwrap()); + let bridges: HashSet<[u8; 20]> = + bincode::deserialize(&db.get("bridges").unwrap().unwrap()).unwrap(); + assert!(bridges.contains(&bridge_to_test)); + assert!(db.contains_key(bridge_to_test).unwrap()); + let _bridge_info: BridgeInfo = + bincode::deserialize(&db.get(bridge_to_test).unwrap().unwrap()).unwrap(); +} + #[test] fn test_negative_reports() { let mut th = TestHarness::new();