Explorar o código

Begin client using hyper to work with onyinyang's server

Vecna hai 1 ano
pai
achega
589b2cc7f7
Modificáronse 4 ficheiros con 160 adicións e 1 borrados
  1. 5 1
      Cargo.toml
  2. 65 0
      src/bin/lox_client_2.rs
  3. 65 0
      src/client_lib.rs
  4. 25 0
      src/hyper_client_net.rs

+ 5 - 1
Cargo.toml

@@ -6,10 +6,14 @@ edition = "2021"
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
 
 [dependencies]
-lox = { git = "https://git-crysp.uwaterloo.ca/iang/lox.git", branch = "vvecna/lox_test" }
+#lox = { git = "https://git-crysp.uwaterloo.ca/iang/lox.git", branch = "vvecna/lox_test" }
+lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git" }
 ed25519-dalek = { version = "1", features = ["serde"] }
 serde = "1"
 bincode = "1"
 serde_json = "1.0"
+serde_with = "1.9.1"
+time = "0.2"
 # TODO: reduce feature set to just the ones needed
 tokio = { version = "1.20", features = ["full"] }
+hyper = { version = "0.14", features = ["full"] }

+ 65 - 0
src/bin/lox_client_2.rs

@@ -0,0 +1,65 @@
+// During a later cleanup, this file will replace lox_client.rs.
+
+// This seems like probably not the best way to do this, but it works.
+#[path = "../client_lib.rs"]
+mod client_lib;
+use client_lib::*;
+
+use lox::IssuerPubKey;
+use std::env::args;
+use std::fs::File;
+use std::io::Write;
+use std::path::Path;
+
+#[tokio::main]
+async fn main() {
+    // TODO: Do proper argument handling
+    let server_addr = args().nth(1).unwrap(); // must include http://
+
+
+    // Get Lox Authority public keys
+    // TODO: Make this filename configurable
+    let lox_auth_pubkeys_filename = "lox_auth_pubkeys.json";
+
+    let lox_auth_pubkeys: Vec<IssuerPubKey> = if Path::new(lox_auth_pubkeys_filename).exists() {
+        // read in file
+        let lox_auth_pubkeys_infile = File::open(lox_auth_pubkeys_filename).unwrap();
+        serde_json::from_reader(lox_auth_pubkeys_infile).unwrap()
+    } else {
+        // download from Lox Auth
+        let pubkeys = get_lox_auth_keys(server_addr.clone()).await;
+        // save to file for next time
+        let mut lox_auth_pubkeys_outfile = File::create(lox_auth_pubkeys_filename).expect("Failed to create lox_auth pubkeys file");
+        write!(
+            lox_auth_pubkeys_outfile,
+            "{}",
+            serde_json::to_string(&pubkeys).unwrap()
+        ).expect("Failed to write to lox_auth pubkeys file");
+        pubkeys
+    };
+    let lox_pub = lox_auth_pubkeys[0].clone();
+    let migration_pub = lox_auth_pubkeys[1].clone();
+    let migrationkey_pub = lox_auth_pubkeys[2].clone();
+    let reachability_pub = lox_auth_pubkeys[3].clone();
+    let invitation_pub = lox_auth_pubkeys[4].clone();
+
+    // Get Lox Credential
+    // TODO: Make this filename configurable
+    let lox_cred_filename = "lox_cred.json";
+    let lox_cred = if Path::new(lox_cred_filename).exists() {
+        let lox_cred_infile = File::open(lox_cred_filename).unwrap();
+        serde_json::from_reader(lox_cred_infile).unwrap()
+    } else {
+        // get new credential based on an open invite
+        let open_invite = get_open_invitation(server_addr.clone()).await;
+        let cred = get_lox_credential(server_addr.clone(), open_invite, lox_pub).await;
+        // save to file for next time
+        let mut lox_cred_outfile = File::create(lox_cred_filename).expect("Failed to create lox credential file");
+        write!(
+            lox_cred_outfile,
+            "{}",
+            serde_json::to_string(&cred).unwrap()
+        ).expect("Failed to write to lox credential file");
+        cred
+    };
+}

+ 65 - 0
src/client_lib.rs

