Implement minimal prd/pcd, remove challenges

This commit is contained in:
Sosthene 2024-08-28 09:51:40 +02:00
parent 45628edb61
commit 287f74136e
10 changed files with 391 additions and 1540 deletions

View File

@ -15,11 +15,9 @@ wasm-bindgen = "0.2.91"
getrandom = { version="0.2.12", features = ["js"] }
wasm-logger = "0.2.0"
rand = "0.8.5"
log = "0.4.6"
tsify = { git = "https://github.com/Sosthene00/tsify", branch = "next" }
# sdk_common = { path = "../sdk_common" }
sdk_common = { git = "https://git.4nkweb.com/4nk/sdk_common.git", branch = "dev" }
shamir = { git = "https://github.com/Sosthene00/shamir", branch = "master" }
sdk_common = { path = "../sdk_common" }
# sdk_common = { git = "https://git.4nkweb.com/4nk/sdk_common.git", branch = "dev" }
[dev-dependencies]
wasm-bindgen-test = "0.3"

File diff suppressed because it is too large Load Diff

View File

@ -2,9 +2,15 @@
use anyhow::Error;
use sdk_common::crypto::AnkSharedSecret;
use sdk_common::network::CachedMessage;
use sdk_common::process::Process;
use sdk_common::sp_client::bitcoin::OutPoint;
use sdk_common::uuid::Uuid;
use sdk_common::prd::ValidationToken;
use serde::{Deserialize, Serialize};
use serde_json::{Value, Map};
use std::collections::{HashMap, HashSet};
use std::fmt::Debug;
use std::ops::Index;
use std::sync::{Mutex, MutexGuard, OnceLock};
use tsify::Tsify;
@ -21,6 +27,45 @@ pub fn lock_messages() -> Result<MutexGuard<'static, Vec<CachedMessage>>, Error>
.lock_anyhow()
}
#[derive(Debug)]
pub enum ProcessStatus {
Sealed,
Active(Vec<String>), // shared_secrets used to communicate on current session
}
#[derive(Debug, Clone)]
pub struct ProcessState {
pub commited_in: OutPoint,
pub encrypted_pcd: Value,
pub keys: Map<String, Value>, // We may not always have all the keys
pub validation_token: Vec<ValidationToken> // This signs the encrypted pcd
}
#[derive(Debug)]
pub struct RelevantProcess {
process: Process,
states: Vec<ProcessState>,
current_status: ProcessStatus,
}
impl RelevantProcess {
pub fn get_process(&self) -> Process {
self.process.clone()
}
pub fn get_status_at(&self, index: usize) -> Option<ProcessState> {
self.states.get(index).cloned()
}
}
pub static CACHEDPROCESSES: OnceLock<Mutex<HashMap<Uuid, RelevantProcess>>> = OnceLock::new();
pub fn lock_processes() -> Result<MutexGuard<'static, HashMap<Uuid, RelevantProcess>>, Error> {
CACHEDPROCESSES
.get_or_init(|| Mutex::new(HashMap::new()))
.lock_anyhow()
}
pub(crate) trait MutexExt<T> {
fn lock_anyhow(&self) -> Result<MutexGuard<T>, Error>;
}

View File

