tests.rs 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  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 (bucket, reachcred) = get_bucket(net, cred).await.unwrap();
  53. println!("Leveling up from level {} to {}", level, min(4, level + 1));
  54. let new_cred = level_up(
  55. net,
  56. cred,
  57. &reachcred.unwrap(),
  58. get_lox_pub(la_pubkeys),
  59. get_reachability_pub(la_pubkeys),
  60. )
  61. .await
  62. .unwrap();
  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.unwrap();
  76. // Get new Lox credential
  77. println!("Getting new open-entry Lox credential");
  78. let open_inv = get_open_invitation(&net).await.unwrap();
  79. let (mut cred, bridgeline) = get_lox_credential(&net, &open_inv, get_lox_pub(&la_pubkeys))
  80. .await
  81. .unwrap();
  82. let bucket = get_bucket(&net, &cred).await.unwrap().0;
  83. assert_eq!(bucket[0], bridgeline); // For some reason, this sometimes fails.
  84. assert_eq!(bucket[1], BridgeLine::default());
  85. assert_eq!(bucket[2], BridgeLine::default());
  86. // Level up Lox Credential
  87. println!("Leveling up to level 1");
  88. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 0);
  89. // Advance server time and trust migrate
  90. advance_days(&net_test, u16::try_from(UNTRUSTED_INTERVAL).unwrap()).await;
  91. assert!(eligible_for_trust_promotion(&net, &cred).await);
  92. let migration_cred = trust_promotion(&net, &cred, get_lox_pub(&la_pubkeys))
  93. .await
  94. .unwrap();
  95. cred = trust_migration(
  96. &net,
  97. &cred,
  98. &migration_cred,
  99. get_lox_pub(&la_pubkeys),
  100. get_migration_pub(&la_pubkeys),
  101. )
  102. .await
  103. .unwrap();
  104. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 1);
  105. // Advance server time and level up
  106. for i in 1..LEVEL_INTERVAL.len() {
  107. println!("Leveling up to level {}", min(i, LEVEL_INTERVAL.len() - 1));
  108. assert_eq!(
  109. scalar_u32(&cred.trust_level).unwrap(),
  110. u32::try_from(i).unwrap()
  111. );
  112. cred = test_level_up(&net, &net_test, &cred, &la_pubkeys).await;
  113. // Assert that we increased level by 1 or stayed at 4
  114. assert_eq!(
  115. scalar_u32(&cred.trust_level).unwrap(),
  116. u32::try_from(min(i + 1, LEVEL_INTERVAL.len() - 1)).unwrap()
  117. );
  118. assert_eq!(
  119. scalar_u32(&cred.invites_remaining).unwrap(),
  120. LEVEL_INVITATIONS[i]
  121. );
  122. // Invite as many friends as possible
  123. for j in 0..LEVEL_INVITATIONS[i] {
  124. println!("Inviting friend {}", j);
  125. let encbuckets = get_reachability_credential(&net).await.unwrap();
  126. let (new_cred, invite) = issue_invite(
  127. &net,
  128. &cred,
  129. &encbuckets,
  130. get_lox_pub(&la_pubkeys),
  131. get_reachability_pub(&la_pubkeys),
  132. get_invitation_pub(&la_pubkeys),
  133. )
  134. .await
  135. .unwrap();
  136. let (friend_cred, friend_bucket) = redeem_invite(
  137. &net,
  138. &invite,
  139. get_lox_pub(&la_pubkeys),
  140. get_invitation_pub(&la_pubkeys),
  141. )
  142. .await
  143. .unwrap();
  144. cred = new_cred;
  145. assert_eq!(
  146. scalar_u32(&cred.invites_remaining).unwrap(),
  147. LEVEL_INVITATIONS[i] - j - 1
  148. );
  149. assert_eq!(scalar_u32(&friend_cred.trust_level).unwrap(), 1);
  150. assert_eq!(&cred.bucket, &friend_cred.bucket);
  151. }
  152. }
  153. let net_tp = HyperNet {
  154. hostname: "http://localhost:8002".to_string(),
  155. };
  156. // helper function to create map of bridges from bucket to mark blocked
  157. fn bridges_to_block(
  158. bucket: [BridgeLine; bridge_table::MAX_BRIDGES_PER_BUCKET],
  159. num_bridges_to_block: usize,
  160. ) -> HashMap<String, HashSet<String>> {
  161. let mut blocked_bridges = HashMap::<String, HashSet<String>>::new();
  162. for i in 0..num_bridges_to_block {
  163. let mut hasher = Sha1::new();
  164. hasher.update(bucket[i].fingerprint);
  165. let mut countries = HashSet::<String>::new();
  166. countries.insert("RU".to_string());
  167. blocked_bridges.insert(array_bytes::bytes2hex("", hasher.finalize()), countries);
  168. }
  169. blocked_bridges
  170. }
  171. // Block 1 bridge
  172. println!("Marking one bridge blocked");
  173. let bridges = get_bucket(&net, &cred).await.unwrap().0;
  174. let blocked_bridges = bridges_to_block(bridges, 1);
  175. let response = net_tp
  176. .request(
  177. "/reportblocked".to_string(),
  178. serde_json::to_string(&blocked_bridges).unwrap().into(),
  179. )
  180. .await;
  181. assert_eq!(String::from_utf8(response).unwrap(), "OK");
  182. // Time passes...
  183. advance_days(&net_test, 1).await;
  184. // Check that we still have a Bucket Reachability credential
  185. let (bucket, reachcred) = get_bucket(&net, &cred).await.unwrap();
  186. assert!(reachcred.is_some());
  187. println!("Can still obtain bucket reachability credential");
  188. // Block 2 bridges
  189. println!("Marking two bridges blocked");
  190. let bridges = get_bucket(&net, &cred).await.unwrap().0;
  191. let blocked_bridges = bridges_to_block(bridges, 2);
  192. let response = net_tp
  193. .request(
  194. "/reportblocked".to_string(),
  195. serde_json::to_string(&blocked_bridges).unwrap().into(),
  196. )
  197. .await;
  198. assert_eq!(String::from_utf8(response).unwrap(), "OK");
  199. // Time passes...
  200. advance_days(&net_test, 1).await;
  201. // Check that we don't have a Bucket Reachability credential
  202. let (bucket, reachcred) = get_bucket(&net, &cred).await.unwrap();
  203. assert!(reachcred.is_none());
  204. println!("Cannot obtain bucket reachability credential");
  205. // Migrate to a new bucket
  206. println!("Migrating to a new bucket");
  207. let migration_cred = check_blockage(&net, &cred, get_lox_pub(&la_pubkeys))
  208. .await
  209. .unwrap();
  210. cred = blockage_migration(
  211. &net,
  212. &cred,
  213. &migration_cred,
  214. get_lox_pub(&la_pubkeys),
  215. get_migration_pub(&la_pubkeys),
  216. )
  217. .await
  218. .unwrap();
  219. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 2);
  220. assert_eq!(scalar_u32(&cred.blockages).unwrap(), 1);
  221. // Level up to level 3
  222. cred = test_level_up(&net, &net_test, &cred, &la_pubkeys).await;
  223. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 3);
  224. assert_eq!(scalar_u32(&cred.blockages).unwrap(), 1);
  225. // Another blockage happens
  226. println!("Marking three bridges blocked");
  227. let bridges = get_bucket(&net, &cred).await.unwrap().0;
  228. let blocked_bridges = bridges_to_block(bridges, 3);
  229. let response = net_tp
  230. .request(
  231. "/reportblocked".to_string(),
  232. serde_json::to_string(&blocked_bridges).unwrap().into(),
  233. )
  234. .await;
  235. assert_eq!(String::from_utf8(response).unwrap(), "OK");
  236. // Time passes...
  237. advance_days(&net_test, 1).await;
  238. // Migrate again
  239. println!("Migrating to a new bucket");
  240. let migration_cred = check_blockage(&net, &cred, get_lox_pub(&la_pubkeys))
  241. .await
  242. .unwrap();
  243. cred = blockage_migration(
  244. &net,
  245. &cred,
  246. &migration_cred,
  247. get_lox_pub(&la_pubkeys),
  248. get_migration_pub(&la_pubkeys),
  249. )
  250. .await
  251. .unwrap();
  252. assert_eq!(scalar_u32(&cred.trust_level).unwrap(), 1);
  253. // Level up to level 2
  254. cred = test_level_up(&net, &net_test, &cred, &la_pubkeys).await;
  255. // Can't level up to level 3
  256. assert!(!eligible_for_level_up(&net, &cred).await);
  257. }