tests.rs 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296
  1. /*! Unit tests. Note that these require
  2. https://gitlab.torproject.org/vecna/lox/-/tree/main/crates/lox-distributor
  3. to be running. That fork adds an endpoint which allows for artificially
  4. increasing the number of days that have passed, which allows us to test
  5. trust migration and level up functions. */
  6. // TODO:
  7. // - unit test file save/read functions
  8. // - unit test migration when possible
  9. // Note: We can't run multiple time-changing tests simultaneously because
  10. // they will invalidate invites that haven't been redeemed yet.
  11. use crate::{networking::*, *};
  12. use lox_library::{
  13. bridge_table::{self, from_scalar, BridgeLine, BridgeTable},
  14. cred::Lox,
  15. proto::{
  16. level_up::{LEVEL_INTERVAL, LEVEL_INVITATIONS},
  17. trust_promotion::UNTRUSTED_INTERVAL,
  18. },
  19. scalar_u32,
  20. };
  21. use array_bytes;
  22. use sha1::{Digest, Sha1};
  23. use std::{
  24. cmp::min,
  25. collections::{HashMap, HashSet},
  26. };
  27. // Advance days on server
  28. pub async fn advance_days(net: &dyn Networking, days: u16) -> u32 {
  29. let resp = net
  30. .request(
  31. "/advancedays".to_string(),
  32. serde_json::to_vec(&days).unwrap(),
  33. )
  34. .await;
  35. let today: u32 = serde_json::from_slice(&resp).unwrap();
  36. today
  37. }
  38. // Advance days and level up
  39. pub async fn test_level_up(
  40. net: &dyn Networking,
  41. net_test: &dyn Networking,
  42. cred: &Lox,
  43. la_pubkeys: &Vec<IssuerPubKey>,
  44. ) -> Lox {
  45. let level = scalar_u32(&cred.trust_level).unwrap();
  46. advance_days(
  47. net_test,
  48. u16::try_from(LEVEL_INTERVAL[usize::try_from(level).unwrap()]).unwrap(),
  49. )
  50. .await;
  51. assert!(eligible_for_level_up(net, cred).await);
  52. let encbuckets = get_reachability_credential(net).await;
  53. println!("Leveling up from level {} to {}", level, min(4, level + 1));
  54. let new_cred = level_up(
  55. net,
  56. cred,
  57. &encbuckets,
  58. get_lox_pub(la_pubkeys),
  59. get_reachability_pub(la_pubkeys),
  60. )
  61. .await
  62. .0;
  63. new_cred
  64. }
  65. // These are all combined into the same test because otherwise we run into
  66. // issues with server state due to asynchronicity.
  67. #[tokio::test]
  68. async fn test_credential_operations() {
  69. let net = HyperNet {
  70. hostname: "http://localhost:8001".to_string(),
  71. };
  72. let net_test = HyperNet {
  73. hostname: "http://localhost:8005".to_string(),
  74. };
  75. let la_pubkeys = get_lox_auth_keys(&net).await;
  76. // Get new Lox credential
  77. println!("Getting new open-entry Lox credential");
  78. let open_inv = get_open_invitation(&net).await;
  79. let (mut cred, bridgeline) =
  80. get_lox_credential(&net, &open_inv, get_lox_pub(&la_pubkeys)).await;
  81. let bucket = get_bucket(&net, &cred).await;
  82. //assert_eq!(bucket[0], bridgeline); // For some reason, this sometimes fails.
  83. assert_eq!(bucket[1], BridgeLine::default());
  84. assert_eq!(bucket[2], BridgeLine::default());
  85. // Level up Lox Credential
  86. println!("Leveling up to level 1");
  87. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 0);
  88. // Advance server time and trust migrate
  89. advance_days(&net_test, u16::try_from(UNTRUSTED_INTERVAL).unwrap()).await;
  90. assert!(eligible_for_trust_promotion(&net, &cred).await);
  91. let migration_cred = trust_promotion(&net, &cred, get_lox_pub(&la_pubkeys)).await;
  92. cred = trust_migration(
  93. &net,
  94. &cred,
  95. &migration_cred,
  96. get_lox_pub(&la_pubkeys),
  97. get_migration_pub(&la_pubkeys),
  98. )
  99. .await;
  100. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 1);
  101. // Advance server time and level up
  102. for i in 1..LEVEL_INTERVAL.len() {
  103. assert_eq!(
  104. scalar_u32(&cred.trust_level).unwrap(),
  105. u32::try_from(i).unwrap()
  106. );
  107. /*
  108. advance_days(&net_test, u16::try_from(LEVEL_INTERVAL[i]).unwrap()).await;
  109. assert!(eligible_for_level_up(&net, &cred).await);
  110. let encbuckets = get_reachability_credential(&net).await;
  111. cred = level_up(
  112. &net,
  113. &cred,
  114. &encbuckets,
  115. get_lox_pub(&la_pubkeys),
  116. get_reachability_pub(&la_pubkeys),
  117. )
  118. .await
  119. .0;
  120. */
  121. cred = test_level_up(&net, &net_test, &cred, &la_pubkeys).await;
  122. // Assert that we increased level by 1 or stayed at 4
  123. assert_eq!(
  124. scalar_u32(&cred.trust_level).unwrap(),
  125. u32::try_from(min(i + 1, LEVEL_INTERVAL.len() - 1)).unwrap()
  126. );
  127. assert_eq!(
  128. scalar_u32(&cred.invites_remaining).unwrap(),
  129. LEVEL_INVITATIONS[i]
  130. );
  131. // Invite as many friends as possible
  132. for j in 0..LEVEL_INVITATIONS[i] {
  133. println!("Inviting friend {}", j);
  134. let encbuckets = get_reachability_credential(&net).await;
  135. let (new_cred, invite) = issue_invite(
  136. &net,
  137. &cred,
  138. &encbuckets,
  139. get_lox_pub(&la_pubkeys),
  140. get_reachability_pub(&la_pubkeys),
  141. get_invitation_pub(&la_pubkeys),
  142. )
  143. .await;
  144. let (friend_cred, friend_bucket) = redeem_invite(
  145. &net,
  146. &invite,
  147. get_lox_pub(&la_pubkeys),
  148. get_invitation_pub(&la_pubkeys),
  149. )
  150. .await;
  151. cred = new_cred;
  152. assert_eq!(
  153. scalar_u32(&cred.invites_remaining).unwrap(),
  154. LEVEL_INVITATIONS[i] - j - 1
  155. );
  156. assert_eq!(scalar_u32(&friend_cred.trust_level).unwrap(), 1);
  157. assert_eq!(&cred.bucket, &friend_cred.bucket);
  158. }
  159. }
  160. let net_tp = HyperNet {
  161. hostname: "http://localhost:8002".to_string(),
  162. };
  163. // helper function to create map of bridges from bucket to mark blocked
  164. fn bridges_to_block(
  165. bucket: [BridgeLine; bridge_table::MAX_BRIDGES_PER_BUCKET],
  166. num_bridges_to_block: usize,
  167. ) -> HashMap<String, HashSet<String>> {
  168. let mut blocked_bridges = HashMap::<String, HashSet<String>>::new();
  169. for i in 0..num_bridges_to_block {
  170. let mut hasher = Sha1::new();
  171. hasher.update(bucket[i].fingerprint);
  172. let mut countries = HashSet::<String>::new();
  173. countries.insert("RU".to_string());
  174. blocked_bridges.insert(array_bytes::bytes2hex("", hasher.finalize()), countries);
  175. }
  176. blocked_bridges
  177. }
  178. // Block 1 bridge
  179. println!("Marking one bridge blocked");
  180. let bridges = get_bucket(&net, &cred).await;
  181. let blocked_bridges = bridges_to_block(bridges, 1);
  182. let response = net_tp
  183. .request(
  184. "/reportblocked".to_string(),
  185. serde_json::to_string(&blocked_bridges).unwrap().into(),
  186. )
  187. .await;
  188. assert_eq!(String::from_utf8(response).unwrap(), "OK");
  189. // Time passes...
  190. advance_days(&net_test, 1).await;
  191. // Check that we still have a Bridge Reachability credential
  192. let etable = get_reachability_credential(&net).await;
  193. let (id, key) = from_scalar(cred.bucket).unwrap();
  194. let encbucket = etable.get(&id).unwrap();
  195. let bucket = BridgeTable::decrypt_bucket(id, &key, &encbucket).unwrap();
  196. assert!(bucket.1.is_some());
  197. println!("Can still obtain bridge reachability credential");
  198. // Block 2 bridges
  199. println!("Marking two bridges blocked");
  200. let bridges = get_bucket(&net, &cred).await;
  201. let blocked_bridges = bridges_to_block(bridges, 2);
  202. let response = net_tp
  203. .request(
  204. "/reportblocked".to_string(),
  205. serde_json::to_string(&blocked_bridges).unwrap().into(),
  206. )
  207. .await;
  208. assert_eq!(String::from_utf8(response).unwrap(), "OK");
  209. // Time passes...
  210. advance_days(&net_test, 1).await;
  211. // Check that we don't have a Bridge Reachability credential
  212. let etable = get_reachability_credential(&net).await;
  213. let (id, key) = from_scalar(cred.bucket).unwrap();
  214. let encbucket = etable.get(&id).unwrap();
  215. let bucket = BridgeTable::decrypt_bucket(id, &key, &encbucket).unwrap();
  216. assert!(bucket.1.is_none());
  217. println!("Cannot obtain bridge reachability credential");
  218. // Migrate to a new bucket
  219. println!("Migrating to a new bucket");
  220. let migration_cred = check_blockage(&net, &cred, get_lox_pub(&la_pubkeys)).await;
  221. cred = blockage_migration(
  222. &net,
  223. &cred,
  224. &migration_cred,
  225. get_lox_pub(&la_pubkeys),
  226. get_migration_pub(&la_pubkeys),
  227. )
  228. .await;
  229. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 2);
  230. // TODO: Figure out why this always fails
  231. // Level up to level 3
  232. cred = test_level_up(&net, &net_test, &cred, &la_pubkeys).await;
  233. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 3);
  234. assert_eq!(scalar_u32(&cred.blockages).unwrap(), 1);
  235. // Another blockage happens
  236. println!("Marking three bridges blocked");
  237. let bridges = get_bucket(&net, &cred).await;
  238. let blocked_bridges = bridges_to_block(bridges, 3);
  239. let response = net_tp
  240. .request(
  241. "/reportblocked".to_string(),
  242. serde_json::to_string(&blocked_bridges).unwrap().into(),
  243. )
  244. .await;
  245. assert_eq!(String::from_utf8(response).unwrap(), "OK");
  246. // Time passes...
  247. advance_days(&net_test, 1).await;
  248. // Migrate again
  249. println!("Migrating to a new bucket");
  250. let migration_cred = check_blockage(&net, &cred, get_lox_pub(&la_pubkeys)).await;
  251. cred = blockage_migration(
  252. &net,
  253. &cred,
  254. &migration_cred,
  255. get_lox_pub(&la_pubkeys),
  256. get_migration_pub(&la_pubkeys),
  257. )
  258. .await;
  259. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 1);
  260. // Level up to level 2
  261. cred = test_level_up(&net, &net_test, &cred, &la_pubkeys).await;
  262. // Can't level up to level 3
  263. assert!(!eligible_for_level_up(&net, &cred).await);
  264. }