ws mono user
This commit is contained in:
parent
5cddf0566a
commit
26bf0c0865
@ -33,7 +33,7 @@ use crate::images;
|
||||
use crate::silentpayments::{
|
||||
check_transaction, create_transaction_for_address_with_shared_secret, ScannedTransaction,
|
||||
};
|
||||
use crate::user::{lock_connected_users, User, UserWallets, CONNECTED_USERS};
|
||||
use crate::user::{lock_connected_user, User, UserWallets, CONNECTED_USER};
|
||||
|
||||
use crate::process::Process;
|
||||
|
||||
@ -141,9 +141,20 @@ pub fn generate_sp_wallet(
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn get_receiving_address(pre_id: String) -> ApiResult<String> {
|
||||
if let Some(my_wallets) = lock_connected_users()?.get(&pre_id) {
|
||||
Ok(my_wallets.recover.get_client().get_receiving_address())
|
||||
pub fn get_recover_address() -> ApiResult<String> {
|
||||
if let Ok(my_wallets) = lock_connected_user() {
|
||||
Ok(my_wallets.try_get_recover()?.get_client().get_receiving_address())
|
||||
} else {
|
||||
Err(ApiError {
|
||||
message: "Unknown user pre_id".to_owned(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn get_main_address() -> ApiResult<String> {
|
||||
if let Ok(my_wallets) = lock_connected_user() {
|
||||
Ok(my_wallets.try_get_main()?.get_client().get_receiving_address())
|
||||
} else {
|
||||
Err(ApiError {
|
||||
message: "Unknown user pre_id".to_owned(),
|
||||
@ -168,7 +179,7 @@ pub fn create_user(
|
||||
|
||||
let user_wallets = UserWallets::new(
|
||||
Some(sp_wallet_main),
|
||||
sp_wallet_recover,
|
||||
Some(sp_wallet_recover),
|
||||
Some(sp_wallet_revoke),
|
||||
);
|
||||
|
||||
@ -176,7 +187,9 @@ pub fn create_user(
|
||||
|
||||
let outputs = user_wallets.get_all_outputs();
|
||||
|
||||
lock_connected_users()?.insert(user.pre_id.clone(), user_wallets);
|
||||
// Setting CONNECTED_USER to user
|
||||
let mut connected_user = lock_connected_user()?;
|
||||
*connected_user = user_wallets;
|
||||
|
||||
let generate_user = createUserReturn {
|
||||
user,
|
||||
@ -359,24 +372,22 @@ pub fn parse_network_msg(raw: String) -> ApiResult<parseNetworkMsgReturn> {
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn get_outpoints_for_user() -> ApiResult<outputs_list> {
|
||||
let connected_users = lock_connected_users()?;
|
||||
let (_, user) = connected_users.iter().last().ok_or(ApiError {
|
||||
message: "Can't find user".to_owned(),
|
||||
})?;
|
||||
Ok(outputs_list(user.get_all_outputs()))
|
||||
let connected_user = lock_connected_user()?;
|
||||
if connected_user.is_not_empty() {
|
||||
Ok(outputs_list(connected_user.get_all_outputs()))
|
||||
} else {
|
||||
Err(ApiError { message: "No user logged in".to_owned() })
|
||||
}
|
||||
}
|
||||
|
||||
#[wasm_bindgen]
|
||||
pub fn is_tx_owned_by_user(pre_id: String, tx: String) -> ApiResult<bool> {
|
||||
let transaction = deserialize::<Transaction>(&Vec::from_hex(&tx)?)?;
|
||||
let txid = transaction.txid();
|
||||
let connected_users = lock_connected_users()?;
|
||||
let user = connected_users.get(&pre_id).ok_or(ApiError {
|
||||
message: "Can't find user".to_owned(),
|
||||
})?;
|
||||
let connected_user = lock_connected_user()?;
|
||||
|
||||
if let Some(_) = user
|
||||
.recover
|
||||
if let Some(_) = connected_user
|
||||
.try_get_recover()?
|
||||
.get_outputs()
|
||||
.to_outpoints_list()
|
||||
.iter()
|
||||
|
@ -27,7 +27,7 @@ use sp_client::{
|
||||
};
|
||||
use tsify::Tsify;
|
||||
|
||||
use crate::user::{lock_connected_users, CONNECTED_USERS};
|
||||
use crate::user::{lock_connected_user, CONNECTED_USER};
|
||||
use crate::MutexExt;
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, Tsify)]
|
||||
@ -94,26 +94,19 @@ pub fn create_transaction_for_address_with_shared_secret(
|
||||
sp_address: SilentPaymentAddress,
|
||||
message: String,
|
||||
) -> Result<(Transaction, SharedSecret)> {
|
||||
let connected_users = lock_connected_users()?;
|
||||
|
||||
let (_, wallets) = connected_users
|
||||
.iter()
|
||||
.last()
|
||||
.ok_or(Error::msg("Unknown sender"))?;
|
||||
|
||||
debug!("Got user wallets");
|
||||
let connected_user = lock_connected_user()?;
|
||||
|
||||
let sp_wallet = if sp_address.is_testnet() {
|
||||
&wallets.recover
|
||||
connected_user.try_get_recover()?
|
||||
} else {
|
||||
if let Some(main) = &wallets.main {
|
||||
if let Ok(main) = connected_user.try_get_main() {
|
||||
main
|
||||
} else {
|
||||
return Err(Error::msg("Can't spend on mainnet"));
|
||||
}
|
||||
};
|
||||
|
||||
let available_outpoints = wallets.recover.get_outputs().to_spendable_list();
|
||||
let available_outpoints = sp_wallet.get_outputs().to_spendable_list();
|
||||
|
||||
// Here we need to add more heuristics about which outpoint we spend
|
||||
// For now let's keep it simple
|
||||
@ -205,27 +198,19 @@ pub fn check_transaction(
|
||||
return Err(Error::msg(err_msg));
|
||||
}
|
||||
|
||||
let connected_users = lock_connected_users()?;
|
||||
let mut connected_user = lock_connected_user()?;
|
||||
|
||||
let txid = tx.txid().to_string();
|
||||
// Check the transaction for all connected users
|
||||
for (pre_id, keys) in connected_users.clone() {
|
||||
let mut recover = keys.recover;
|
||||
if recover.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
|
||||
return Ok(txid);
|
||||
}
|
||||
if connected_user.try_get_mut_recover()?.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
|
||||
return Ok(txid);
|
||||
}
|
||||
|
||||
if let Some(mut main) = keys.main {
|
||||
if main.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
|
||||
return Ok(txid);
|
||||
}
|
||||
}
|
||||
if connected_user.try_get_mut_main()?.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
|
||||
return Ok(txid);
|
||||
}
|
||||
|
||||
if let Some(mut revoke) = keys.revoke {
|
||||
if revoke.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
|
||||
return Ok(txid);
|
||||
}
|
||||
}
|
||||
if connected_user.try_get_mut_revoke()?.update_wallet_with_transaction(tx, blockheight, tweak_data)? > 0 {
|
||||
return Ok(txid);
|
||||
}
|
||||
|
||||
return Err(Error::msg("No new outputs found"));
|
||||
|
@ -36,24 +36,23 @@ type PreId = String;
|
||||
const MANAGERS_NUMBER: u8 = 10;
|
||||
const QUORUM_SHARD: f32 = 0.8;
|
||||
|
||||
type UsersMap = HashMap<PreId, UserWallets>;
|
||||
pub static CONNECTED_USERS: OnceLock<Mutex<UsersMap>> = OnceLock::new();
|
||||
pub static CONNECTED_USER: OnceLock<Mutex<UserWallets>> = OnceLock::new();
|
||||
|
||||
pub fn lock_connected_users() -> Result<MutexGuard<'static, UsersMap>> {
|
||||
CONNECTED_USERS
|
||||
.get_or_init(|| Mutex::new(HashMap::new()))
|
||||
pub fn lock_connected_user() -> Result<MutexGuard<'static, UserWallets>> {
|
||||
CONNECTED_USER
|
||||
.get_or_init(|| Mutex::new(UserWallets::default()))
|
||||
.lock_anyhow()
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
|
||||
pub struct UserWallets {
|
||||
pub main: Option<SpWallet>,
|
||||
pub recover: SpWallet,
|
||||
pub revoke: Option<SpWallet>,
|
||||
main: Option<SpWallet>,
|
||||
recover: Option<SpWallet>,
|
||||
revoke: Option<SpWallet>,
|
||||
}
|
||||
|
||||
impl UserWallets {
|
||||
pub fn new(main: Option<SpWallet>, recover: SpWallet, revoke: Option<SpWallet>) -> Self {
|
||||
pub fn new(main: Option<SpWallet>, recover: Option<SpWallet>, revoke: Option<SpWallet>) -> Self {
|
||||
Self {
|
||||
main,
|
||||
recover,
|
||||
@ -61,8 +60,56 @@ impl UserWallets {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_revoke(&self) -> Option<&SpWallet> {
|
||||
self.revoke.as_ref()
|
||||
pub fn try_get_revoke(&self) -> Result<&SpWallet> {
|
||||
if let Some(revoke) = &self.revoke {
|
||||
Ok(revoke)
|
||||
} else {
|
||||
Err(Error::msg("No revoke wallet available"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_recover(&self) -> Result<&SpWallet> {
|
||||
if let Some(recover) = &self.recover {
|
||||
Ok(recover)
|
||||
} else {
|
||||
Err(Error::msg("No recover wallet available"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_main(&self) -> Result<&SpWallet> {
|
||||
if let Some(main) = &self.main {
|
||||
Ok(main)
|
||||
} else {
|
||||
Err(Error::msg("No main wallet available"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_mut_revoke(&mut self) -> Result<&mut SpWallet> {
|
||||
if let Some(revoke) = &mut self.revoke {
|
||||
Ok(revoke)
|
||||
} else {
|
||||
Err(Error::msg("No revoke wallet available"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_mut_recover(&mut self) -> Result<&mut SpWallet> {
|
||||
if let Some(recover) = &mut self.recover {
|
||||
Ok(recover)
|
||||
} else {
|
||||
Err(Error::msg("No recover wallet available"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn try_get_mut_main(&mut self) -> Result<&mut SpWallet> {
|
||||
if let Some(main) = &mut self.main {
|
||||
Ok(main)
|
||||
} else {
|
||||
Err(Error::msg("No main wallet available"))
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_not_empty(&self) -> bool {
|
||||
self.get_all_outputs().len() > 0
|
||||
}
|
||||
|
||||
pub(crate) fn get_all_outputs(&self) -> Vec<OutputList> {
|
||||
@ -73,7 +120,9 @@ impl UserWallets {
|
||||
if let Some(revoke) = &self.revoke {
|
||||
res.push(revoke.get_outputs().clone());
|
||||
}
|
||||
res.push(self.recover.get_outputs().clone());
|
||||
if let Some(recover) = &self.recover {
|
||||
res.push(recover.get_outputs().clone());
|
||||
}
|
||||
|
||||
res
|
||||
}
|
||||
@ -93,22 +142,24 @@ pub struct User {
|
||||
|
||||
impl User {
|
||||
pub fn new(user_wallets: UserWallets, user_password: String, process: String) -> Result<Self> {
|
||||
// if we are already logged in, abort
|
||||
if lock_connected_user()?.is_not_empty() {
|
||||
return Err(Error::msg("User already logged in"));
|
||||
}
|
||||
|
||||
let mut rng = thread_rng();
|
||||
|
||||
// image revoke
|
||||
// We just take the 2 revoke keys
|
||||
let mut revoke_data = Vec::with_capacity(64);
|
||||
if let Some(revoke) = user_wallets.try_get_revoke() {
|
||||
revoke_data.extend_from_slice(revoke.get_client().get_scan_key().as_ref());
|
||||
revoke_data.extend_from_slice(revoke.get_client().try_get_secret_spend_key()?.as_ref());
|
||||
} else {
|
||||
return Err(Error::msg("No revoke wallet available"));
|
||||
}
|
||||
let revoke = user_wallets.try_get_revoke()?;
|
||||
revoke_data.extend_from_slice(revoke.get_client().get_scan_key().as_ref());
|
||||
revoke_data.extend_from_slice(revoke.get_client().try_get_secret_spend_key()?.as_ref());
|
||||
|
||||
// Take the 2 recover keys
|
||||
// split recover spend key
|
||||
let recover_spend_key = user_wallets
|
||||
.recover
|
||||
.try_get_recover()?
|
||||
.get_client()
|
||||
.try_get_secret_spend_key()?
|
||||
.clone();
|
||||
@ -186,7 +237,7 @@ impl User {
|
||||
let scan_key_encryption = Aes256Encryption::import_key(
|
||||
Purpose::ThirtyTwoBytes,
|
||||
user_wallets
|
||||
.recover
|
||||
.try_get_recover()?
|
||||
.get_client()
|
||||
.get_scan_key()
|
||||
.secret_bytes()
|
||||
@ -200,6 +251,8 @@ impl User {
|
||||
|
||||
recover_data.extend_from_slice(&cipher_scan_key);
|
||||
|
||||
let all_outputs = user_wallets.get_all_outputs();
|
||||
|
||||
Ok(User {
|
||||
pre_id: pre_id.to_string(),
|
||||
processes: vec![process],
|
||||
@ -207,10 +260,19 @@ impl User {
|
||||
recover_data,
|
||||
revoke_data: Some(revoke_data),
|
||||
shares,
|
||||
outputs: user_wallets.get_all_outputs(),
|
||||
outputs: all_outputs,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn logout() -> Result<()> {
|
||||
if let Ok(mut user) = lock_connected_user() {
|
||||
*user = UserWallets::default();
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::msg("Failed to lock CONNECTED_USER"))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn login(
|
||||
pre_id: PreId,
|
||||
user_password: String,
|
||||
@ -218,6 +280,11 @@ impl User {
|
||||
shares: &[Vec<u8>],
|
||||
outputs: &[OutputList],
|
||||
) -> Result<()> {
|
||||
// if we are already logged in, abort
|
||||
if lock_connected_user()?.is_not_empty() {
|
||||
return Err(Error::msg("User already logged in"));
|
||||
}
|
||||
|
||||
let mut retrieved_spend_key = [0u8; 32];
|
||||
let mut retrieved_scan_key = [0u8; 32];
|
||||
let mut entropy1 = [0u8; 32];
|
||||
@ -241,21 +308,6 @@ impl User {
|
||||
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,
|
||||
@ -290,26 +342,12 @@ impl User {
|
||||
|
||||
let recover_wallet = SpWallet::new(recover_client, recover_outputs)?;
|
||||
|
||||
// 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(), UserWallets::new(None, recover_wallet, None));
|
||||
}
|
||||
let user_wallets = UserWallets::new(None, Some(recover_wallet), None);
|
||||
|
||||
if let Ok(mut user) = lock_connected_user() {
|
||||
*user = user_wallets;
|
||||
} else {
|
||||
let mut user_map = HashMap::new();
|
||||
user_map.insert(pre_id, UserWallets::new(None, recover_wallet, 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",
|
||||
));
|
||||
}
|
||||
return Err(Error::msg("Failed to lock CONNECTED_USER"));
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -456,21 +494,26 @@ mod tests {
|
||||
.unwrap();
|
||||
let user_wallets = UserWallets::new(
|
||||
Some(SpWallet::new(sp_main, None).unwrap()),
|
||||
SpWallet::new(sp_recover, None).unwrap(),
|
||||
Some(SpWallet::new(sp_recover, None).unwrap()),
|
||||
Some(SpWallet::new(sp_revoke, None).unwrap()),
|
||||
);
|
||||
|
||||
user_wallets
|
||||
}
|
||||
|
||||
// Test 1: Create User
|
||||
#[test]
|
||||
fn test_successful_creation() {
|
||||
let user_wallets = helper_create_user_wallets();
|
||||
let result = User::new(user_wallets, USER_PASSWORD.to_owned(), PROCESS.to_owned());
|
||||
|
||||
assert!(result.is_ok());
|
||||
let user = result.unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_logout() {
|
||||
let res = User::logout();
|
||||
|
||||
assert!(res.is_ok());
|
||||
}
|
||||
|
||||
#[test]
|
||||
@ -493,9 +536,9 @@ mod tests {
|
||||
|
||||
assert!(res.is_ok());
|
||||
|
||||
let connected = CONNECTED_USERS.get().unwrap().lock().unwrap();
|
||||
let connected = lock_connected_user().unwrap();
|
||||
|
||||
let recover = &connected.get(&user.pre_id).unwrap().recover;
|
||||
let recover = connected.try_get_recover().unwrap();
|
||||
|
||||
assert!(
|
||||
format!(
|
||||
|
Loading…
x
Reference in New Issue
Block a user