Bläddra i källkod

Get today from lox-distributor; add days function (for testing)

Vecna 8 månader sedan
förälder
incheckning
59e6c3b066
3 ändrade filer med 143 tillägg och 108 borttagningar
  1. 2 1
      Cargo.toml
  2. 94 84
      src/client_lib.rs
  3. 47 23
      src/main.rs

+ 2 - 1
Cargo.toml

@@ -7,7 +7,8 @@ edition = "2021"
 
 [dependencies]
 #lox = { git = "https://git-crysp.uwaterloo.ca/iang/lox.git", branch = "vvecna/lox_test" }
-lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git" }
+lox-library = { git = "https://gitlab.torproject.org/tpo/anti-censorship/lox-rs.git", version = "0.1.0" }
+lox_utils = { git = "https://gitlab.torproject.org/tpo/anti-censorship/lox-rs.git", version = "0.1.0" }
 curve25519-dalek = { package = "curve25519-dalek-ng", version = "3", default-features = false, features = ["serde", "std"] }
 ed25519-dalek = { version = "1", features = ["serde"] }
 getopts = "0.2"

+ 94 - 84
src/client_lib.rs

@@ -1,12 +1,15 @@
 use async_trait::async_trait;
 use curve25519_dalek::scalar::Scalar;
-use lox::bridge_table::BridgeLine;
-use lox::bridge_table::ENC_BUCKET_BYTES;
-use lox::proto::*;
-use lox::IssuerPubKey;
-use lox::OPENINV_LENGTH;
+use lox_library::bridge_table::BridgeLine;
+use lox_library::bridge_table::EncryptedBucket;
+use lox_library::proto::*;
+use lox_library::scalar_u32;
+use lox_library::IssuerPubKey;
+use lox_library::OPENINV_LENGTH;
+use lox_utils::EncBridgeTable;
 use serde::{Deserialize, Serialize};
 use serde_with::serde_as;
+use std::collections::HashMap;
 use std::time::Duration;
 
 // used for testing function
@@ -26,42 +29,6 @@ pub struct Invite {
     #[serde_as(as = "[_; OPENINV_LENGTH]")]
     invite: [u8; OPENINV_LENGTH],
 }
