ws mono user

This commit is contained in:
Sosthene 2024-04-22 11:52:57 +02:00
parent 5cddf0566a
commit 26bf0c0865
3 changed files with 146 additions and 107 deletions

View File

@ -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()

View File

@ -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"));

View File

@ -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!(