tests.rs 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970
  1. #![allow(non_snake_case)]
  2. use crate::{
  3. analysis::{blocked_in, Analyzer},
  4. bridge_verification_info::BridgeVerificationInfo,
  5. *,
  6. };
  7. use lox_library::{
  8. bridge_table::{self, BridgeLine, BridgeTable},
  9. cred::Lox,
  10. proto::*,
  11. scalar_u32, BridgeAuth, BridgeDb,
  12. };
  13. use base64::{engine::general_purpose, Engine as _};
  14. use curve25519_dalek::{ristretto::RistrettoBasepointTable, Scalar};
  15. use rand::RngCore;
  16. use sha1::{Digest, Sha1};
  17. use std::{
  18. collections::{BTreeMap, HashMap, HashSet},
  19. sync::{Arc, Mutex},
  20. };
  21. struct TestHarness {
  22. bdb: BridgeDb,
  23. pub ba: BridgeAuth,
  24. }
  25. impl TestHarness {
  26. fn new() -> Self {
  27. TestHarness::new_buckets(5, 5)
  28. }
  29. fn new_buckets(num_buckets: u16, hot_spare: u16) -> Self {
  30. // Create a BridegDb
  31. let mut bdb = BridgeDb::new();
  32. // Create a BridgeAuth
  33. let mut ba = BridgeAuth::new(bdb.pubkey);
  34. // Make 3 x num_buckets open invitation bridges, in sets of 3
  35. for _ in 0..num_buckets {
  36. let bucket = [random(), random(), random()];
  37. let _ = ba.add_openinv_bridges(bucket, &mut bdb);
  38. }
  39. // Add hot_spare more hot spare buckets
  40. for _ in 0..hot_spare {
  41. let bucket = [random(), random(), random()];
  42. let _ = ba.add_spare_bucket(bucket, &mut bdb);
  43. }
  44. // Create the encrypted bridge table
  45. ba.enc_bridge_table();
  46. Self { bdb, ba }
  47. }
  48. fn advance_days(&mut self, days: u16) {
  49. self.ba.advance_days(days);
  50. }
  51. fn get_new_credential(&mut self) -> Lox {
  52. let inv = self.bdb.invite().unwrap();
  53. let (req, state) = open_invite::request(&inv);
  54. let resp = self.ba.handle_open_invite(req).unwrap();
  55. let (cred, _bridgeline) =
  56. open_invite::handle_response(state, resp, &self.ba.lox_pub).unwrap();
  57. cred
  58. }
  59. fn level_up(&mut self, cred: &Lox) -> Lox {
  60. let current_level = scalar_u32(&cred.trust_level).unwrap();
  61. if current_level == 0 {
  62. self.advance_days(trust_promotion::UNTRUSTED_INTERVAL.try_into().unwrap());
  63. let (promreq, promstate) =
  64. trust_promotion::request(cred, &self.ba.lox_pub, self.ba.today()).unwrap();
  65. let promresp = self.ba.handle_trust_promotion(promreq).unwrap();
  66. let migcred = trust_promotion::handle_response(promstate, promresp).unwrap();
  67. let (migreq, migstate) =
  68. migration::request(cred, &migcred, &self.ba.lox_pub, &self.ba.migration_pub)
  69. .unwrap();
  70. let migresp = self.ba.handle_migration(migreq).unwrap();
  71. let new_cred = migration::handle_response(migstate, migresp, &self.ba.lox_pub).unwrap();
  72. new_cred
  73. } else {
  74. self.advance_days(
  75. level_up::LEVEL_INTERVAL[usize::try_from(current_level).unwrap()]
  76. .try_into()
  77. .unwrap(),
  78. );
  79. let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
  80. let encbuckets = self.ba.enc_bridge_table();
  81. let bucket =
  82. bridge_table::BridgeTable::decrypt_bucket(id, &key, encbuckets.get(&id).unwrap())
  83. .unwrap();
  84. let reachcred = bucket.1.unwrap();
  85. let (lvreq, lvstate) = level_up::request(
  86. cred,
  87. &reachcred,
  88. &self.ba.lox_pub,
  89. &self.ba.reachability_pub,
  90. self.ba.today(),
  91. )
  92. .unwrap();
  93. let lvresp = self.ba.handle_level_up(lvreq).unwrap();
  94. let new_cred = level_up::handle_response(lvstate, lvresp, &self.ba.lox_pub).unwrap();
  95. new_cred
  96. }
  97. }
  98. fn get_bucket(&mut self, cred: &Lox) -> [BridgeLine; bridge_table::MAX_BRIDGES_PER_BUCKET] {
  99. let (id, key) = bridge_table::from_scalar(cred.bucket).unwrap();
  100. let encbuckets = self.ba.enc_bridge_table();
  101. let bucket =
  102. bridge_table::BridgeTable::decrypt_bucket(id, &key, encbuckets.get(&id).unwrap())
  103. .unwrap();
  104. bucket.0
  105. }
  106. }
  107. pub fn random() -> BridgeLine {
  108. let mut rng = rand::thread_rng();
  109. let mut res: BridgeLine = BridgeLine::default();
  110. // Pick a random 4-byte address
  111. let mut addr: [u8; 4] = [0; 4];
  112. rng.fill_bytes(&mut addr);
  113. // If the leading byte is 224 or more, that's not a valid IPv4
  114. // address. Choose an IPv6 address instead (but don't worry too
  115. // much about it being well formed).
  116. if addr[0] >= 224 {
  117. rng.fill_bytes(&mut res.addr);
  118. } else {
  119. // Store an IPv4 address as a v4-mapped IPv6 address
  120. res.addr[10] = 255;
  121. res.addr[11] = 255;
  122. res.addr[12..16].copy_from_slice(&addr);
  123. };
  124. let ports: [u16; 4] = [443, 4433, 8080, 43079];
  125. let portidx = (rng.next_u32() % 4) as usize;
  126. res.port = ports[portidx];
  127. res.uid_fingerprint = rng.next_u64();
  128. rng.fill_bytes(&mut res.fingerprint);
  129. let mut cert: [u8; 52] = [0; 52];
  130. rng.fill_bytes(&mut cert);
  131. let infostr: String = format!(
  132. "obfs4 cert={}, iat-mode=0",
  133. general_purpose::STANDARD_NO_PAD.encode(cert)
  134. );
  135. res.info[..infostr.len()].copy_from_slice(infostr.as_bytes());
  136. res
  137. }
  138. #[tokio::test]
  139. async fn test_extra_infos() {
  140. let bridge_to_test =
  141. array_bytes::hex2array("72E12B89136B45BBC81D1EF0AC7DDDBB91B148DB").unwrap();
  142. // Open test database
  143. let db: Db = sled::open("test_db").unwrap();
  144. // Delete all data in test DB
  145. db.clear().unwrap();
  146. assert!(!db.contains_key("bridges").unwrap());
  147. assert!(!db.contains_key(bridge_to_test).unwrap());
  148. // Download and process recent extra-infos files
  149. update_extra_infos(
  150. &db,
  151. "https://collector.torproject.org/recent/bridge-descriptors/extra-infos/",
  152. )
  153. .await
  154. .unwrap();
  155. // Check that DB contains information on a bridge with high uptime
  156. assert!(db.contains_key("bridges").unwrap());
  157. let bridges: HashSet<[u8; 20]> =
  158. bincode::deserialize(&db.get("bridges").unwrap().unwrap()).unwrap();
  159. assert!(bridges.contains(&bridge_to_test));
  160. assert!(db.contains_key(bridge_to_test).unwrap());
  161. let _bridge_info: BridgeInfo =
  162. bincode::deserialize(&db.get(bridge_to_test).unwrap().unwrap()).unwrap();
  163. }
  164. #[test]
  165. fn test_negative_reports() {
  166. let mut th = TestHarness::new();
  167. // Get new level 1 credential
  168. let cred = th.get_new_credential();
  169. let cred = th.level_up(&cred);
  170. let bridges = th.get_bucket(&cred);
  171. // Create BridgeVerificationInfo for each bridge
  172. let mut buckets = HashSet::<Scalar>::new();
  173. buckets.insert(cred.bucket);
  174. let bridge_info_1 = BridgeVerificationInfo {
  175. bridge_line: bridges[0],
  176. buckets: buckets.clone(),
  177. pubkey: None,
  178. };
  179. let bridge_info_2 = BridgeVerificationInfo {
  180. bridge_line: bridges[1],
  181. buckets: buckets.clone(),
  182. pubkey: None,
  183. };
  184. let bridge_info_3 = BridgeVerificationInfo {
  185. bridge_line: bridges[2],
  186. buckets: buckets.clone(),
  187. pubkey: None,
  188. };
  189. // Create reports
  190. let report_1 =
  191. NegativeReport::from_bridgeline(bridges[0], "ru".to_string(), BridgeDistributor::Lox);
  192. let report_2 =
  193. NegativeReport::from_lox_bucket(bridges[1].fingerprint, cred.bucket, "ru".to_string());
  194. let report_3 =
  195. NegativeReport::from_lox_credential(bridges[2].fingerprint, &cred, "ru".to_string());
  196. // Backdated reports
  197. let date = get_date();
  198. let mut rng = rand::thread_rng();
  199. let mut nonce = [0; 32];
  200. rng.fill_bytes(&mut nonce);
  201. let report_4 = NegativeReport::new(
  202. bridges[0].fingerprint,
  203. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
  204. &bridges[0],
  205. date - 1,
  206. nonce,
  207. )),
  208. "ru".to_string(),
  209. date - 1,
  210. nonce,
  211. BridgeDistributor::Lox,
  212. );
  213. let mut nonce = [0; 32];
  214. rng.fill_bytes(&mut nonce);
  215. let report_5 = NegativeReport::new(
  216. bridges[1].fingerprint,
  217. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
  218. &bridges[1],
  219. date - 2,
  220. nonce,
  221. )),
  222. "ru".to_string(),
  223. date - 2,
  224. nonce,
  225. BridgeDistributor::Lox,
  226. );
  227. let mut nonce = [0; 32];
  228. rng.fill_bytes(&mut nonce);
  229. let report_6 = NegativeReport::new(
  230. bridges[2].fingerprint,
  231. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
  232. &bridges[2],
  233. date - 3,
  234. nonce,
  235. )),
  236. "ru".to_string(),
  237. date - 3,
  238. nonce,
  239. BridgeDistributor::Lox,
  240. );
  241. // Verify reports
  242. assert!(report_1.verify(&bridge_info_1));
  243. assert!(report_2.verify(&bridge_info_2));
  244. assert!(report_3.verify(&bridge_info_3));
  245. assert!(report_4.verify(&bridge_info_1));
  246. assert!(report_5.verify(&bridge_info_2));
  247. assert!(report_6.verify(&bridge_info_3));
  248. // Check that deserialization fails under invalid conditions
  249. // Date in the future
  250. let mut invalid_report_1 =
  251. NegativeReport::from_bridgeline(bridges[0], "ru".to_string(), BridgeDistributor::Lox)
  252. .to_serializable_report();
  253. invalid_report_1.date = invalid_report_1.date + 2;
  254. // Date too far in past
  255. let mut invalid_report_2 =
  256. NegativeReport::from_bridgeline(bridges[1], "ru".to_string(), BridgeDistributor::Lox)
  257. .to_serializable_report();
  258. invalid_report_2.date = invalid_report_2.date - MAX_BACKDATE - 1;
  259. // Invalid country code
  260. let invalid_report_3 =
  261. NegativeReport::from_bridgeline(bridges[2], "xx".to_string(), BridgeDistributor::Lox)
  262. .to_serializable_report();
  263. assert!(invalid_report_1.to_report().is_err());
  264. assert!(invalid_report_2.to_report().is_err());
  265. assert!(invalid_report_3.to_report().is_err());
  266. // Check that verification fails with incorrect data
  267. let date = get_date();
  268. let mut rng = rand::thread_rng();
  269. // Incorrect BridgeLine hash
  270. let mut nonce = [0; 32];
  271. rng.fill_bytes(&mut nonce);
  272. let invalid_report_4 = NegativeReport::new(
  273. bridges[0].fingerprint,
  274. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
  275. &BridgeLine::default(),
  276. date,
  277. nonce,
  278. )),
  279. "ru".to_string(),
  280. date,
  281. nonce,
  282. BridgeDistributor::Lox,
  283. );
  284. // Incorrect bucket hash
  285. let mut nonce = [0; 32];
  286. rng.fill_bytes(&mut nonce);
  287. let invalid_report_5 = NegativeReport::new(
  288. bridges[1].fingerprint,
  289. ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&Scalar::ZERO, date, nonce)),
  290. "ru".to_string(),
  291. date,
  292. nonce,
  293. BridgeDistributor::Lox,
  294. );
  295. assert!(!invalid_report_4.verify(&bridge_info_1));
  296. assert!(!invalid_report_5.verify(&bridge_info_2));
  297. // Test that reports with duplicate nonces are rejected
  298. // Open test database
  299. let db: Db = sled::open("test_db").unwrap();
  300. // Delete all data in test DB
  301. db.clear().unwrap();
  302. assert!(!db.contains_key("nrs-to-process").unwrap());
  303. let mut nonce = [0; 32];
  304. rng.fill_bytes(&mut nonce);
  305. // A valid report
  306. let valid_report_1 = NegativeReport::new(
  307. bridges[0].fingerprint,
  308. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[0], date, nonce)),
  309. "ru".to_string(),
  310. date,
  311. nonce,
  312. BridgeDistributor::Lox,
  313. );
  314. // Report which reuses this nonce
  315. let invalid_report_1 = NegativeReport::new(
  316. bridges[0].fingerprint,
  317. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[0], date, nonce)),
  318. "ru".to_string(),
  319. date,
  320. nonce,
  321. BridgeDistributor::Lox,
  322. );
  323. // This is the same report
  324. assert_eq!(valid_report_1, invalid_report_1);
  325. // Report which reuses this nonce for a different bridge
  326. let invalid_report_2 = NegativeReport::new(
  327. bridges[1].fingerprint,
  328. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[1], date, nonce)),
  329. "ru".to_string(),
  330. date,
  331. nonce,
  332. BridgeDistributor::Lox,
  333. );
  334. // Report which uses this nonce but on a different day
  335. let valid_report_2 = NegativeReport::new(
  336. bridges[0].fingerprint,
  337. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(
  338. &bridges[0],
  339. date - 1,
  340. nonce,
  341. )),
  342. "ru".to_string(),
  343. date - 1,
  344. nonce,
  345. BridgeDistributor::Lox,
  346. );
  347. // Report with different nonce
  348. let mut nonce = [0; 32];
  349. rng.fill_bytes(&mut nonce);
  350. let valid_report_3 = NegativeReport::new(
  351. bridges[0].fingerprint,
  352. ProofOfBridgeKnowledge::HashOfBridgeLine(HashOfBridgeLine::new(&bridges[0], date, nonce)),
  353. "ru".to_string(),
  354. date,
  355. nonce,
  356. BridgeDistributor::Lox,
  357. );
  358. let map_key_1 = format!(
  359. "{}_{}_{}",
  360. array_bytes::bytes2hex("", valid_report_1.fingerprint),
  361. "ru".to_string(),
  362. date
  363. );
  364. save_negative_report_to_process(&db, valid_report_1);
  365. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  366. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  367. let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
  368. assert_eq!(negative_reports.len(), 1);
  369. save_negative_report_to_process(&db, invalid_report_1); // no change
  370. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  371. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  372. let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
  373. assert_eq!(negative_reports.len(), 1);
  374. let map_key_2 = format!(
  375. "{}_{}_{}",
  376. array_bytes::bytes2hex("", invalid_report_2.fingerprint),
  377. "ru".to_string(),
  378. date
  379. );
  380. save_negative_report_to_process(&db, invalid_report_2); // no change
  381. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  382. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  383. assert!(!nrs_to_process.contains_key(&map_key_2));
  384. let map_key_3 = format!(
  385. "{}_{}_{}",
  386. array_bytes::bytes2hex("", valid_report_2.fingerprint),
  387. "ru".to_string(),
  388. date - 1
  389. );
  390. save_negative_report_to_process(&db, valid_report_2);
  391. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  392. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  393. let negative_reports = nrs_to_process.get(&map_key_3).unwrap();
  394. assert_eq!(negative_reports.len(), 1);
  395. save_negative_report_to_process(&db, valid_report_3);
  396. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  397. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  398. let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
  399. assert_eq!(negative_reports.len(), 2);
  400. // Same tests, but use hash of bucket
  401. // Delete all data in test DB
  402. db.clear().unwrap();
  403. assert!(!db.contains_key("nrs-to-process").unwrap());
  404. let mut nonce = [0; 32];
  405. rng.fill_bytes(&mut nonce);
  406. // A valid report
  407. let valid_report_1 = NegativeReport::new(
  408. bridges[0].fingerprint,
  409. ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
  410. "ru".to_string(),
  411. date,
  412. nonce,
  413. BridgeDistributor::Lox,
  414. );
  415. // Report which reuses this nonce
  416. let invalid_report_1 = NegativeReport::new(
  417. bridges[0].fingerprint,
  418. ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
  419. "ru".to_string(),
  420. date,
  421. nonce,
  422. BridgeDistributor::Lox,
  423. );
  424. // This is the same report
  425. assert_eq!(valid_report_1, invalid_report_1);
  426. // Report which reuses this nonce for a different bridge
  427. let invalid_report_2 = NegativeReport::new(
  428. bridges[1].fingerprint,
  429. ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
  430. "ru".to_string(),
  431. date,
  432. nonce,
  433. BridgeDistributor::Lox,
  434. );
  435. // Report which uses this nonce but on a different day
  436. let valid_report_2 = NegativeReport::new(
  437. bridges[0].fingerprint,
  438. ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date - 1, nonce)),
  439. "ru".to_string(),
  440. date - 1,
  441. nonce,
  442. BridgeDistributor::Lox,
  443. );
  444. // Report with different nonce
  445. let mut nonce = [0; 32];
  446. rng.fill_bytes(&mut nonce);
  447. let valid_report_3 = NegativeReport::new(
  448. bridges[0].fingerprint,
  449. ProofOfBridgeKnowledge::HashOfBucket(HashOfBucket::new(&cred.bucket, date, nonce)),
  450. "ru".to_string(),
  451. date,
  452. nonce,
  453. BridgeDistributor::Lox,
  454. );
  455. let map_key_1 = format!(
  456. "{}_{}_{}",
  457. array_bytes::bytes2hex("", valid_report_1.fingerprint),
  458. "ru".to_string(),
  459. date
  460. );
  461. save_negative_report_to_process(&db, valid_report_1);
  462. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  463. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  464. let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
  465. assert_eq!(negative_reports.len(), 1);
  466. save_negative_report_to_process(&db, invalid_report_1); // no change
  467. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  468. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  469. let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
  470. assert_eq!(negative_reports.len(), 1);
  471. let map_key_2 = format!(
  472. "{}_{}_{}",
  473. array_bytes::bytes2hex("", invalid_report_2.fingerprint),
  474. "ru".to_string(),
  475. date
  476. );
  477. save_negative_report_to_process(&db, invalid_report_2); // no change
  478. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  479. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  480. assert!(!nrs_to_process.contains_key(&map_key_2));
  481. let map_key_3 = format!(
  482. "{}_{}_{}",
  483. array_bytes::bytes2hex("", valid_report_2.fingerprint),
  484. "ru".to_string(),
  485. date - 1
  486. );
  487. save_negative_report_to_process(&db, valid_report_2);
  488. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  489. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  490. let negative_reports = nrs_to_process.get(&map_key_3).unwrap();
  491. assert_eq!(negative_reports.len(), 1);
  492. save_negative_report_to_process(&db, valid_report_3);
  493. let nrs_to_process: BTreeMap<String, Vec<SerializableNegativeReport>> =
  494. bincode::deserialize(&db.get("nrs-to-process").unwrap().unwrap()).unwrap();
  495. let negative_reports = nrs_to_process.get(&map_key_1).unwrap();
  496. assert_eq!(negative_reports.len(), 2);
  497. }
  498. #[test]
  499. fn test_positive_reports() {
  500. let mut th = TestHarness::new();
  501. // Get new level 3 credential
  502. let cred = th.get_new_credential();
  503. let cred = th.level_up(&cred);
  504. let cred = th.level_up(&cred);
  505. let cred = th.level_up(&cred);
  506. let bridges = th.get_bucket(&cred);
  507. // Create BridgeVerificationInfo for each bridge
  508. let mut buckets = HashSet::<Scalar>::new();
  509. buckets.insert(cred.bucket);
  510. let bridge_info_1 = BridgeVerificationInfo {
  511. bridge_line: bridges[0],
  512. buckets: buckets.clone(),
  513. pubkey: None,
  514. };
  515. let bridge_info_2 = BridgeVerificationInfo {
  516. bridge_line: bridges[1],
  517. buckets: buckets.clone(),
  518. pubkey: None,
  519. };
  520. let bridge_info_3 = BridgeVerificationInfo {
  521. bridge_line: bridges[2],
  522. buckets: buckets.clone(),
  523. pubkey: None,
  524. };
  525. // Create reports
  526. let report_1 = PositiveReport::from_lox_credential(
  527. bridges[0].fingerprint,
  528. None,
  529. &cred,
  530. &th.ba.lox_pub,
  531. "ru".to_string(),
  532. )
  533. .unwrap();
  534. let report_2 = PositiveReport::from_lox_credential(
  535. bridges[1].fingerprint,
  536. None,
  537. &cred,
  538. &th.ba.lox_pub,
  539. "ru".to_string(),
  540. )
  541. .unwrap();
  542. let report_3 = PositiveReport::from_lox_credential(
  543. bridges[2].fingerprint,
  544. None,
  545. &cred,
  546. &th.ba.lox_pub,
  547. "ru".to_string(),
  548. )
  549. .unwrap();
  550. // Compute Htable
  551. let H = lox_library::proto::positive_report::compute_H(report_1.date);
  552. let Htable = RistrettoBasepointTable::create(&H);
  553. assert!(report_1.verify(&mut th.ba, &bridge_info_1, &Htable));
  554. assert!(report_2.verify(&mut th.ba, &bridge_info_2, &Htable));
  555. assert!(report_3.verify(&mut th.ba, &bridge_info_3, &Htable));
  556. // Check that user cannot use credential for other bridge
  557. // Get new credential
  558. let cred_2 = th.get_new_credential();
  559. let bridges_2 = th.get_bucket(&cred_2);
  560. let mut buckets_2 = HashSet::<Scalar>::new();
  561. buckets_2.insert(cred_2.bucket);
  562. let bridge_info_4 = BridgeVerificationInfo {
  563. bridge_line: bridges_2[0],
  564. buckets: buckets_2.clone(),
  565. pubkey: None,
  566. };
  567. // Use new credential to create positive report even we don't trust it
  568. let invalid_report_1 = PositiveReport::from_lox_credential(
  569. bridges_2[0].fingerprint,
  570. None,
  571. &cred_2,
  572. &th.ba.lox_pub,
  573. "ru".to_string(),
  574. );
  575. // Use first credential for bridge from second bucket
  576. let invalid_report_2 = PositiveReport::from_lox_credential(
  577. bridges_2[0].fingerprint,
  578. None,
  579. &cred,
  580. &th.ba.lox_pub,
  581. "ru".to_string(),
  582. );
  583. // Use second credential for bridge from first bucket
  584. let invalid_report_3 = PositiveReport::from_lox_credential(
  585. bridges[0].fingerprint,
  586. None,
  587. &cred_2,
  588. &th.ba.lox_pub,
  589. "ru".to_string(),
  590. );
  591. // Check that all of these fail
  592. assert!(invalid_report_1.is_err());
  593. assert!(!invalid_report_2
  594. .unwrap()
  595. .verify(&mut th.ba, &bridge_info_4, &Htable));
  596. assert!(invalid_report_3.is_err());
  597. // Check that deserialization fails under invalid conditions
  598. // Date in the future
  599. let mut invalid_report_4 = PositiveReport::from_lox_credential(
  600. bridges[0].fingerprint,
  601. None,
  602. &cred,
  603. &th.ba.lox_pub,
  604. "ru".to_string(),
  605. )
  606. .unwrap()
  607. .to_serializable_report();
  608. invalid_report_4.date = invalid_report_4.date + 2;
  609. // Invalid country code
  610. let invalid_report_5 = PositiveReport::from_lox_credential(
  611. bridges[0].fingerprint,
  612. None,
  613. &cred,
  614. &th.ba.lox_pub,
  615. "xx".to_string(),
  616. )
  617. .unwrap()
  618. .to_serializable_report();
  619. assert!(invalid_report_4.to_report().is_err());
  620. assert!(invalid_report_5.to_report().is_err());
  621. // Test storing to-be-processed positive reports to database
  622. // Create reports
  623. let report_1 = PositiveReport::from_lox_credential(
  624. bridges[0].fingerprint,
  625. None,
  626. &cred,
  627. &th.ba.lox_pub,
  628. "ru".to_string(),
  629. )
  630. .unwrap();
  631. let report_2 = PositiveReport::from_lox_credential(
  632. bridges[0].fingerprint,
  633. None,
  634. &cred,
  635. &th.ba.lox_pub,
  636. "ru".to_string(),
  637. )
  638. .unwrap();
  639. let report_3 = PositiveReport::from_lox_credential(
  640. bridges[1].fingerprint,
  641. None,
  642. &cred,
  643. &th.ba.lox_pub,
  644. "ru".to_string(),
  645. )
  646. .unwrap();
  647. // Open test database
  648. let db: Db = sled::open("test_db").unwrap();
  649. // Delete all data in test DB
  650. db.clear().unwrap();
  651. assert!(!db.contains_key("prs-to-process").unwrap());
  652. let map_key_1 = format!(
  653. "{}_{}_{}",
  654. array_bytes::bytes2hex("", report_1.fingerprint),
  655. &report_1.country,
  656. &report_1.date
  657. );
  658. let map_key_2 = format!(
  659. "{}_{}_{}",
  660. array_bytes::bytes2hex("", report_3.fingerprint),
  661. &report_3.country,
  662. &report_3.date
  663. );
  664. save_positive_report_to_process(&db, report_1);
  665. let prs_to_process: BTreeMap<String, Vec<SerializablePositiveReport>> =
  666. bincode::deserialize(&db.get("prs-to-process").unwrap().unwrap()).unwrap();
  667. let positive_reports = prs_to_process.get(&map_key_1).unwrap();
  668. assert_eq!(positive_reports.len(), 1);
  669. assert!(!prs_to_process.contains_key(&map_key_2));
  670. save_positive_report_to_process(&db, report_2);
  671. let prs_to_process: BTreeMap<String, Vec<SerializablePositiveReport>> =
  672. bincode::deserialize(&db.get("prs-to-process").unwrap().unwrap()).unwrap();
  673. let positive_reports = prs_to_process.get(&map_key_1).unwrap();
  674. assert_eq!(positive_reports.len(), 2);
  675. assert!(!prs_to_process.contains_key(&map_key_2));
  676. save_positive_report_to_process(&db, report_3);
  677. let prs_to_process: BTreeMap<String, Vec<SerializablePositiveReport>> =
  678. bincode::deserialize(&db.get("prs-to-process").unwrap().unwrap()).unwrap();
  679. // Check that this has not changed
  680. let positive_reports = prs_to_process.get(&map_key_1).unwrap();
  681. assert_eq!(positive_reports.len(), 2);
  682. // New report added to its own collection
  683. let positive_reports = prs_to_process.get(&map_key_2).unwrap();
  684. assert_eq!(positive_reports.len(), 1);
  685. }
  686. #[test]
  687. fn test_analysis() {
  688. // Test stage 1 analysis
  689. {
  690. let mut date = get_date();
  691. // New bridge info
  692. let mut bridge_info = BridgeInfo::new([0; 20], &String::default());
  693. bridge_info
  694. .info_by_country
  695. .insert("ru".to_string(), BridgeCountryInfo::new());
  696. let analyzer = analysis::NormalAnalyzer::new(5, 0.25);
  697. let confidence = 0.95;
  698. let mut blocking_countries = HashSet::<String>::new();
  699. // No data today
  700. assert_eq!(
  701. blocked_in(&analyzer, &bridge_info, confidence, date),
  702. blocking_countries
  703. );
  704. // 1 connection, 0 negative reports
  705. date += 1;
  706. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  707. BridgeInfoType::BridgeIps,
  708. date,
  709. 8,
  710. );
  711. assert_eq!(
  712. blocked_in(&analyzer, &bridge_info, confidence, date),
  713. blocking_countries
  714. );
  715. // 0 connections, 0 negative reports
  716. date += 1;
  717. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  718. BridgeInfoType::BridgeIps,
  719. date,
  720. 0,
  721. );
  722. assert_eq!(
  723. blocked_in(&analyzer, &bridge_info, confidence, date),
  724. blocking_countries
  725. );
  726. // 0 connections, 1 negative report
  727. // (exceeds scaled threshold)
  728. date += 1;
  729. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  730. BridgeInfoType::NegativeReports,
  731. date,
  732. 1,
  733. );
  734. blocking_countries.insert("ru".to_string());
  735. assert_eq!(
  736. blocked_in(&analyzer, &bridge_info, confidence, date),
  737. blocking_countries
  738. );
  739. }
  740. {
  741. let mut date = get_date();
  742. // New bridge info
  743. let mut bridge_info = BridgeInfo::new([0; 20], &String::default());
  744. bridge_info
  745. .info_by_country
  746. .insert("ru".to_string(), BridgeCountryInfo::new());
  747. let analyzer = analysis::NormalAnalyzer::new(5, 0.25);
  748. let confidence = 0.95;
  749. let mut blocking_countries = HashSet::<String>::new();
  750. // No data today
  751. assert_eq!(
  752. blocked_in(&analyzer, &bridge_info, confidence, date),
  753. blocking_countries
  754. );
  755. // 1 connection, 1 negative report
  756. date += 1;
  757. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  758. BridgeInfoType::BridgeIps,
  759. date,
  760. 8,
  761. );
  762. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  763. BridgeInfoType::NegativeReports,
  764. date,
  765. 1,
  766. );
  767. assert_eq!(
  768. blocked_in(&analyzer, &bridge_info, confidence, date),
  769. blocking_countries
  770. );
  771. // 8 connections, 2 negative reports
  772. date += 1;
  773. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  774. BridgeInfoType::BridgeIps,
  775. date,
  776. 8,
  777. );
  778. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  779. BridgeInfoType::NegativeReports,
  780. date,
  781. 2,
  782. );
  783. assert_eq!(
  784. blocked_in(&analyzer, &bridge_info, confidence, date),
  785. blocking_countries
  786. );
  787. // 8 connections, 3 negative reports
  788. // (exceeds scaled threshold)
  789. date += 1;
  790. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  791. BridgeInfoType::BridgeIps,
  792. date,
  793. 8,
  794. );
  795. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  796. BridgeInfoType::NegativeReports,
  797. date,
  798. 3,
  799. );
  800. blocking_countries.insert("ru".to_string());
  801. assert_eq!(
  802. blocked_in(&analyzer, &bridge_info, confidence, date),
  803. blocking_countries
  804. );
  805. }
  806. {
  807. let mut date = get_date();
  808. // New bridge info
  809. let mut bridge_info = BridgeInfo::new([0; 20], &String::default());
  810. bridge_info
  811. .info_by_country
  812. .insert("ru".to_string(), BridgeCountryInfo::new());
  813. let analyzer = analysis::NormalAnalyzer::new(5, 0.25);
  814. let confidence = 0.95;
  815. let mut blocking_countries = HashSet::<String>::new();
  816. // 24 connections, 5 negative reports
  817. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  818. BridgeInfoType::BridgeIps,
  819. date,
  820. 24,
  821. );
  822. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  823. BridgeInfoType::NegativeReports,
  824. date,
  825. 5,
  826. );
  827. assert_eq!(
  828. blocked_in(&analyzer, &bridge_info, confidence, date),
  829. blocking_countries
  830. );
  831. // 24 connections, 6 negative reports
  832. // (exceeds max threshold)
  833. date += 1;
  834. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  835. BridgeInfoType::BridgeIps,
  836. date,
  837. 24,
  838. );
  839. bridge_info.info_by_country.get_mut("ru").unwrap().add_info(
  840. BridgeInfoType::NegativeReports,
  841. date,
  842. 6,
  843. );
  844. blocking_countries.insert("ru".to_string());
  845. assert_eq!(
  846. blocked_in(&analyzer, &bridge_info, confidence, date),
  847. blocking_countries
  848. );
  849. }
  850. // TODO: Test stage 2 analysis
  851. // TODO: Test stage 3 analysis
  852. }