diff --git a/crates/lox-wasm/.gitignore b/crates/lox-wasm/.gitignore new file mode 100644 index 0000000..fbd7c91 --- /dev/null +++ b/crates/lox-wasm/.gitignore @@ -0,0 +1,2 @@ +target/* +Cargo.lock diff --git a/crates/lox-wasm/Cargo.toml b/crates/lox-wasm/Cargo.toml new file mode 100644 index 0000000..e5712e5 --- /dev/null +++ b/crates/lox-wasm/Cargo.toml @@ -0,0 +1,30 @@ +[package] +name = "lox-wasm" +authors = ["Cecylia Bocovich "] +version = "0.1.0" +edition = "2021" +description = "WASM bindings for lox" +license = "MIT" + +[lib] +crate-type = ["cdylib"] + +[dependencies] +julianday = "1.2.0" +lazy_static = "1.4.0" +lox = { git = "https://gitlab.torproject.org/onyinyang/lox.git", branch = "master" } +wasm-bindgen = "0.2" +time = "0.2" +serde_json = "1.0.87" +serde = "1" +serde_with = "1.9.1" +serde-wasm-bindgen = "0.4.5" + +console_error_panic_hook = "0.1.7" +js-sys = "0.3.61" +rand = { version = "0.7", features = ["wasm-bindgen"] } +zkp = "0.8.0" + +[dependencies.chrono] +version = "0.4.19" +features = ["serde", "wasmbind"] diff --git a/crates/lox-wasm/LICENSE b/crates/lox-wasm/LICENSE new file mode 100644 index 0000000..ca549f7 --- /dev/null +++ b/crates/lox-wasm/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2022 Cecylia Bocovich + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/crates/lox-wasm/README.md b/crates/lox-wasm/README.md new file mode 100644 index 0000000..3f0ffb7 --- /dev/null +++ b/crates/lox-wasm/README.md @@ -0,0 +1,26 @@ +# lox-wasm + +wasm bindings for the lox crate: https://git-crysp.uwaterloo.ca/iang/lox + +# Dependencies + +``` +cargo install wasm-pack +``` + +# Build + +``` +wasm-pack build --target web +``` + +# Testing + +The provided `index.html` file can be used for testing the lox bindings. First, follow the instructions to [run a lox server](https://gitlab.torproject.org/cohosh/lox-server). + +Then, spin up a simple local webserver in the current directory: +``` +python3 -m http.server 8000 +``` + +Next, open the dev console in your browser and navigate to `http://localhost:8000`. diff --git a/crates/lox-wasm/index.html b/crates/lox-wasm/index.html new file mode 100644 index 0000000..4c7c7e2 --- /dev/null +++ b/crates/lox-wasm/index.html @@ -0,0 +1,11 @@ + + + + + Lox binding test + + + + + + diff --git a/crates/lox-wasm/index.js b/crates/lox-wasm/index.js new file mode 100644 index 0000000..ad303ca --- /dev/null +++ b/crates/lox-wasm/index.js @@ -0,0 +1,241 @@ +import init, { + open_invite, + handle_new_lox_credential, + trust_promotion, + handle_trust_promotion, + trust_migration, + handle_trust_migration, + level_up, + handle_level_up, + issue_invite, + handle_issue_invite, + prepare_invite, + redeem_invite, + handle_redeem_invite, + check_blockage, + handle_check_blockage, + blockage_migration, + handle_blockage_migration, + set_panic_hook } from "./pkg/lox_wasm.js"; +let pubkeys = await simple_request("/pubkeys"); +console.log("Got pubkeys: " + pubkeys); + +// Get Lox Invitation +let requested_invite = await init().then(() => { + set_panic_hook(); + let requested_invite = request_open_invite().then((token) => { + return open_invite(token); + }); + return requested_invite; +}); +console.log("Got request and state: "+requested_invite); + +// Redeem Lox Invitation for an Open Invitation Lox Credential +// Trust Level 0 +let open_lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/openreq", requested_invite).then((response) => { + console.log("Got new Level 0 Lox Credential: " + response); + return handle_new_lox_credential(requested_invite, response, pubkeys); + }); + return cred; +}); + +let requested_trust_promo = trust_promotion(open_lox_cred, pubkeys); + +// Get Migration credential for Trust Promotion from Trust Level 0 -> 1 +let trust_promo_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/trustpromo", requested_trust_promo).then((response)=> { + console.log("Got Migration Credential for Trust Promotion: " + response); + return handle_trust_promotion(requested_trust_promo, response); + }); + return cred; + }); + + +let requested_trust_migration = trust_migration(open_lox_cred, trust_promo_cred, pubkeys); + +// Trust Promotion from Trust Level 0 -> 1 +let lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/trustmig", requested_trust_migration).then((response)=> { + console.log("Got new Level 1 Lox Credential: " + response); + return handle_trust_migration(requested_trust_migration, response, pubkeys); + }); + return cred; + }); + +let encrypted_table = await simple_request("/reachability"); +console.log("Got Encrypted Table: " + encrypted_table); +let requested_level_two = level_up(lox_cred, encrypted_table, pubkeys); + +// Level Up to Trust Level 2 +lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/levelup", requested_level_two).then((response)=> { + console.log("Got new Level 2 Lox Credential: " + response); + return handle_level_up(requested_level_two, response, pubkeys); + }); + return cred; + }); + +// Update reachability cred + encrypted_table = await simple_request("/reachability"); + console.log("Got Encrypted Table: " + encrypted_table); + let requested_level_three = level_up(lox_cred, encrypted_table, pubkeys); + +// Level Up to Trust Level 3 + lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/levelup", requested_level_three).then((response)=> { + console.log("Got new Level 3 Lox Credential: " + response); + return handle_level_up(requested_level_three, response, pubkeys); + }); + return cred; + }); + + +// Update reachability cred +encrypted_table = await simple_request("/reachability"); +console.log("Got Encrypted Table: " + encrypted_table); +let requested_level_four = level_up(lox_cred, encrypted_table, pubkeys); + +// Level Up to Trust Level 4 +lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/levelup", requested_level_four).then((response)=> { + console.log("Got new Level 4 Lox Credential: " + response); + return handle_level_up(requested_level_four, response, pubkeys); + }); + return cred; + }); + +// Update reachability cred +encrypted_table = await simple_request("/reachability"); +console.log("Got Encrypted Table: " + encrypted_table); +let requested_issue_invitation = issue_invite(lox_cred, encrypted_table, pubkeys); + +// Issue an Invitation cred +lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/issueinvite", requested_issue_invitation).then((response)=> { + console.log("Got new Invite and Lox Credential: " + response); + return handle_issue_invite(requested_issue_invitation, response, pubkeys); + }); + return cred; + }); + +let prepared_invitation = prepare_invite(lox_cred); +// Trusted Invitation Request +let requested_invitation = redeem_invite(prepared_invitation, pubkeys); +// Redeem an Invitation cred +let lox_cred_from_invite = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/redeem", requested_invitation).then((response)=> { + console.log("Got new Trusted Lox Credential Invite: " + response); + return handle_redeem_invite(requested_invitation, response, pubkeys); + }); + return cred; + }); + + let requested_check_blockage = check_blockage(lox_cred, pubkeys); + + // Check whether or not a bucket is blocked + let check_migration_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/checkblockage", requested_check_blockage).then((response)=> { + console.log("Got check blockage Migration Credential: " + response); + return handle_check_blockage(requested_check_blockage, response); + }); + return cred; + }); + +let requested_blockage_migration = blockage_migration(lox_cred, check_migration_cred, pubkeys); + + // Migrate to a new unblocked bridge + lox_cred = await init().then(() => { + set_panic_hook(); + let cred = requested_cred("/blockagemigration", requested_blockage_migration).then((response)=> { + console.log("Got Lox Credential for new bucket: " + response); + return handle_blockage_migration(requested_blockage_migration, response, pubkeys); + }); + return cred; + }); + + +function requested_cred(command, requested) { + return new Promise((fulfill, reject) => { + let req = JSON.parse(requested); + loxServerPostRequest(command, req.request).then((response) => { + fulfill(JSON.stringify(response)); + return; + }).catch(() => { + console.log("Error requesting new Lox credential from server"); + reject(); + }); + }); +} + +function request_open_invite() { + return new Promise((fulfill, reject) => { + loxServerPostRequest("/invite", null).then((response) => { + console.log("Got invitation token: " + response.invite); + fulfill(response.invite); + return; + }).catch(() => { + console.log("Error requesting open invite from Lox server"); + reject(); + }); + }); +} + +function simple_request(requested) { + return new Promise((fulfill, reject) => { + loxServerPostRequest(requested, null).then((response) => { + fulfill(JSON.stringify(response)); + return; + }).catch(() => { + console.log("Error making simple request: " + requested); + reject(); + }); + }); +} + +function loxServerPostRequest(data, payload) { + return new Promise((fulfill, reject) => { + const xhr = new XMLHttpRequest(); + xhr.onreadystatechange = function() { + if (xhr.DONE !== xhr.readyState) { + return; + } + if (xhr.status !== 200) { + console.log("Error. Status code: "+xhr.status); + console.log(xhr); + reject(); + return; + } + const response = JSON.parse(xhr.responseText); + fulfill(response); + return; + }; + try { + xhr.open('POST', "http://localhost:8001"+data, true) + xhr.setRequestHeader("Content-Type", "application/json"); + } catch (err) { + console.log("Error connecting to lox bridge db"); + reject(); + return; + } + xhr.send(JSON.stringify(payload)); + }); +} + +// The correct key should be matched against a public commit to the key to +// verify that the key issuer is in fact the correct Bridge Authority +function loxKeyRequest(key_type) { + return new Promise((fulfull, reject) => { + + + }) +} diff --git a/crates/lox-wasm/src/lib.rs b/crates/lox-wasm/src/lib.rs new file mode 100644 index 0000000..7db3092 --- /dev/null +++ b/crates/lox-wasm/src/lib.rs @@ -0,0 +1,629 @@ +use chrono::{Duration, Utc}; +use julianday::JulianDay; +use lox::bridge_table::{BridgeLine,from_scalar,BridgeTable, ENC_BUCKET_BYTES}; +use lox::cred::{BucketReachability, Invitation, Lox, Migration}; +use lox::proto::{open_invite, trust_promotion, migration, level_up, + issue_invite, redeem_invite, check_blockage, blockage_migration}; +use lox::{IssuerPubKey, OPENINV_LENGTH, scalar_u32}; +use serde::{Deserialize, Serialize}; +use serde_with::{serde_as}; +use std::array::TryFromSliceError; +use std::{panic}; +use wasm_bindgen::prelude::*; +use zkp::ProofError; + + +#[derive(Deserialize, Serialize)] +struct OpenReqState { + request: open_invite::Request, + state: open_invite::State, +} + +#[derive(Deserialize, Serialize)] +struct TrustReqState { + request: trust_promotion::Request, + state: trust_promotion::State, +} + +#[derive(Deserialize, Serialize)] +struct MigReqState { + request: migration::Request, + state: migration::State, +} + +#[derive(Deserialize, Serialize)] +struct LevelupReqState { + request: level_up::Request, + state: level_up::State, +} + +#[derive(Deserialize, Serialize)] +struct IssueInviteReqState { + request: issue_invite::Request, + state: issue_invite::State, +} + +#[derive(Deserialize, Serialize)] +struct RedeemReqState { + request: redeem_invite::Request, + state: redeem_invite::State, +} + +#[derive(Deserialize, Serialize)] +struct CheckBlockageReqState { + request: check_blockage::Request, + state: check_blockage::State, +} + +#[derive(Deserialize, Serialize)] +struct BlockageMigReqState { + request: blockage_migration::Request, + state: blockage_migration::State, +} + + + +#[derive(Debug, Deserialize, Serialize)] +struct PubKeys { + lox_pub: IssuerPubKey, + migration_pub: IssuerPubKey, + migrationkey_pub: IssuerPubKey, + reachability_pub: IssuerPubKey, + invitation_pub: IssuerPubKey, +} + +#[serde_as] +#[derive(Serialize, Deserialize)] +pub struct EncBridgeTable { + #[serde_as(as = "Vec<[_; ENC_BUCKET_BYTES]>")] + pub etable: Vec<[u8; ENC_BUCKET_BYTES]>, +} + +#[derive(Debug, Deserialize, Serialize)] +struct LoxCredential { + lox_credential: Lox, + bridgeline: Option, + invitation: Option, +} + +fn today() -> u32 { + let naive_now = Utc::now().date_naive(); + JulianDay::from(naive_now).inner().try_into().unwrap() +} + +// This should only be used for testing, use today in production +fn test_today(days: i64) -> u32 { + let naive_now_plus = (Utc::now() + Duration::days(days)).date_naive(); + JulianDay::from(naive_now_plus).inner().try_into().unwrap() +} + + +//pub const MAX_LEVEL: usize = 4; +//pub const LEVEL_INTERVAL: [u32; MAX_LEVEL + 1] = [0, 14, 28, 56, 84]; +fn calc_test_days(lox_cred: &Lox) -> Result { + let trust_level: i64 = match scalar_u32(&lox_cred.trust_level) { + Some(v) => v as i64, + None => return Err(ProofError::VerificationFailure), + }; + let mut total = 31; + // for level in 0..trust_level { + // let level_interval: u32 = LEVEL_INTERVAL[trust_level as usize]; + // total += level_interval; + total += trust_level*85; + // } + Ok(total) + } + +#[wasm_bindgen] +extern "C" { + #[wasm_bindgen(js_namespace = console)] + pub fn log(s: &str); +} + + +#[wasm_bindgen] +pub fn set_panic_hook() { + panic::set_hook(Box::new(console_error_panic_hook::hook)); +} + +#[wasm_bindgen] +pub fn open_invite(invite: &[u8]) -> Result { + unsafe { + log(&format!("Using invite: {:?}", invite)); + } + let token = match validate(invite) { + Ok(token) => token, + Err(e) => return Err(JsValue::from(e.to_string())), + }; + let (request, state) = open_invite::request(&token); + let req_state = OpenReqState { + request, + state, + }; + unsafe { + log(&format!( + "Formatted open invite request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + +#[wasm_bindgen] +pub fn handle_new_lox_credential( + open_lox_result: String, + open_lox_response: String, + lox_pub: String, +) -> Result { + let req_state: OpenReqState = serde_json::from_str(&open_lox_result).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&open_lox_response).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let lox_cred = match open_invite::handle_response( + deserialized_state, + deserialized_response, + &pubkeys.lox_pub, + ) { + Ok(lox_cred) => lox_cred, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let lox_cred = LoxCredential { + lox_credential: lox_cred.0, + bridgeline: Some(lox_cred.1), + invitation: None, + }; + unsafe { + log(&format!( + "Got new Lox Credential: {}", + serde_json::to_string(&lox_cred.lox_credential).unwrap() + )); + log(&format!( + "Got new bridgeline: {}", + serde_json::to_string(&lox_cred.bridgeline).unwrap() + )); + } + Ok(serde_json::to_string(&lox_cred).unwrap()) +} + +#[wasm_bindgen] +pub fn trust_promotion(open_lox_cred: String, lox_pub: String) -> Result { + let lox_cred: LoxCredential = serde_json::from_str(&open_lox_cred).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + // To test creation of the credential we need to advance the day to 30 + // in production this should just use the today() function + log(&format!( + "TEST ONLY: Add 31 days to today's date: {}", + test_today(31) + )); + let tp_result = + //CHANGE add_today(31) to today() for production + match trust_promotion::request(&lox_cred.lox_credential, &pubkeys.lox_pub, test_today(31)) { + Ok(tp_result) => tp_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = TrustReqState { + request: tp_result.0, + state: tp_result.1, + }; + unsafe { + log(&format!( + "Formatted Trust Promotion request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + +#[wasm_bindgen] +pub fn handle_trust_promotion( + trust_promo_request: String, + trust_promo_response: String, +) -> Result { + let req_state: TrustReqState = serde_json::from_str(&trust_promo_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&trust_promo_response).unwrap(); + let migration_cred = + match trust_promotion::handle_response(deserialized_state, deserialized_response) { + Ok(migration_cred) => migration_cred, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + unsafe { + log(&format!( + "Got new Migration Credential: {}", + serde_json::to_string(&migration_cred).unwrap() + )); + } + Ok(serde_json::to_string(&migration_cred).unwrap()) +} + +#[wasm_bindgen] +pub fn trust_migration(open_lox_cred: String, trust_promo_cred: String, lox_pub: String) -> Result { + let lox_cred: LoxCredential = serde_json::from_str(&open_lox_cred).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let mig_cred: Migration = serde_json::from_str(&trust_promo_cred).unwrap(); + let tm_result = + match migration::request(&lox_cred.lox_credential, &mig_cred, &pubkeys.lox_pub, &pubkeys.migration_pub) { + Ok(tm_result) => tm_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = MigReqState { + request: tm_result.0, + state: tm_result.1, + }; + unsafe { + log(&format!( + "Formatted Trust Migration request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + +#[wasm_bindgen] +pub fn handle_trust_migration( + trust_migration_request: String, + trust_migration_response: String, + lox_pub: String +) -> Result { + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let req_state: MigReqState = serde_json::from_str(&trust_migration_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&trust_migration_response).unwrap(); + let level_one_cred = + match migration::handle_response(deserialized_state, deserialized_response, &pubkeys.lox_pub) { + Ok(level_1_cred) => LoxCredential { + lox_credential: level_1_cred, + bridgeline: None, + invitation: None, + }, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + unsafe { + log(&format!( + "Got new Level 1 Credential: {}", + serde_json::to_string(&level_one_cred).unwrap() + )); + } + Ok(serde_json::to_string(&level_one_cred).unwrap()) +} + +fn generate_reachability_cred(lox_cred: &Lox, encrypted_table: String) -> BucketReachability { + let (id, key) = from_scalar(lox_cred.bucket).unwrap(); + let enc_buckets: EncBridgeTable = serde_json::from_str(&encrypted_table).unwrap(); + let bucket = BridgeTable::decrypt_bucket(id, &key, &enc_buckets.etable[id as usize]).unwrap(); + bucket.1.unwrap() +} + +#[wasm_bindgen] +pub fn level_up(level_one_cred: String, encrypted_table: String, lox_pub: String) -> Result { + let lox_cred: LoxCredential = serde_json::from_str(&level_one_cred).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let reach_cred = generate_reachability_cred(&lox_cred.lox_credential, encrypted_table); + + // To test level up of the credential we need to advance the day to the correct interval + // In this case, the maximum of 85 can be used to test all level ups + // in production this should just use the today() function + // decrypt trust level and use to calculate the correct date for now + // The trust level has to be at least 1 + let test_cumulative_days = match calc_test_days(&lox_cred.lox_credential) { + Ok(v) => v, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + + log(&format!( + "TEST ONLY: Add 31 (open invitation) + Trust Level*85 days to today's date: {}", test_today(test_cumulative_days) + )); + let lu_result = + //CHANGE add_today(31) to today() for production + match level_up::request(&lox_cred.lox_credential, &reach_cred, &pubkeys.lox_pub, &pubkeys.reachability_pub, test_today(test_cumulative_days)) { + Ok(lu_result) => lu_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = LevelupReqState { + request: lu_result.0, + state: lu_result.1, + }; + unsafe { + log(&format!( + "Formatted Level Up request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + + +#[wasm_bindgen] +pub fn handle_level_up( + levelup_request: String, + levelup_response: String, + lox_pub: String +) -> Result { + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let req_state: LevelupReqState = serde_json::from_str(&levelup_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&levelup_response).unwrap(); + let level_up_cred = + match level_up::handle_response(deserialized_state, deserialized_response, &pubkeys.lox_pub) { + Ok(level_up_cred) => LoxCredential { + lox_credential: level_up_cred, + bridgeline: None, + invitation: None, + }, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + unsafe { + log(&format!( + "Got new Level Up Credential: {}", + serde_json::to_string(&level_up_cred).unwrap() + )); + } + Ok(serde_json::to_string(&level_up_cred).unwrap()) +} + +#[wasm_bindgen] +pub fn issue_invite(trusted_cred: String, encrypted_table: String, lox_pub: String) -> Result { + let lox_cred: LoxCredential = serde_json::from_str(&trusted_cred).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let reach_cred = generate_reachability_cred(&lox_cred.lox_credential, encrypted_table); + + let issue_result = + match issue_invite::request(&lox_cred.lox_credential, &reach_cred, &pubkeys.lox_pub, &pubkeys.reachability_pub, test_today(371)) { + Ok(issue_result) => issue_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = IssueInviteReqState { + request: issue_result.0, + state: issue_result.1, + }; + unsafe { + log(&format!( + "Formatted Issue Invite request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + + +#[wasm_bindgen] +pub fn handle_issue_invite( + issue_invite_request: String, + issue_invite_response: String, + lox_pub: String +) -> Result { + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let req_state: IssueInviteReqState = serde_json::from_str(&issue_invite_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&issue_invite_response).unwrap(); + let issue_invite_cred = + match issue_invite::handle_response(deserialized_state, deserialized_response, &pubkeys.lox_pub, &pubkeys.invitation_pub) { + Ok(issue_invite_cred) => issue_invite_cred, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let invitation_cred = LoxCredential { + lox_credential: issue_invite_cred.0, + bridgeline: None, + invitation: Some(issue_invite_cred.1), + }; + + unsafe { + log(&format!( + "Got new Invitation Credential and Lox Credential: {}", + serde_json::to_string(&invitation_cred).unwrap() + )); + } + Ok(serde_json::to_string(&invitation_cred).unwrap()) +} + +// Separate Trusted Invite from credential prior to passing it to friend +#[wasm_bindgen] +pub fn prepare_invite(invitation_cred: String) -> String { + let cred: LoxCredential = serde_json::from_str(&invitation_cred).unwrap(); + log(&format!( + "Prepared Invitation: {}", + serde_json::to_string(&cred.invitation).unwrap() + )); + serde_json::to_string(&cred.invitation).unwrap() +} + +// +#[wasm_bindgen] +pub fn redeem_invite(invitation: String, lox_pub: String) -> Result { + let invitation_cred: Invitation = serde_json::from_str(&invitation).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let redeem_result = + match redeem_invite::request(&invitation_cred, &pubkeys.invitation_pub, test_today(371)) { + Ok(redeem_result) => redeem_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = RedeemReqState { + request: redeem_result.0, + state: redeem_result.1, + }; + unsafe { + log(&format!( + "Formatted Redeem Invite request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + +#[wasm_bindgen] +pub fn handle_redeem_invite( + redeem_invite_request: String, + redeem_invite_response: String, + lox_pub: String +) -> Result { + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let req_state: RedeemReqState = serde_json::from_str(&redeem_invite_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&redeem_invite_response).unwrap(); + let redeem_invite_cred = + match redeem_invite::handle_response(deserialized_state, deserialized_response, &pubkeys.lox_pub) { + Ok(issue_invite_cred) => LoxCredential { + lox_credential: issue_invite_cred, + bridgeline: None, + invitation: None, + }, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + unsafe { + log(&format!( + "Got new Trusted Lox Credential from Invitation: {}", + serde_json::to_string(&redeem_invite_cred).unwrap() + )); + } + Ok(serde_json::to_string(&redeem_invite_cred).unwrap()) +} + + +#[wasm_bindgen] +pub fn check_blockage(lox_cred: String, lox_pub: String) -> Result { + let lox: LoxCredential = serde_json::from_str(&lox_cred).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let cb_result = + match check_blockage::request(&lox.lox_credential, &pubkeys.lox_pub) { + Ok(cb_result) => cb_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = CheckBlockageReqState { + request: cb_result.0, + state: cb_result.1, + }; + unsafe { + log(&format!( + "Formatted Check Blockage request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + +#[wasm_bindgen] +pub fn handle_check_blockage( + check_blockage_request: String, + check_blockage_response: String, +) -> Result { + let req_state: CheckBlockageReqState = serde_json::from_str(&check_blockage_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&check_blockage_response).unwrap(); + let migration_cred = + match check_blockage::handle_response(deserialized_state, deserialized_response) { + Ok(migration_cred) => migration_cred, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + unsafe { + log(&format!( + "Got new Blockage Migration Credential: {}", + serde_json::to_string(&migration_cred).unwrap() + )); + } + Ok(serde_json::to_string(&migration_cred).unwrap()) +} + + +#[wasm_bindgen] +pub fn blockage_migration(lox_cred: String, check_migration_cred: String, lox_pub: String) -> Result { + let lox_cred: LoxCredential = serde_json::from_str(&lox_cred).unwrap(); + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let mig_cred: Migration = serde_json::from_str(&check_migration_cred).unwrap(); + let bm_result = + match blockage_migration::request(&lox_cred.lox_credential, &mig_cred, &pubkeys.lox_pub, &pubkeys.migration_pub) { + Ok(bm_result) => bm_result, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + let req_state = BlockageMigReqState { + request: bm_result.0, + state: bm_result.1, + }; + unsafe { + log(&format!( + "Formatted Blockage Migration request: {}", + serde_json::to_string(&req_state).unwrap() + )); + } + Ok(serde_json::to_string(&req_state).unwrap()) +} + +#[wasm_bindgen] +pub fn handle_blockage_migration( + blockage_migration_request: String, + blockage_migration_response: String, + lox_pub: String +) -> Result { + let pubkeys: PubKeys = serde_json::from_str(&lox_pub).unwrap(); + let req_state: BlockageMigReqState = serde_json::from_str(&blockage_migration_request).unwrap(); + let deserialized_state = req_state.state; + let deserialized_response = serde_json::from_str(&blockage_migration_response).unwrap(); + let lox_cred = + match blockage_migration::handle_response(deserialized_state, deserialized_response, &pubkeys.lox_pub) { + Ok(lox_cred) => LoxCredential { + lox_credential: lox_cred, + bridgeline: None, + invitation: None, + }, + Err(e) => { + log(&format!("Error: {:?}", e.to_string())); + return Err(JsValue::from(e.to_string())); + } + }; + unsafe { + log(&format!( + "Got new Lox Credential after Migration: {}", + serde_json::to_string(&lox_cred).unwrap() + )); + } + Ok(serde_json::to_string(&lox_cred).unwrap()) +} + +// This should also check the pubkey +fn validate(invite: &[u8]) -> Result<[u8; OPENINV_LENGTH], TryFromSliceError> { + invite.try_into() +}