@ -1,405 +0,0 @@
use std::fmt::DebugStruct;
use sdk_common::sp_client::silentpayments::utils::SilentPaymentAddress;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use tsify::Tsify;
use wasm_bindgen::prelude::*;
pub const HTML_KOTPART: &str = "
<div class='card'>
<div class='side-by-side'>
<h3>Send encrypted messages</h3>
<div>
<a href='#' id='send messages'>Send Messages</a>
</div>
</div>
<form id='form4nk' action='#'>
<label for='sp_address'>Send to:</label>
<input type='text' id='sp_address' />
<hr/>
<label for='message'>Message:</label>
<input type='message' id='message' />
<hr/>
<button type='submit' id='submitButton' class='recover bg-primary'>Send</button>
</form>
</div>
";
pub const HTML_STORAGE: &str = "
<div class='card'>
<div class='side-by-side'>
<h3>Send encrypted messages</h3>
<div>
<a href='#' id='send messages'>Send Messages</a>
</div>
</div>
<form id='form4nk' action='#'>
<label for='sp_address'>Send to:</label>
<input type='text' id='sp_address' />
<hr/>
<label for='message'>Message:</label>
<input type='message' id='message' />
<hr/>
<button type='submit' id='submitButton' class='recover bg-primary'>Send</button>
</form>
</div>
";
pub const HTML_MESSAGING: &str = "
<div class='card'>
<div class='side-by-side'>
<h3>Send encrypted messages</h3>
<div>
<a href='#' id='send messages'>Send Messages</a>
</div>
</div>
<form id='form4nk' action='#'>
<div id='our_address' class='our_address'></div>
<label for='sp_address'>Send to:</label>
<input type='text' id='sp_address' />
<hr/>
<label for='message'>Message:</label>
<input type='message' id='message' />
<hr/>
<button type='submit' id='submitButton' class='recover bg-primary'>Send</button>
</form>
</div>
";
pub const CSS: &str = "
body {
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #f4f4f4;
font-family: 'Arial', sans-serif;
}
.container {
text-align: center;
}
.card {
max-width: 400px;
width: 100%;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
background-color: #ffffff;
border-radius: 8px;
text-align: left;
overflow: hidden;
}
form {
display: flex;
flex-direction: column;
/* flex-wrap: wrap; */
}
label {
font-weight: bold;
margin-bottom: 8px;
}
hr {
border: 0;
height: 1px;
background-color: #ddd;
margin: 10px 0;
}
input, select {
width: 100%;
padding: 10px;
margin: 8px 0;
box-sizing: border-box;
}
select {
padding: 10px;
background-color: #f9f9f9;
border: 1px solid #ddd;
border-radius: 4px;
cursor: pointer;
}
button {
display: inline-block;
background-color: #4caf50;
color: #fff;
border: none;
padding: 12px 17px;
border-radius: 4px;
cursor: pointer;
}
button:hover {
background-color: #45a049;
}
.side-by-side {
display: flex;
align-items: center;
justify-content: space-between;
}
.side-by-side>* {
display: inline-block;
}
button.recover {
display: inline-block;
text-align: center;
text-decoration: none;
display: inline-block;
background-color: #4caf50;
color: #fff;
border: none;
padding: 12px 17px;
border-radius: 4px;
cursor: pointer;
}
button.recover:hover {
background-color: #45a049;
}
a.btn {
display: inline-block;
text-align: center;
text-decoration: none;
display: inline-block;
background-color: #4caf50;
color: #fff;
border: none;
padding: 12px 17px;
border-radius: 4px;
cursor: pointer;
}
a.btn:hover {
background-color: #45a049;
}
a {
text-decoration: none;
color: #78a6de;
}
.bg-secondary {
background-color: #2b81ed;
}
.bg-primary {
background-color: #1A61ED;
}
.bg-primary:hover {
background-color: #457be8;
}
.card-revoke {
display: flex;
flex-direction: column;
max-width: 400px;
width: 100%;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
background-color: #ffffff;
border-radius: 8px;
text-align: center;
align-items: center;
overflow: hidden;
}
.card-revoke a {
max-width: 50px;
width: 100%;
background: none;
border: none;
cursor: pointer;
}
.card-revoke button {
max-width: 200px;
width: 100%;
background: none;
border: none;
cursor: pointer;
color: #78a6de;
}
.card-revoke svg {
width: 100%;
height: auto;
fill: #333;
}
.image-label {
display: block;
color: #fff;
padding: 5px;
margin-top: 10px;
}
.image-container {
width: 400px;
height: 300px;
overflow: hidden;
}
.image-container img {
text-align: center;
width: 100%;
height: 100%;
object-fit: cover;
object-position: center center;
}
.passwordalert {
color: #FF0000;
}
";
pub const CSSUPDATE: &str = "
<style>
body {
margin: 0;
padding: 0;
display: flex;
align-items: center;
justify-content: center;
min-height: 100vh;
background-color: #f4f4f4;
font-family: 'Arial', sans-serif;
}
.container {
max-width: 400px;
width: 100%;
padding: 20px;
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
background-color: #ffffff;
border-radius: 8px;
text-align: left;
overflow: hidden;
}
form {
display: grid;
grid-template-columns: repeat(1fr, 2fr);
gap: 10px;
max-width: 400px;
margin: auto;
}
.bg-primary {
background-color: #1a61ed;
}
.bg-primary:hover {
background-color: #457be8;
}
.bg-secondary {
background-color: #2b81ed;
}
.bg-secondary:hover {
background-color: #5f9bff;
}
label {
text-align: left;
padding-right: 10px;
line-height: 2;
}
input {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
button {
grid-column: span 2;
display: inline-block;
color: #fff;
border: none;
padding: 12px 17px;
border-radius: 4px;
cursor: pointer;
}
.div-text-area {
grid-column: span 2;
}
textarea {
width: 100%;
padding: 8px;
box-sizing: border-box;
}
.side-by-side {
display: flex;
align-items: center;
justify-content: space-between;
gap: 10px;
margin-bottom: 5px;
}
.circle-btn {
width: 25px;
height: 25px;
border-radius: 50%;
border: none;
color: white;
padding: 0px;
text-align: center;
}
#fileInput {
width: 100%;
padding: 8px;
padding-left: 0px;
box-sizing: border-box;
}
</style>
";
pub const JSUPDATE: &str = "
var addSpAddressBtn = document.getElementById('add-sp-address-btn');
var removeSpAddressBtn = document.querySelectorAll('.minus-sp-address-btn');
addSpAddressBtn.addEventListener('click', function (event) {
addDynamicField(this);
});
function addDynamicField(element) {
var addSpAddressBlock = document.getElementById('sp-address-block');
var spAddress = addSpAddressBlock.querySelector('#sp-address').value;
addSpAddressBlock.querySelector('#sp-address').value = '';
spAddress = spAddress.trim();
if (spAddress != '') {
var sideBySideDiv = document.createElement('div');
sideBySideDiv.className = 'side-by-side';
var inputElement = document.createElement('input');
inputElement.type = 'text';
inputElement.name = 'spAddresses[]';
inputElement.setAttribute('form', 'no-form');
inputElement.value = spAddress;
inputElement.disabled = true;
var buttonElement = document.createElement('button');
buttonElement.type = 'button';
buttonElement.className =
'circle-btn bg-secondary minus-sp-address-btn';
buttonElement.innerHTML = '-';
buttonElement.addEventListener('click', function (event) {
removeDynamicField(this.parentElement);
});
sideBySideDiv.appendChild(inputElement);
sideBySideDiv.appendChild(buttonElement);
addSpAddressBlock.appendChild(sideBySideDiv);
}
function removeDynamicField(element) {
element.remove();
}
}
";
#[derive(Debug, Serialize, Deserialize, Default, Tsify)]
#[tsify(into_wasm_abi, from_wasm_abi)]
pub struct Process {
pub id: u32,
pub name: String,
pub version: String,
pub members: Vec<String>,
pub html: String,
pub style: String,
pub script: String,
// Add conditions : process, member, peer, artefact
}