-#[serde_as]
-#[derive(Serialize, Deserialize)]
-pub struct EncBridgeTable {
-    #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")]
-    etable: Vec<[u8; ENC_BUCKET_BYTES]>,
-}
-
-// These two functions should only be used for testing.
-// This file should probably belong to the client, not the library.
-const TIME_OFFSET_FILENAME: &str = "time_offset.json";
-fn get_time_offset() -> u32 {
-    if std::path::Path::new(&TIME_OFFSET_FILENAME).exists() {
-        let infile = std::fs::File::open(&TIME_OFFSET_FILENAME).unwrap();
-        serde_json::from_reader(infile).unwrap()
-    } else {
-        0
-    }
-}
-fn save_time_offset(secs: &u32) {
-    let mut outfile =
-        std::fs::File::create(&TIME_OFFSET_FILENAME).expect("Failed to create time_offset");
-    write!(outfile, "{}", serde_json::to_string(&secs).unwrap())
-        .expect("Failed to write to time_offset");
-}
-
-/// Get today's (real or simulated) date
-///
-/// This function is modified from the lox lib.rs
-fn today(time_offset: Duration) -> u32 {
-    // We will not encounter negative Julian dates (~6700 years ago)
-    // or ones larger than 32 bits
-    (time::OffsetDateTime::now_utc().date() + time_offset)
-        .julian_day()
-        .try_into()
-        .unwrap()
-}
 
 // Helper functions to get public keys from vector
 pub fn get_lox_pub(lox_auth_pubkeys: &Vec<IssuerPubKey>) -> &IssuerPubKey {
@@ -86,7 +53,7 @@ pub fn get_invitation_pub(lox_auth_pubkeys: &Vec<IssuerPubKey>) -> &IssuerPubKey
 
 // Helper function to get credential trust level as i8
 // (Note that this value should only be 0-4)
-pub fn get_cred_trust_level(cred: &lox::cred::Lox) -> i8 {
+pub fn get_cred_trust_level(cred: &lox_library::cred::Lox) -> i8 {
     let trust_levels: [Scalar; 5] = [
         Scalar::zero(),
         Scalar::one(),
@@ -102,6 +69,41 @@ pub fn get_cred_trust_level(cred: &lox::cred::Lox) -> i8 {
     -1
 }
 
+// Helper function to check if credential is eligible for
+// promotion from level 0 to 1
+pub async fn eligible_for_trust_promotion(
+    net: &dyn Networking,
+    cred: &lox_library::cred::Lox,
+) -> bool {
+    let level_since: u32 = match scalar_u32(&cred.level_since) {
+        Some(v) => v,
+        None => return false,
+    };
+    get_cred_trust_level(cred) == 0
+        && level_since + lox_library::proto::trust_promotion::UNTRUSTED_INTERVAL
+            <= get_today(net).await
+}
+
+// Helper function to check if credential is eligible for
+// level up from level 1+
+pub async fn eligible_for_level_up(net: &dyn Networking, cred: &lox_library::cred::Lox) -> bool {
+    let level_since: u32 = match scalar_u32(&cred.level_since) {
+        Some(v) => v,
+        None => return false,
+    };
+    let trust_level: usize = get_cred_trust_level(cred).try_into().unwrap();
+    trust_level > 0
+        && level_since + lox_library::proto::level_up::LEVEL_INTERVAL[trust_level]
+            <= get_today(net).await
+}
+
+// Get current date from Lox Auth
+pub async fn get_today(net: &dyn Networking) -> u32 {
+    let resp = net.request("/today".to_string(), [].to_vec()).await;
+    let today: u32 = serde_json::from_slice(&resp).unwrap();
+    today
+}
+
 // Download Lox Auth pubkeys
 pub async fn get_lox_auth_keys(net: &dyn Networking) -> Vec<IssuerPubKey> {
     let resp = net.request("/pubkeys".to_string(), [].to_vec()).await;
@@ -110,7 +112,7 @@ pub async fn get_lox_auth_keys(net: &dyn Networking) -> Vec<IssuerPubKey> {
 }
 
 // Get encrypted bridge table
-pub async fn get_reachability_credential(net: &dyn Networking) -> Vec<[u8; ENC_BUCKET_BYTES]> {
+pub async fn get_reachability_credential(net: &dyn Networking) -> HashMap<u32, EncryptedBucket> {
     let resp = net.request("/reachability".to_string(), [].to_vec()).await;
     let reachability_cred: EncBridgeTable = serde_json::from_slice(&resp).unwrap();
     reachability_cred.etable
@@ -128,7 +130,7 @@ pub async fn get_lox_credential(
     net: &dyn Networking,
     open_invite: &[u8; OPENINV_LENGTH],
     lox_pub: &IssuerPubKey,
-) -> (lox::cred::Lox, BridgeLine) {
+) -> (lox_library::cred::Lox, BridgeLine) {
     let (req, state) = open_invite::request(&open_invite);
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
     let encoded_resp = net.request("/openreq".to_string(), encoded_req).await;
@@ -140,16 +142,10 @@ pub async fn get_lox_credential(
 // Get a migration credential to migrate to higher trust
 pub async fn trust_promotion(
     net: &dyn Networking,
-    lox_cred: &lox::cred::Lox,
+    lox_cred: &lox_library::cred::Lox,
     lox_pub: &IssuerPubKey,
-) -> lox::cred::Migration {
-    // FOR TESTING ONLY
-    let time_offset = get_time_offset() + 60 * 60 * 24 * 31;
-    save_time_offset(&time_offset);
-
-    let (req, state) =
-//        trust_promotion::request(&lox_cred, &lox_pub, today(Duration::ZERO)).unwrap();
-        trust_promotion::request(&lox_cred, &lox_pub, today(Duration::from_secs(time_offset.into()))).unwrap(); // FOR TESTING ONLY
+) -> lox_library::cred::Migration {
+    let (req, state) = trust_promotion::request(&lox_cred, &lox_pub, get_today(net).await).unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
     let encoded_resp = net.request("/trustpromo".to_string(), encoded_req).await;
     let decoded_resp: trust_promotion::Response = serde_json::from_slice(&encoded_resp).unwrap();
@@ -160,11 +156,11 @@ pub async fn trust_promotion(
 // Promote from untrusted (trust level 0) to trusted (trust level 1)
 pub async fn trust_migration(
     net: &dyn Networking,
-    lox_cred: &lox::cred::Lox,
-    migration_cred: &lox::cred::Migration,
+    lox_cred: &lox_library::cred::Lox,
+    migration_cred: &lox_library::cred::Migration,
     lox_pub: &IssuerPubKey,
     migration_pub: &IssuerPubKey,
-) -> lox::cred::Lox {
+) -> lox_library::cred::Lox {
     let (req, state) =
         migration::request(lox_cred, migration_cred, lox_pub, migration_pub).unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
@@ -177,23 +173,22 @@ pub async fn trust_migration(
 // Increase trust from at least level 1 to higher levels
 pub async fn level_up(
     net: &dyn Networking,
-    lox_cred: &lox::cred::Lox,
-    encbuckets: &Vec<[u8; ENC_BUCKET_BYTES]>,
+    lox_cred: &lox_library::cred::Lox,
+    encbuckets: &HashMap<u32, EncryptedBucket>,
     lox_pub: &IssuerPubKey,
     reachability_pub: &IssuerPubKey,
-) -> lox::cred::Lox {
+) -> lox_library::cred::Lox {
     // Read the bucket in the credential to get today's Bucket
     // Reachability credential
-
-    let (id, key) = lox::bridge_table::from_scalar(lox_cred.bucket).unwrap();
-    let bucket =
-        lox::bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
+    let (id, key) = lox_library::bridge_table::from_scalar(lox_cred.bucket).unwrap();
+    let bucket = lox_library::bridge_table::BridgeTable::decrypt_bucket(
+        id,
+        &key,
+        &encbuckets.get(&id).unwrap(),
+    )
+    .unwrap();
     let reachcred = bucket.1.unwrap();
 
-    // FOR TESTING ONLY
-    let time_offset = get_time_offset() + 60 * 60 * 24 * 85;
-    save_time_offset(&time_offset);
-
     // Use the Bucket Reachability credential to advance to the next
     // level
     let (req, state) = level_up::request(
@@ -201,8 +196,7 @@ pub async fn level_up(
         &reachcred,
         lox_pub,
         reachability_pub,
-        //today(Duration::ZERO),
-        today(Duration::from_secs(time_offset.into())), // FOR TESTING ONLY
+        get_today(net).await,
     )
     .unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
@@ -215,18 +209,22 @@ pub async fn level_up(
 // Request an Invitation credential to give to a friend
 pub async fn issue_invite(
     net: &dyn Networking,
-    lox_cred: &lox::cred::Lox,
-    encbuckets: &Vec<[u8; ENC_BUCKET_BYTES]>,
+    lox_cred: &lox_library::cred::Lox,
+    encbuckets: &HashMap<u32, EncryptedBucket>,
     lox_pub: &IssuerPubKey,
     reachability_pub: &IssuerPubKey,
     invitation_pub: &IssuerPubKey,
-) -> (lox::cred::Lox, lox::cred::Invitation) {
+) -> (lox_library::cred::Lox, lox_library::cred::Invitation) {
     // Read the bucket in the credential to get today's Bucket
     // Reachability credential
 
-    let (id, key) = lox::bridge_table::from_scalar(lox_cred.bucket).unwrap();
-    let bucket =
-        lox::bridge_table::BridgeTable::decrypt_bucket(id, &key, &encbuckets[id as usize]).unwrap();
+    let (id, key) = lox_library::bridge_table::from_scalar(lox_cred.bucket).unwrap();
+    let bucket = lox_library::bridge_table::BridgeTable::decrypt_bucket(
+        id,
+        &key,
+        &encbuckets.get(&id).unwrap(),
+    )
+    .unwrap();
     let reachcred = bucket.1.unwrap();
 
     let (req, state) = issue_invite::request(
@@ -234,7 +232,7 @@ pub async fn issue_invite(
         &reachcred,
         lox_pub,
         reachability_pub,
-        today(Duration::ZERO),
+        get_today(net).await,
     )
     .unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
@@ -248,12 +246,12 @@ pub async fn issue_invite(
 // Redeem an Invitation credential to start at trust level 1
 pub async fn redeem_invite(
     net: &dyn Networking,
-    invite: &lox::cred::Invitation,
+    invite: &lox_library::cred::Invitation,
     lox_pub: &IssuerPubKey,
     invitation_pub: &IssuerPubKey,
-) -> lox::cred::Lox {
+) -> lox_library::cred::Lox {
     let (req, state) =
-        redeem_invite::request(invite, invitation_pub, today(Duration::ZERO)).unwrap();
+        redeem_invite::request(invite, invitation_pub, get_today(net).await).unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
     let encoded_resp = net.request("/redeem".to_string(), encoded_req).await;
     let decoded_resp: redeem_invite::Response = serde_json::from_slice(&encoded_resp).unwrap();
@@ -264,9 +262,9 @@ pub async fn redeem_invite(
 // Check for a migration credential to move to a new bucket
 pub async fn check_blockage(
     net: &dyn Networking,
-    lox_cred: &lox::cred::Lox,
+    lox_cred: &lox_library::cred::Lox,
     lox_pub: &IssuerPubKey,
-) -> lox::cred::Migration {
+) -> lox_library::cred::Migration {
     let (req, state) = check_blockage::request(lox_cred, lox_pub).unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
     let encoded_resp = net.request("/checkblockage".to_string(), encoded_req).await;
@@ -278,11 +276,11 @@ pub async fn check_blockage(
 // Migrate to a new bucket (must be level >= 3)
 pub async fn blockage_migration(
     net: &dyn Networking,
-    lox_cred: &lox::cred::Lox,
-    migcred: &lox::cred::Migration,
+    lox_cred: &lox_library::cred::Lox,
+    migcred: &lox_library::cred::Migration,
     lox_pub: &IssuerPubKey,
     migration_pub: &IssuerPubKey,
-) -> lox::cred::Lox {
+) -> lox_library::cred::Lox {
     let (req, state) =
         blockage_migration::request(lox_cred, migcred, lox_pub, migration_pub).unwrap();
     let encoded_req: Vec<u8> = serde_json::to_vec(&req).unwrap();
@@ -293,3 +291,15 @@ pub async fn blockage_migration(
     let cred = blockage_migration::handle_response(state, decoded_resp, lox_pub).unwrap();
     cred
 }
+
+// Advance days on server (ONLY FOR TESTING)
+pub async fn advance_days(net: &dyn Networking, days: u16) -> u32 {
+    let resp = net
+        .request(
+            "/advancedays".to_string(),
+            serde_json::to_vec(&days).unwrap(),
+        )
+        .await;
+    let today: u32 = serde_json::from_slice(&resp).unwrap();
+    today
+}

+ 47 - 23
src/main.rs

@@ -6,13 +6,14 @@ use client_net::HyperNet;
 
 use curve25519_dalek::scalar::Scalar;
 use getopts::Options;
-use lox::bridge_table::BridgeLine;
-use lox::IssuerPubKey;
+use lox_library::bridge_table::BridgeLine;
+use lox_library::IssuerPubKey;
 use serde::Serialize;
 use std::env::args;
 use std::fs::File;
 use std::io::Write;
 use std::path::Path;
+use std::str::FromStr;
 
 // Prints the argument details for this program
 fn print_usage(program: &str, opts: Options) {
@@ -33,6 +34,13 @@ async fn main() {
 
     let mut opts = Options::new();
     opts.optflag("h", "help", "print this help menu");
+    //#[cfg(test)]
+    opts.optopt(
+        "A",
+        "advance-days",
+        "increase server days by NUM_DAYS",
+        "NUM_DAYS",
+    );
     opts.optflag("L", "level-up", "increase trust level");
     opts.optflag("N", "new-lox-cred", "get a new Lox Credential");
     opts.optopt(
@@ -64,6 +72,14 @@ async fn main() {
         }
     };
 
+    // Advance days on server (TESTING ONLY)
+    //#[cfg(test)]
+    if matches.opt_present("A") {
+        let days: u16 = u16::from_str(matches.opt_str("A").unwrap().as_str()).unwrap();
+        let today: u32 = advance_days(&net, days).await;
+        println!("Today's date according to the server: {}", today);
+    }
+
     // Get Lox Authority public keys
     // TODO: Make this filename configurable
     let lox_auth_pubkeys_filename = "lox_auth_pubkeys.json";
@@ -108,28 +124,36 @@ async fn main() {
 
         // If trust level is 0, do trust promotion, otherwise level up.
         let cred = if old_level == 0 {
-            let migration_cred =
-                trust_promotion(&net, &lox_cred, get_lox_pub(&lox_auth_pubkeys)).await;
-            let cred = trust_migration(
-                &net,
-                &lox_cred,
-                &migration_cred,
-                get_lox_pub(&lox_auth_pubkeys),
-                get_migration_pub(&lox_auth_pubkeys),
-            )
-            .await;
-            cred
+            if eligible_for_trust_promotion(&net, &lox_cred).await {
+                let migration_cred =
+                    trust_promotion(&net, &lox_cred, get_lox_pub(&lox_auth_pubkeys)).await;
+                let cred = trust_migration(
+                    &net,
+                    &lox_cred,
+                    &migration_cred,
+                    get_lox_pub(&lox_auth_pubkeys),
+                    get_migration_pub(&lox_auth_pubkeys),
+                )
+                .await;
+                cred
+            } else {
+                lox_cred
+            }
         } else {
-            let encbuckets = get_reachability_credential(&net).await;
-            let cred = level_up(
-                &net,
-                &lox_cred,
-                &encbuckets,
-                get_lox_pub(&lox_auth_pubkeys),
-                get_reachability_pub(&lox_auth_pubkeys),
-            )
-            .await;
-            cred
+            if eligible_for_level_up(&net, &lox_cred).await {
+                let encbuckets = get_reachability_credential(&net).await;
+                let cred = level_up(
+                    &net,
+                    &lox_cred,
+                    &encbuckets,
+                    get_lox_pub(&lox_auth_pubkeys),
+                    get_reachability_pub(&lox_auth_pubkeys),
+                )
+                .await;
+                cred
+            } else {
+                lox_cred
+            }
         };
         save_object(&cred, &lox_cred_filename);
         let new_level = get_cred_trust_level(&cred);