@@ -0,0 +1,65 @@
+mod hyper_client_net;
+use hyper_client_net::net_request;
+
+use lox::IssuerPubKey;
+use lox::OPENINV_LENGTH;
+use lox::proto::*;
+use serde::{Serialize, Deserialize};
+use serde_with::serde_as;
+use std::time::Duration;
+
+// From https://gitlab.torproject.org/onyinyang/lox-server/-/blob/main/src/main.rs
+// TODO: Move this to main Lox library?
+#[serde_as]
+#[derive(Serialize, Deserialize)]
+pub struct Invite {
+    #[serde_as(as = "[_; OPENINV_LENGTH]")]
+    invite: [u8; OPENINV_LENGTH],
+}
+
+/// 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()
+}
+
+// Download Lox Auth pubkeys
+pub async fn get_lox_auth_keys(server_addr: String) -> Vec<IssuerPubKey> {
+    let lox_auth_pubkeys_resp = net_request(format!("{}/pubkeys", server_addr), [].to_vec()).await;
+    let lox_auth_pubkeys: Vec<IssuerPubKey> = serde_json::from_slice(&lox_auth_pubkeys_resp).unwrap();
+    lox_auth_pubkeys
+}
+
+// Get an open invitation
+pub async fn get_open_invitation(server_addr: String) -> [u8; OPENINV_LENGTH] {
+    let open_invite_resp = net_request(format!("{}/invite", server_addr), [].to_vec()).await;
+    let open_invite: [u8; OPENINV_LENGTH]  = serde_json::from_slice::<Invite>(&open_invite_resp).unwrap().invite;
+    open_invite
+}
+
+// Get a Lox Credential from an open invitation
+pub async fn get_lox_credential(server_addr: String, open_invite: [u8; OPENINV_LENGTH], lox_pub: IssuerPubKey) -> lox::cred::Lox {
+    let (open_inv_req, state) = open_invite::request(&open_invite);
+    let encoded_open_inv_req: Vec<u8> = serde_json::to_vec(&open_inv_req).unwrap();
+    let encoded_open_inv_resp = net_request(format!("{}/openreq", server_addr), encoded_open_inv_req).await;
+    let decoded_open_inv_resp: open_invite::Response = serde_json::from_slice(&encoded_open_inv_resp).unwrap();
+    let (cred, bridgeline) = open_invite::handle_response(state, decoded_open_inv_resp, &lox_pub).unwrap();
+    cred
+    // TODO: Also return the bridgeline
+}
+
+// Get a migration credential to migrate to higher trust
+pub async fn trust_promotion(server_addr: String, lox_cred: lox::cred::Lox, lox_pub: IssuerPubKey) -> lox::cred::Migration {
+    let (prom_req, state) = trust_promotion::request(&lox_cred, &lox_pub, today(Duration::ZERO)).unwrap();
+    let encoded_prom_req: Vec<u8> = serde_json::to_vec(&prom_req).unwrap();
+    let encoded_prom_resp = net_request(format!("{}/promreq", server_addr), encoded_prom_req).await;
+    let decoded_prom_resp: trust_promotion::Response = serde_json::from_slice(&encoded_prom_resp).unwrap();
+    let migration_cred = trust_promotion::handle_response(state, decoded_prom_resp).unwrap();
+    migration_cred
+}

+ 25 - 0
src/hyper_client_net.rs

@@ -0,0 +1,25 @@
+// This file provides networking using hyper (which
+// https://gitlab.torproject.org/onyinyang/lox-server uses).
+// During a later cleanup, this will replace client_net.rs.
+
+use hyper::{Body, Client, Method, Request};
+
+pub async fn net_request(url: String, body: Vec<u8>) -> Vec<u8> {
+    let client = Client::new();
+
+    let uri = url.parse().expect("Failed to parse URL");
+
+    let resp = if body.len() > 0 {
+        // make a POST with a body
+        let req = Request::builder().method(Method::POST).uri(uri).body(Body::from(body)).expect("Failed to create POST request");
+        client.request(req).await.expect("Failed to POST")
+    } else {
+        // make a GET request
+        client.get(uri).await.expect("Failed to GET")
+    };
+
+    println!("Response: {}", resp.status());
+
+    let buf = hyper::body::to_bytes(resp).await.expect("Failed to concat bytes");
+    buf.to_vec()
+}