Implement minimal prd/pcd, remove challenges
This commit is contained in:
parent
45628edb61
commit
287f74136e
@ -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"
|
||||
|
918
src/api.rs
918
src/api.rs
File diff suppressed because it is too large
Load Diff
45
src/lib.rs
45
src/lib.rs
@ -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>;
|
||||
}
|
||||
|
405
src/process.rs
405
src/process.rs
@ -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
|
||||
}
|
@ -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;
|
||||
|
@ -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()
|
||||
);
|
||||
|
@ -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()));
|
||||
// }
|
303
tests/pairing.rs
303
tests/pairing.rs
@ -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
|
||||
}
|
||||
|
81
tests/prd.rs
81
tests/prd.rs
@ -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(
|
||||
¬ification_tx.transaction,
|
||||
alice_outputs
|
||||
);
|
||||
|
||||
debug!("Alice parses her own notification transaction");
|
||||
// Alice parse her own transaction to update her utxos
|
||||
helper_parse_transaction(
|
||||
¬ification_tx.transaction,
|
||||
¬ification_tweak_data,
|
||||
);
|
||||
|
||||
reset_device().unwrap();
|
||||
restore_device(BOB_LOGGED_DEVICE.to_owned()).unwrap();
|
||||
|
||||
debug!("bob parses the transaction and the message");
|
||||
helper_parse_transaction(¬ification_tx.transaction, ¬ification_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);
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user