View File

@ -9,6 +9,7 @@ use sdk_common::sp_client::bitcoin::{
Network, OutPoint, ScriptBuf, Transaction, Txid, XOnlyPublicKey,
};
use sdk_common::sp_client::spclient::SpClient;
use sdk_common::uuid::Uuid;
use serde::{Deserialize, Serialize};
use serde_json::{json, Value};
use tsify::Tsify;

View File

@ -33,7 +33,7 @@ pub fn generate_sp_wallet(label: Option<String>, network: Network) -> anyhow::Re
network,
)?;
let our_address: SilentPaymentAddress = sp_client.get_receiving_address().try_into()?;
log::info!(
sdk_common::log::info!(
"Created client for sp with address: {}",
our_address.to_string()
);

View File

@ -1,153 +0,0 @@
use std::collections::HashMap;
use log::debug;
use sdk_client::api::{
create_confirmation_transaction, create_notification_transaction, dump_device, dump_message_cache, get_outputs, reset_device, restore_device, set_message_cache, setup
};
use sdk_common::network::{
CachedMessage, CachedMessageStatus, Pcd
};
use sdk_common::sp_client::bitcoin::OutPoint;
use sdk_common::sp_client::spclient::OwnedOutput;
use tsify::JsValueSerdeExt;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
mod utils;
use utils::*;
#[wasm_bindgen_test]
fn test_bob_challenges_alice() {
reset_device().unwrap();
debug!("==============================================\nStarting test_bob_challenges_alice\n==============================================");
// =============================== Bob
setup();
restore_device(BOB_CHALLENGE_DEVICE.to_owned()).unwrap();
set_message_cache(
serde_json::from_str::<Vec<CachedMessage>>(BOB_CHALLENGE_CACHE)
.unwrap()
.into_iter()
.map(|v| v.to_string())
.collect(),
)
.unwrap();
let notification_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap();
let get_outputs_result = get_outputs().unwrap();
let bob_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
debug!("Bob sends a challenge transaction back to Alice");
debug!("outpoints: {:?}", bob_outputs);
let confirmation_tx = create_confirmation_transaction(notification_msg.id, 1).unwrap();
let confirmation_tweak_data = helper_get_tweak_data(
&confirmation_tx.transaction,
bob_outputs
);
debug!("Bob parsing its own confirmation tx");
helper_parse_transaction(
&confirmation_tx.transaction,
&confirmation_tweak_data,
);
// ========================== Alice
reset_device().unwrap();
restore_device(ALICE_CHALLENGE_DEVICE.to_owned()).unwrap();
set_message_cache(
serde_json::from_str::<Vec<CachedMessage>>(ALICE_CHALLENGE_CACHE)
.unwrap()
.into_iter()
.map(|v| v.to_string())
.collect(),
)
.unwrap();
debug!("Alice parsing confirmation tx");
helper_parse_transaction(&confirmation_tx.transaction, &confirmation_tweak_data);
}
// #[wasm_bindgen_test]
// fn test_alice_answers_bob() {
// reset_device().unwrap();
// setup();
// debug!("==============================================\nStarting test_alice_answers_bob\n==============================================");
// restore_device(ALICE_ANSWER_DEVICE.to_owned()).unwrap();
// set_message_cache(
// serde_json::from_str::<Vec<CachedMessage>>(ALICE_ANSWER_CACHE)
// .unwrap()
// .into_iter()
// .map(|v| v.to_string())
// .collect(),
// )
// .unwrap();
// let challenge_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap();
// debug!("Alice answers bob's challenge");
// let answer_tx = answer_confirmation_transaction(challenge_msg.id, 1).unwrap();
// let get_outputs_result = get_outputs().unwrap();
// let alice_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
// let answer_tweak_data = helper_get_tweak_data(
// &answer_tx.transaction,
// alice_outputs,
// );
// debug!("Alice parses her own transaction");
// helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data);
// reset_device().unwrap();
// restore_device(BOB_ANSWER_DEVICE.to_owned()).unwrap();
// set_message_cache(
// serde_json::from_str::<Vec<CachedMessage>>(BOB_ANSWER_CACHE)
// .unwrap()
// .into_iter()
// .map(|v| v.to_string())
// .collect(),
// )
// .unwrap();
// debug!("Bob parses answer transaction {}", answer_tx.txid);
// helper_parse_transaction(&answer_tx.transaction, &answer_tweak_data);
// }
// #[wasm_bindgen_test]
// fn test_alice_sends_message_through_trusted_channel() {
// reset_device().unwrap();
// setup();
// debug!("==============================================\nStarting test_alice_sends_message_through_trusted_channel\n==============================================");
// restore_device(ALICE_FINAL_DEVICE.to_owned()).unwrap();
// set_message_cache(
// serde_json::from_str::<Vec<CachedMessage>>(ALICE_FINAL_CACHE)
// .unwrap()
// .into_iter()
// .map(|v| v.to_string())
// .collect(),
// )
// .unwrap();
// let answered_msg: CachedMessage = serde_json::from_str(dump_message_cache().unwrap().get(0).unwrap()).unwrap();
// // Bob sends a message to Alice
// debug!("Bob Sends a message to Alice");
// let secret_msg = "Hello Alice";
// let cipher =
// encrypt_with_key(secret_msg.to_owned(), answered_msg.shared_secret.unwrap()).unwrap();
// let bob_msg = Envelope::new(sdk_common::network::AnkFlag::Cipher, &cipher);
// // Alice can find the message
// let mut result = helper_parse_cipher(bob_msg.to_string());
// assert!(result.plaintext.pop() == Some(secret_msg.to_owned()));
// }

View File

@ -1,15 +1,18 @@
use std::collections::HashMap;
use log::debug;
use sdk_client::api::{
create_login_transaction, create_pairing_transaction, dump_device, dump_message_cache, dump_wallet, get_outputs, login, pair_device, reset_device, restore_device, set_message_cache, setup
};
use sdk_common::network::{
CachedMessage, CachedMessageStatus,
create_device_from_sp_wallet, create_process_init_transaction, get_outputs, pair_device, reset_device, setup, CreateProcessInitTransactionArguments
};
use sdk_client::lock_processes;
use sdk_common::network::CachedMessage;
use sdk_common::pcd::{Member, Pcd, Role};
use sdk_common::prd::Prd;
use sdk_common::process::{Process, ValidationRules};
use sdk_common::sp_client::bitcoin::OutPoint;
use sdk_common::sp_client::spclient::OwnedOutput;
use serde_json;
use sdk_common::uuid::Uuid;
use sdk_common::log::debug;
use serde_json::{self, json, Value};
use tsify::JsValueSerdeExt;
use wasm_bindgen_test::*;
@ -26,229 +29,119 @@ fn test_pairing() {
debug!("==============================================\nStarting test_pairing\n==============================================");
// ========================= Alice
helper_switch_device(ALICE_LOGIN_WALLET.to_owned());
reset_device().unwrap();
create_device_from_sp_wallet(ALICE_LOGIN_WALLET.to_owned()).unwrap();
debug!("Alice sends a pairing transaction to Bob");
let alice_pairing_tx = create_pairing_transaction(helper_get_bob_address(), 1).unwrap();
// Alice creates the new member with Bob address
let new_member = Member::new(
DEFAULT_NYM.to_owned(),
helper_get_alice_address().try_into().unwrap(),
helper_get_bob_address().try_into().unwrap(),
Role::User
);
let initial_state = json!({
"nym": DEFAULT_NYM,
"members": [
new_member,
],
"current_session_tx": null,
});
let validation_rules = ValidationRules::new(
1.0,
Role::Admin,
1.0
);
let mut member2fields: HashMap<Member, Vec<String>> = HashMap::new();
member2fields.insert(new_member, initial_state.as_object().unwrap().keys().map(|k| k.to_owned()).collect());
// We define the process for pairing
let pairing_process = Process::new(
"pairing".to_owned(),
validation_rules,
String::default(),
String::default(),
String::default(),
Value::Null,
OutPoint::null()
);
// we can update our local device now
pair_device(pairing_process.uuid.clone(), helper_get_bob_address(), initial_state.to_string()).unwrap();
debug!("Alice sends a transaction commiting to an init prd to Bob");
let args = CreateProcessInitTransactionArguments {
member2fields,
process: pairing_process,
stringified_pcd: initial_state.to_string()
};
let alice_pairing_return = create_process_init_transaction(args, 1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let alice_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let alice_pairing_tweak_data =
helper_get_tweak_data(&alice_pairing_tx.transaction, alice_outputs);
helper_get_tweak_data(&alice_pairing_return.transaction, alice_outputs);
// Alice parse her own transaction
let alice_msg_id =
helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data).id;
let alice_wallet = dump_wallet().unwrap();
let alice_cache = dump_message_cache().unwrap();
helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data).id;
// ======================= Bob
reset_device().unwrap();
helper_switch_device(BOB_LOGIN_WALLET.to_owned());
create_device_from_sp_wallet(BOB_LOGIN_WALLET.to_owned()).unwrap();
// Bob receives Alice pairing transaction
// if he agrees, he must send another pairing transaction to Alice
// he can also spend the output that notified him that will become Alice first session key
debug!("Bob parses Alice pairing transaction");
helper_parse_transaction(&alice_pairing_tx.transaction, &alice_pairing_tweak_data);
helper_parse_transaction(&alice_pairing_return.transaction, &alice_pairing_tweak_data);
debug!("Bob receives the prd");
helper_parse_cipher(alice_pairing_tx.new_network_msg.prd_cipher.unwrap());
let mut bob_retrieved_prd = CachedMessage::default();
for message in alice_pairing_return.new_messages.iter() {
for cipher in message.cipher.iter() {
match helper_parse_cipher(cipher.clone()) {
Ok(res) => bob_retrieved_prd = res,
Err(_) => continue
}
}
}
if bob_retrieved_prd == CachedMessage::default() {
panic!("Bob failed to retrieve Alice message");
}
debug!("Bob receives the pcd");
let alice_pairing_res = helper_parse_cipher(alice_pairing_tx.new_network_msg.pcd_cipher.unwrap());
let mut bob_retrieved_pcd = CachedMessage::default();
for message in alice_pairing_return.new_messages {
for cipher in message.cipher {
match helper_parse_cipher(cipher) {
Ok(res) => bob_retrieved_pcd = res,
Err(_) => continue
}
}
}
assert!(alice_pairing_res.status == CachedMessageStatus::Pairing);
// Bob takes the txid of the incoming transaction from Alice, he will need it for pairing
let incoming_txid = alice_pairing_res.commited_in.unwrap().txid;
if bob_retrieved_pcd == CachedMessage::default() {
panic!("Bob failed to retrieve Alice message");
}
// At this point, user must validate the pairing proposal received from Alice
debug!("Bob sends a pairing transaction back");
let bob_pairing_tx = create_pairing_transaction(alice_pairing_res.sender.unwrap(), 1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let bob_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let bob_pairing_tweak_data = helper_get_tweak_data(&bob_pairing_tx.transaction, bob_outputs);
helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data);
debug!("Bob pairs device with Alice");
let pairing_process = pair_device(DEFAULT_NYM.to_owned(), bob_pairing_tx.new_network_msg.id, incoming_txid.to_string()).unwrap();
let process = lock_processes().unwrap();
let prd: Prd = serde_json::from_str(&bob_retrieved_prd.prd.unwrap()).unwrap();
let relevant_process = process.get(&Uuid::parse_str(&prd.process_uuid).unwrap()).unwrap();
// decrypt the pcd and update bob device
if let Some(initial_state) = relevant_process.get_status_at(0) {
let keys = initial_state.keys;
let mut pcd = initial_state.encrypted_pcd;
pcd.decrypt_fields(&keys).unwrap();
pair_device(relevant_process.get_process().uuid, helper_get_alice_address(), pcd.to_string()).unwrap();
}
// sign the pairing process
// To make the pairing effective, alice and bob must now spend their respective output into a new transaction
// send it to Alice so that she can sign it too
// commit it to a transaction to make it public
// ======================== Alice
reset_device().unwrap();
helper_switch_device(alice_wallet);
set_message_cache(alice_cache).unwrap();
// parse Bob's pairing transaction
helper_parse_transaction(&bob_pairing_tx.transaction, &bob_pairing_tweak_data);
helper_parse_cipher(bob_pairing_tx.new_network_msg.prd_cipher.unwrap());
let bob_pairing_msg = helper_parse_cipher(bob_pairing_tx.new_network_msg.pcd_cipher.unwrap());
assert!(bob_pairing_msg.status == CachedMessageStatus::Pairing);
debug!("Alice pairs device");
pair_device(DEFAULT_NYM.to_owned(), alice_msg_id, bob_pairing_tx.txid).unwrap();
}
#[wasm_bindgen_test]
fn test_first_login() {
reset_device().unwrap();
setup();
debug!("==============================================\nStarting test_first_login\n==============================================");
restore_device(BOB_PAIRED_DEVICE.to_owned()).unwrap();
set_message_cache(
serde_json::from_str::<Vec<CachedMessage>>(BOB_PAIRING_CACHE)
.unwrap()
.into_iter()
.map(|v| v.to_string())
.collect(),
)
.unwrap();
// Bob can now spend the notification output, that will become Alice's first session key
debug!("Bob first login");
let bob_first_login_tx = create_login_transaction(1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let bob_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let bob_login_tweak_data = helper_get_tweak_data(&bob_first_login_tx.transaction, bob_outputs);
debug!("Bob parses his own login transaction");
helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data);
let bob_device = dump_device().unwrap();
let bob_cache = dump_message_cache().unwrap();
// ======================== Alice
reset_device().unwrap();
restore_device(ALICE_PAIRED_DEVICE.to_owned()).unwrap();
set_message_cache(
serde_json::from_str::<Vec<CachedMessage>>(ALICE_PAIRING_CACHE)
.unwrap()
.into_iter()
.map(|v| v.to_string())
.collect(),
)
.unwrap();
debug!("Alice finds out the login demand from Bob");
helper_parse_transaction(&bob_first_login_tx.transaction, &bob_login_tweak_data);
helper_parse_cipher(bob_first_login_tx.new_network_msg.prd_cipher.unwrap());
let bob_login_msg = helper_parse_cipher(bob_first_login_tx.new_network_msg.pcd_cipher.unwrap());
// At this point Alice can fire up the revokation output if the login demand is illegitimate
// OR she must answer with a login transaction to Bob
debug!("Alice first login");
let alice_first_login_tx = create_login_transaction(1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let alice_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let alice_login_tweak_data =
helper_get_tweak_data(&alice_first_login_tx.transaction, alice_outputs);
helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data);
login(bob_login_msg.id, alice_first_login_tx.transaction.clone()).unwrap();
// ======================= Bob
reset_device().unwrap();
restore_device(bob_device).unwrap();
set_message_cache(bob_cache).unwrap();
helper_parse_transaction(&alice_first_login_tx.transaction, &alice_login_tweak_data);
helper_parse_cipher(alice_first_login_tx.new_network_msg.prd_cipher.unwrap());
let alice_login_msg = helper_parse_cipher(alice_first_login_tx.new_network_msg.pcd_cipher.unwrap());
assert!(alice_login_msg.status == CachedMessageStatus::Login);
login(alice_login_msg.id, bob_first_login_tx.transaction).unwrap();
}
#[wasm_bindgen_test]
fn test_login() {
reset_device().unwrap();
setup();
debug!("==============================================\nStarting test_login\n==============================================");
// ======================= Alice
restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap();
debug!("Alice sends a login transaction to Bob, which creates a new key for him");
let alice_login_tx = create_login_transaction(1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let alice_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let alice_login_tweak_data = helper_get_tweak_data(
&alice_login_tx.transaction,
alice_outputs
);
debug!("Parsing Alice login transaction");
helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data);
let alice_device = dump_device().unwrap();
let alice_cache = dump_message_cache().unwrap();
// ============================== Bob
reset_device().unwrap();
restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap();
debug!("Bob finds out the login demand from Alice");
helper_parse_transaction(&alice_login_tx.transaction, &alice_login_tweak_data);
helper_parse_cipher(alice_login_tx.new_network_msg.prd_cipher.unwrap());
let alice_login_msg = helper_parse_cipher(alice_login_tx.new_network_msg.pcd_cipher.unwrap());
// Bob must confirm that he agrees to log in
// Boutons "login" ou "Refuser"
// At this point Bob can fire up the revokation output if the login demand is illegitimate
// revoke_paired_device(1).unwrap();
// OR it must answer with a login transaction to Alice
let bob_login_tx = create_login_transaction(1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let bob_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let bob_login_tweak_data = helper_get_tweak_data(&bob_login_tx.transaction, bob_outputs);
debug!("Bob parses his own login transaction");
helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data);
login(alice_login_msg.id, alice_login_tx.transaction.clone()).unwrap();
// =================== Alice
reset_device().unwrap();
restore_device(alice_device).unwrap();
set_message_cache(alice_cache).unwrap();
helper_parse_transaction(&bob_login_tx.transaction, &bob_login_tweak_data);
helper_parse_cipher(bob_login_tx.new_network_msg.prd_cipher.unwrap());
let bob_login_msg = helper_parse_cipher(bob_login_tx.new_network_msg.pcd_cipher.unwrap());
assert!(bob_login_msg.status == CachedMessageStatus::Login);
login(bob_login_msg.id, alice_login_tx.transaction).unwrap();
// Once we know this tx id, we can commit to the relay
}

