tests.rs 9.3 KB

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