tests.rs 9.0 KB

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