View File

@ -1,81 +0,0 @@
use std::collections::HashMap;
use log::debug;
use sdk_client::api::{
create_confirmation_transaction, create_notification_transaction, dump_device, dump_message_cache, get_outputs, reset_device, restore_device, set_message_cache, setup
};
use sdk_common::network::{
CachedMessage, CachedMessageStatus, Pcd
};
use sdk_common::process::{Process, Role, ValidationRules};
use sdk_common::sp_client::bitcoin::hashes::Hash;
use sdk_common::sp_client::bitcoin::{OutPoint, Txid};
use sdk_common::sp_client::spclient::OwnedOutput;
use serde_json::Value;
use tsify::JsValueSerdeExt;
use wasm_bindgen_test::*;
wasm_bindgen_test_configure!(run_in_browser);
mod utils;
use utils::*;
#[wasm_bindgen_test]
fn test_alice_sends_prd_message_to_bob() {
reset_device().unwrap();
setup();
debug!("==============================================\nStarting test_alice_sends_prd_message_to_bob\n==============================================");
// ============================ Alice
restore_device(ALICE_LOGGED_DEVICE.to_owned()).unwrap();
// Alice first puts her message in a pcd
let pcd = Pcd::new("TEST".to_owned());
debug!("Alice notified Bob about a message it sent");
let empty_process = Process::new(
"empty".to_owned(),
vec![],
ValidationRules::new(0.0, Role::User),
Txid::all_zeros(),
String::default(),
String::default(),
String::default(),
Value::Null
);
let notification_tx =
create_notification_transaction(helper_get_bob_address(), empty_process, pcd, 1).unwrap();
let get_outputs_result = get_outputs().unwrap();
let alice_outputs: HashMap<OutPoint, OwnedOutput> = get_outputs_result.into_serde().unwrap();
let notification_tweak_data = helper_get_tweak_data(
&notification_tx.transaction,
alice_outputs
);
debug!("Alice parses her own notification transaction");
// Alice parse her own transaction to update her utxos
helper_parse_transaction(
&notification_tx.transaction,
&notification_tweak_data,
);
reset_device().unwrap();
restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap();
debug!("bob parses the transaction and the message");
helper_parse_transaction(&notification_tx.transaction, &notification_tweak_data);
helper_parse_cipher(notification_tx.new_network_msg.prd_cipher.unwrap());
let bob_notification_msg = helper_parse_cipher(notification_tx.new_network_msg.pcd_cipher.unwrap());
let msg_dump = dump_message_cache().unwrap();
debug!("bob_wallet: {:?}", dump_device());
debug!("bob_notification_msg: {:?}", msg_dump);
debug!("commited_in: {:?}", msg_dump.get(0).unwrap().find("0x71b37cede4655932a5ce97bb8c4a7845adce96d4f85b64bc699bf74942c19f89"));
assert!(bob_notification_msg.status == CachedMessageStatus::ReceivedMustConfirm);
}

