Persistent user and wallets
This commit is contained in:
parent
de14367ce0
commit
c656a852ee
@ -1,4 +1,5 @@
|
||||
use std::collections::HashMap;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
use rand::Rng;
|
||||
|
||||
@ -18,7 +19,7 @@ use sp_backend::spclient::SpendKey;
|
||||
use sp_backend::spclient::{derive_keys_from_seed, OutputList, SpClient};
|
||||
use web_sys::js_sys::JsString;
|
||||
|
||||
use crate::user::{User, UserKeys};
|
||||
use crate::user::{User, UserKeys, CONNECTED_USERS};
|
||||
|
||||
type ApiResult<T: FromWasmAbi> = Result<T, ApiError>;
|
||||
|
||||
@ -128,50 +129,24 @@ pub fn create_user(
|
||||
password: String,
|
||||
label: Option<String>,
|
||||
birthday: u32,
|
||||
process: String
|
||||
process: String,
|
||||
) -> ApiResult<createUserReturn> {
|
||||
let mut output_list: Vec<OutputList> = Vec::new();
|
||||
//recover
|
||||
let sp_wallet_recover = generate_sp_wallet(label.clone(), birthday, true)?;
|
||||
output_list.push(sp_wallet_recover.sp_outputs);
|
||||
let recover_scan_key = sp_wallet_recover.sp_client.get_scan_key();
|
||||
let recover_spend_key = match sp_wallet_recover.sp_client.get_spend_key() {
|
||||
SpendKey::Secret(key) => key,
|
||||
SpendKey::Public(_) => {
|
||||
return Err(ApiError::from(AnyhowError::msg(
|
||||
"No recover spend key created on Signet",
|
||||
)))
|
||||
}
|
||||
};
|
||||
let recover_keys = UserKeys::add_keys_recover(recover_scan_key, recover_spend_key);
|
||||
//revoke
|
||||
let sp_wallet_revoke = generate_sp_wallet(label.clone(), birthday, true)?;
|
||||
output_list.push(sp_wallet_revoke.sp_outputs);
|
||||
let revoke_scan_key = sp_wallet_revoke.sp_client.get_scan_key();
|
||||
let revoke_spend_key = match sp_wallet_revoke.sp_client.get_spend_key() {
|
||||
SpendKey::Secret(key) => key,
|
||||
SpendKey::Public(_) => {
|
||||
return Err(ApiError::from(AnyhowError::msg(
|
||||
"No revoke spend key created on Signet",
|
||||
)))
|
||||
}
|
||||
};
|
||||
let revoke_keys = UserKeys::add_keys_revoke(revoke_scan_key, revoke_spend_key);
|
||||
//mainet
|
||||
let sp_wallet_main = generate_sp_wallet(label, birthday, false)?;
|
||||
output_list.push(sp_wallet_main.sp_outputs);
|
||||
let main_scan_key = sp_wallet_main.sp_client.get_scan_key();
|
||||
let main_spend_key = match sp_wallet_main.sp_client.get_spend_key() {
|
||||
SpendKey::Secret(key) => key,
|
||||
SpendKey::Public(_) => {
|
||||
return Err(ApiError::from(AnyhowError::msg(
|
||||
"No spend key created on Mainet",
|
||||
)))
|
||||
}
|
||||
};
|
||||
let main_keys = UserKeys::add_keys_main(main_scan_key, main_spend_key);
|
||||
|
||||
let user_keys = UserKeys::new(recover_keys, revoke_keys, main_keys);
|
||||
let user_keys = UserKeys::new(
|
||||
Some(sp_wallet_main.sp_client),
|
||||
sp_wallet_recover.sp_client,
|
||||
Some(sp_wallet_revoke.sp_client),
|
||||
);
|
||||
|
||||
let user = User::new(user_keys, password, process)?;
|
||||
|
||||
|
@ -12,15 +12,18 @@ use sp_backend::bitcoin::hashes::Hash;
|
||||
use sp_backend::bitcoin::hashes::HashEngine;
|
||||
use sp_backend::bitcoin::hex::{DisplayHex, FromHex};
|
||||
use sp_backend::bitcoin::secp256k1::SecretKey;
|
||||
use sp_backend::bitcoin::secp256k1::ThirtyTwoByteHash;
|
||||
use tsify::Tsify;
|
||||
use wasm_bindgen::prelude::*;
|
||||
|
||||
use bytes::Bytes;
|
||||
use shamir::SecretData;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::io::Write;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Mutex, OnceLock};
|
||||
|
||||
use sp_backend::bitcoin::secp256k1::constants::SECRET_KEY_SIZE;
|
||||
use sp_backend::silentpayments::bitcoin_hashes::sha256;
|
||||
@ -34,99 +37,60 @@ use img_parts::{ImageEXIF, ImageICC};
|
||||
use crate::aesgcm::Aes256Decryption;
|
||||
use crate::aesgcm::HalfKey;
|
||||
use crate::aesgcm::{Aes256Encryption, Purpose};
|
||||
use crate::user;
|
||||
|
||||
type PreId = String;
|
||||
|
||||
pub static CONNECTED_USERS: OnceLock<Mutex<HashMap<PreId, UserKeys>>> = OnceLock::new();
|
||||
|
||||
//extern crate shamir;
|
||||
//use shamir::SecretData;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub enum KeyType {
|
||||
Recover(SpKeys),
|
||||
Revoke(SpKeys),
|
||||
Main(SpKeys),
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct SpKeys {
|
||||
pub scan_key: SecretKey,
|
||||
pub spend_key: SecretKey,
|
||||
}
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub struct UserKeys {
|
||||
pub recover_keys: KeyType,
|
||||
pub revoke_keys: KeyType,
|
||||
pub main_keys: KeyType,
|
||||
pub main: Option<SpClient>,
|
||||
pub recover: SpClient,
|
||||
pub revoke: Option<SpClient>,
|
||||
}
|
||||
|
||||
impl UserKeys {
|
||||
pub fn new(recover_keys: KeyType, revoke_keys: KeyType, main_keys: KeyType) -> Self {
|
||||
UserKeys {
|
||||
recover_keys,
|
||||
revoke_keys,
|
||||
main_keys,
|
||||
pub fn new(main: Option<SpClient>, recover: SpClient, revoke: Option<SpClient>) -> Self {
|
||||
Self {
|
||||
main,
|
||||
recover,
|
||||
revoke,
|
||||
}
|
||||
}
|
||||
pub fn add_keys_recover(scan_key: SecretKey, spend_key: SecretKey) -> KeyType {
|
||||
let sp_keys = SpKeys {
|
||||
scan_key,
|
||||
spend_key,
|
||||
};
|
||||
KeyType::Recover((sp_keys))
|
||||
}
|
||||
pub fn add_keys_revoke(scan_key: SecretKey, spend_key: SecretKey) -> KeyType {
|
||||
let sp_keys = SpKeys {
|
||||
scan_key,
|
||||
spend_key,
|
||||
};
|
||||
KeyType::Revoke((sp_keys))
|
||||
}
|
||||
pub fn add_keys_main(scan_key: SecretKey, spend_key: SecretKey) -> KeyType {
|
||||
let sp_keys = SpKeys {
|
||||
scan_key,
|
||||
spend_key,
|
||||
};
|
||||
KeyType::Main((sp_keys))
|
||||
}
|
||||
|
||||
pub fn get_keys(&self, key_type: KeyType) -> SpKeys {
|
||||
match key_type {
|
||||
KeyType::Recover(keys) => keys,
|
||||
KeyType::Revoke(keys) => keys,
|
||||
KeyType::Main(keys) => keys,
|
||||
}
|
||||
pub fn try_get_revoke(&self) -> Option<&SpClient> {
|
||||
self.revoke.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Clone, Tsify)]
|
||||
#[tsify(into_wasm_abi, from_wasm_abi)]
|
||||
pub struct User {
|
||||
pre_id: String,
|
||||
process: String,
|
||||
pub pre_id: String,
|
||||
pub process: String,
|
||||
recover_data: Vec<u8>,
|
||||
revoke_data: Option<Vec<u8>>,
|
||||
sharding: Sharding,
|
||||
//recovered_spend_key: Option<String>,
|
||||
//recovered_scan_key: Option<String>,
|
||||
}
|
||||
|
||||
impl User {
|
||||
pub fn new(
|
||||
user_keys: UserKeys,
|
||||
user_password: String,
|
||||
process: String
|
||||
) -> Result<Self> {
|
||||
pub fn new(user_keys: UserKeys, user_password: String, process: String) -> Result<Self> {
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// image revoke
|
||||
// We just take the 2 revoke keys
|
||||
let revoke_scan_key = user_keys.get_keys(user_keys.revoke_keys.clone()).scan_key;
|
||||
let revoke_spend_key = user_keys.get_keys(user_keys.revoke_keys.clone()).spend_key;
|
||||
|
||||
let mut revoke_data = Vec::with_capacity(64);
|
||||
revoke_data.extend_from_slice(revoke_scan_key.as_ref());
|
||||
revoke_data.extend_from_slice(revoke_spend_key.as_ref());
|
||||
if let Some(revoke) = user_keys.try_get_revoke() {
|
||||
revoke_data.extend_from_slice(revoke.get_scan_key().as_ref());
|
||||
revoke_data.extend_from_slice(revoke.try_get_secret_spend_key()?.as_ref());
|
||||
} else {
|
||||
return Err(Error::msg("No revoke wallet available"));
|
||||
}
|
||||
|
||||
// Take the 2 recover keys
|
||||
let recover_scan_key = user_keys.get_keys(user_keys.recover_keys.clone()).scan_key;
|
||||
let recover_spend_key = user_keys.get_keys(user_keys.recover_keys.clone()).spend_key;
|
||||
// split recover spend key
|
||||
let recover_spend_key = user_keys.recover.try_get_secret_spend_key()?.clone();
|
||||
let (part1_key, part2_key) = recover_spend_key.as_ref().split_at(SECRET_KEY_SIZE / 2);
|
||||
let mut recover_data = Vec::<u8>::with_capacity(180); // 32 * 3 + (12+16)*3
|
||||
|
||||
@ -158,6 +122,9 @@ impl User {
|
||||
|
||||
recover_data.extend_from_slice(&cipher_recover_part1);
|
||||
|
||||
//Pre ID
|
||||
let pre_id: PreId = Self::compute_pre_id(&user_password, &cipher_recover_part1);
|
||||
|
||||
// encrypt the part 2 of the key
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&user_password.as_bytes());
|
||||
@ -178,12 +145,6 @@ impl User {
|
||||
//create shardings
|
||||
let sharding = Sharding::new(&cipher_recover_part2.to_lower_hex_string(), 10u8); //nMembers = 10 for testing, need to recover nmember elsewhere
|
||||
|
||||
//Pre ID
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&user_password.as_bytes());
|
||||
engine.write_all(&cipher_recover_part1);
|
||||
let pre_id = sha256::Hash::from_engine(engine);
|
||||
|
||||
//scan key:
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&user_password.as_bytes());
|
||||
@ -192,7 +153,7 @@ impl User {
|
||||
|
||||
let scan_key_encryption = Aes256Encryption::import_key(
|
||||
Purpose::ThirtyTwoBytes,
|
||||
recover_scan_key.secret_bytes().to_vec(),
|
||||
user_keys.recover.get_scan_key().secret_bytes().to_vec(),
|
||||
hash3.to_byte_array(),
|
||||
Aes256Gcm::generate_nonce(&mut rng).into(),
|
||||
)?;
|
||||
@ -214,28 +175,58 @@ impl User {
|
||||
recover_data,
|
||||
revoke_data: Some(revoke_data),
|
||||
sharding,
|
||||
//recovered_spend_key: None,
|
||||
//recovered_scan_key: None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn login(&self,user_password: String, recover_data: &[u8], sharding: Sharding) -> Result<()> {
|
||||
pub fn login(
|
||||
pre_id: PreId,
|
||||
user_password: String,
|
||||
recover_data: &[u8],
|
||||
sharding: Sharding,
|
||||
) -> Result<()> {
|
||||
let mut retrieved_spend_key = [0u8; 32];
|
||||
let mut retrieved_scan_key = [0u8; 32];
|
||||
let mut entropy1 = [0u8; 32];
|
||||
let mut entropy2 = [0u8; 32];
|
||||
let mut entropy3 = [0u8; 32];
|
||||
let mut cipher_scan_key = Vec::with_capacity(32);
|
||||
let mut part1_ciphertext = Vec::with_capacity(32); // just a guess
|
||||
let mut cipher_scan_key = [0u8; 60];
|
||||
let mut part1_ciphertext = [0u8; 44];
|
||||
|
||||
let mut reader = recover_data.reader();
|
||||
reader.read_exact(&mut entropy1)?;
|
||||
reader.read_exact(&mut entropy2)?;
|
||||
reader.read_exact(&mut entropy3)?;
|
||||
reader.read_exact(&mut part1_ciphertext)?;
|
||||
reader.read_to_end(&mut cipher_scan_key)?;
|
||||
reader.read_exact(&mut cipher_scan_key)?;
|
||||
|
||||
retrieved_spend_key[..16].copy_from_slice(&Self::recover_key_slice(&user_password, &entropy1, part1_ciphertext)?);
|
||||
// We can retrieve the pre_id and check that it matches
|
||||
let retrieved_pre_id = Self::compute_pre_id(&user_password, &part1_ciphertext);
|
||||
|
||||
// If pre_id is not the same, password is probably false, or the client is feeding us garbage
|
||||
if retrieved_pre_id != pre_id {
|
||||
return Err(Error::msg("pre_id and recover_data don't match"));
|
||||
}
|
||||
|
||||
// If we already have loaded a user with this pre_id, abort
|
||||
if let Some(current_users) = CONNECTED_USERS.get() {
|
||||
if current_users
|
||||
.to_owned()
|
||||
.lock()
|
||||
.unwrap()
|
||||
.contains_key(&pre_id)
|
||||
{
|
||||
return Err(Error::msg(format!(
|
||||
"User with pre_id {} already logged in",
|
||||
pre_id
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
retrieved_spend_key[..16].copy_from_slice(&Self::recover_part1(
|
||||
&user_password,
|
||||
&entropy1,
|
||||
part1_ciphertext.to_vec(),
|
||||
)?);
|
||||
|
||||
//@todo: get shardings from member managers!
|
||||
let shardings = sharding.shares_vec.clone(); // temporary
|
||||
@ -246,33 +237,79 @@ impl User {
|
||||
shardings,
|
||||
)?);
|
||||
|
||||
retrieved_scan_key[..32].copy_from_slice(&Self::recover_key_slice(&user_password, &entropy3, cipher_scan_key)?);;
|
||||
retrieved_scan_key.copy_from_slice(&Self::recover_key_slice(
|
||||
&user_password,
|
||||
&entropy3,
|
||||
cipher_scan_key.to_vec(),
|
||||
)?);
|
||||
|
||||
//@todo: retrieved_scan_key and retrieved_spend_key should be stored somewhere!
|
||||
// we can create the recover sp_client
|
||||
let recover_client = SpClient::new(
|
||||
"".to_owned(),
|
||||
SecretKey::from_slice(&retrieved_scan_key)?,
|
||||
SpendKey::Secret(SecretKey::from_slice(&retrieved_spend_key)?),
|
||||
None,
|
||||
true,
|
||||
)?;
|
||||
|
||||
// Adding user to CONNECTED_USERS
|
||||
if let Some(current_users) = CONNECTED_USERS.get() {
|
||||
let mut lock = current_users.to_owned().lock().unwrap();
|
||||
if lock.contains_key(&pre_id) {
|
||||
return Err(Error::msg(format!(
|
||||
"User with pre_id {} already exists",
|
||||
pre_id
|
||||
)));
|
||||
} else {
|
||||
lock.insert(pre_id.clone(), UserKeys::new(None, recover_client, None));
|
||||
}
|
||||
} else {
|
||||
let mut user_map = HashMap::new();
|
||||
user_map.insert(pre_id, UserKeys::new(None, recover_client, None));
|
||||
let new_value = Mutex::new(user_map);
|
||||
if let Err(error) = CONNECTED_USERS.set(new_value) {
|
||||
return Err(Error::msg(
|
||||
"Failed to set the CONNECTED_USERS static variable",
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn recover_key_slice(
|
||||
password: &str,
|
||||
entropy: &[u8],
|
||||
ciphertext: Vec<u8>,
|
||||
) -> Result<Vec<u8>> {
|
||||
fn recover_key_slice(password: &str, entropy: &[u8], ciphertext: Vec<u8>) -> Result<Vec<u8>> {
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&password.as_bytes());
|
||||
engine.write_all(&entropy);
|
||||
let hash = sha256::Hash::from_engine(engine);
|
||||
|
||||
let aes_dec = Aes256Decryption::new(Purpose::Login, ciphertext, hash.to_byte_array().to_vec(), None)?;
|
||||
let aes_dec = Aes256Decryption::new(
|
||||
Purpose::ThirtyTwoBytes,
|
||||
ciphertext,
|
||||
hash.to_byte_array().to_vec(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
aes_dec.decrypt_with_key()
|
||||
}
|
||||
|
||||
fn recover_part2(
|
||||
password: &str,
|
||||
entropy: &[u8],
|
||||
shares_vec: Vec<Vec<u8>>,
|
||||
) -> Result<Vec<u8>> {
|
||||
fn recover_part1(password: &str, entropy: &[u8], ciphertext: Vec<u8>) -> Result<Vec<u8>> {
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&password.as_bytes());
|
||||
engine.write_all(&entropy);
|
||||
let hash = sha256::Hash::from_engine(engine);
|
||||
|
||||
let aes_dec = Aes256Decryption::new(
|
||||
Purpose::Login,
|
||||
ciphertext,
|
||||
hash.to_byte_array().to_vec(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
aes_dec.decrypt_with_key()
|
||||
}
|
||||
|
||||
fn recover_part2(password: &str, entropy: &[u8], shares_vec: Vec<Vec<u8>>) -> Result<Vec<u8>> {
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&password.as_bytes());
|
||||
engine.write_all(&entropy);
|
||||
@ -286,11 +323,25 @@ impl User {
|
||||
.ok_or_else(|| anyhow::Error::msg("Failed to retrieve the sharded secret"))?,
|
||||
)?;
|
||||
|
||||
let aes_dec = Aes256Decryption::new(Purpose::Login, part2_key_enc, hash.to_byte_array().to_vec(), None)?;
|
||||
let aes_dec = Aes256Decryption::new(
|
||||
Purpose::Login,
|
||||
part2_key_enc,
|
||||
hash.to_byte_array().to_vec(),
|
||||
None,
|
||||
)?;
|
||||
|
||||
aes_dec.decrypt_with_key()
|
||||
}
|
||||
|
||||
fn compute_pre_id(user_password: &str, cipher_recover_part1: &[u8]) -> PreId {
|
||||
let mut engine = sha256::HashEngine::default();
|
||||
engine.write_all(&user_password.as_bytes());
|
||||
engine.write_all(&cipher_recover_part1);
|
||||
let pre_id = sha256::Hash::from_engine(engine);
|
||||
|
||||
pre_id.to_string()
|
||||
}
|
||||
|
||||
//not used
|
||||
// pub fn pbkdf2(password: &str, data: &str) -> String {
|
||||
// let data_salt = data.trim_end_matches('=');
|
||||
@ -439,25 +490,56 @@ pub fn read_exif(image: &[u8]) -> Result<Vec<u8>, String> {
|
||||
// let base64_string = base64::encode(decoded_data);
|
||||
// base64_string
|
||||
// }
|
||||
/*
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*; // Import everything from the outer module
|
||||
|
||||
const RECOVER_SPEND: &str = "394ef7757f5bc8cd692337c62abf6fa0ce9932fd4ec6676daddfbe3c1b3b9d11";
|
||||
const RECOVER_SCAN: &str = "3aa8cc570d17ec3a4dc4136e50151cc6de26052d968abfe02a5fea724ce38205";
|
||||
const REVOKE_SPEND: &str = "821c1a84fa9ee718c02005505fb8315bd479c7b9a878b1eff45929c48dfcaf28";
|
||||
const REVOKE_SCAN: &str = "a0f36cbc380624fa7eef022f39cab2716333451649dd8eb78e86d2e76bdb3f47";
|
||||
const MAIN_SPEND: &str = "b9098a6598ac55d8dd0e6b7aab0d1f63eb8792d06143f3c0fb6f5b80476a1c0d";
|
||||
const MAIN_SCAN: &str = "79dda4031663ac2cb250c46d896dc92b3c027a48a761b2342fabf1e441ea2857";
|
||||
const USER_PASSWORD: &str = "correct horse battery staple";
|
||||
const PROCESS: &str = "example";
|
||||
|
||||
fn helper_create_user_keys() -> UserKeys {
|
||||
let label = "default".to_owned();
|
||||
let sp_main = SpClient::new(
|
||||
label.clone(),
|
||||
SecretKey::from_str(MAIN_SCAN).unwrap(),
|
||||
SpendKey::Secret(SecretKey::from_str(MAIN_SPEND).unwrap()),
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let sp_recover = SpClient::new(
|
||||
label.clone(),
|
||||
SecretKey::from_str(RECOVER_SCAN).unwrap(),
|
||||
SpendKey::Secret(SecretKey::from_str(RECOVER_SPEND).unwrap()),
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let sp_revoke = SpClient::new(
|
||||
label.clone(),
|
||||
SecretKey::from_str(REVOKE_SCAN).unwrap(),
|
||||
SpendKey::Secret(SecretKey::from_str(REVOKE_SPEND).unwrap()),
|
||||
None,
|
||||
true,
|
||||
)
|
||||
.unwrap();
|
||||
let user_keys = UserKeys::new(Some(sp_main), sp_recover, Some(sp_revoke));
|
||||
|
||||
user_keys
|
||||
}
|
||||
|
||||
// Test 1: Create User
|
||||
#[test]
|
||||
fn test_successful_creation() {
|
||||
let result = User::new(
|
||||
SecretKey::from_str(RECOVER_SPEND).unwrap(),
|
||||
SecretKey::from_str(REVOKE_SPEND).unwrap(),
|
||||
SecretKey::from_str(REVOKE_SCAN).unwrap(),
|
||||
USER_PASSWORD.to_owned(),
|
||||
);
|
||||
let user_keys = helper_create_user_keys();
|
||||
let result = User::new(user_keys, USER_PASSWORD.to_owned(), PROCESS.to_owned());
|
||||
|
||||
assert!(result.is_ok());
|
||||
let user = result.unwrap();
|
||||
@ -465,20 +547,31 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_login() {
|
||||
let user = User::new(
|
||||
SecretKey::from_str(RECOVER_SPEND).unwrap(),
|
||||
SecretKey::from_str(REVOKE_SPEND).unwrap(),
|
||||
SecretKey::from_str(REVOKE_SCAN).unwrap(),
|
||||
USER_PASSWORD.to_owned(),
|
||||
).unwrap();
|
||||
let user_keys = helper_create_user_keys();
|
||||
let user = User::new(user_keys, USER_PASSWORD.to_owned(), PROCESS.to_owned()).unwrap();
|
||||
|
||||
let pre_id = user.pre_id;
|
||||
let recover_data = user.recover_data;
|
||||
let sharding = user.sharding;
|
||||
|
||||
let retrieved_recover_spend = User::login(USER_PASSWORD.to_owned(), &recover_data, sharding);
|
||||
let retrieved_recover_spend = User::login(
|
||||
pre_id.clone(),
|
||||
USER_PASSWORD.to_owned(),
|
||||
&recover_data,
|
||||
sharding,
|
||||
);
|
||||
|
||||
assert!(retrieved_recover_spend.is_ok());
|
||||
|
||||
assert!(format!("{}", retrieved_recover_spend.unwrap().display_secret()) == RECOVER_SPEND)
|
||||
let connected = CONNECTED_USERS.get().unwrap().lock().unwrap();
|
||||
|
||||
let recover = &connected.get(&pre_id).unwrap().recover;
|
||||
|
||||
assert!(
|
||||
format!(
|
||||
"{}",
|
||||
recover.try_get_secret_spend_key().unwrap().display_secret()
|
||||
) == RECOVER_SPEND
|
||||
)
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user