View File

@ -1,7 +1,6 @@
use std::collections::HashMap;
use log::debug;
use sdk_client::api::{parse_cipher, parse_new_tx, reset_device, restore_device_from_sp_wallet};
use sdk_client::api::{parse_cipher, parse_new_tx, reset_device, ApiResult};
use sdk_common::network::{
CachedMessage, NewTxMessage,
};
@ -13,6 +12,7 @@ use sdk_common::sp_client::silentpayments::utils::receiving::{
calculate_tweak_data, get_pubkey_from_input,
};
use sdk_common::sp_client::spclient::{OwnedOutput, SpWallet};
use sdk_common::log::debug;
use serde_json;
// We're using alice and bob for clarity, but it's important to remember that for pairing and login Alice and Bob are the same person
@ -39,11 +39,6 @@ pub const ALICE_FINAL_DEVICE: &str = "{\"sp_wallet\":{\"client\":{\"label\":\"de
pub const DEFAULT_NYM: &str = "AliceBob";
pub fn helper_switch_device(wallet: String) {
reset_device().unwrap();
restore_device_from_sp_wallet(wallet.clone()).unwrap();
}
pub fn helper_get_alice_address() -> String {
let wallet: SpWallet = serde_json::from_str(ALICE_START_WALLET).unwrap();
wallet.get_client().get_receiving_address()
@ -100,10 +95,6 @@ pub fn helper_parse_transaction(transaction: &str, tweak_data: &str) -> CachedMe
}
}
pub fn helper_parse_cipher(cipher_msg: String) -> CachedMessage {
let result = parse_cipher(cipher_msg, 1);
match result {
Ok(r) => return r,
Err(e) => panic!("Unexpected error: {}", e.message),
};
pub fn helper_parse_cipher(cipher_msg: String) -> ApiResult<CachedMessage> {
parse_cipher(cipher_msg, 1)
}