From 3bfce128a6ef1897a4142afbecb09e7141247f62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Mon, 16 May 2022 23:39:08 +0200 Subject: [PATCH 01/11] wallet: store id instead of mnemonic in state --- CHANGELOG.md | 1 + Cargo.lock | 1 + nym-wallet/src-tauri/src/main.rs | 3 +- .../src/operations/mixnet/account.rs | 116 ++++++++++++------ nym-wallet/src-tauri/src/state.rs | 14 ++- 5 files changed, 93 insertions(+), 42 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e2e4b58981..c7824f88ab 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Added +- wallet: require password to switch accounts - wallet: added support for multiple accounts ([#1265]) - wallet: the wallet backend learned how to keep track of validator name, either hardcoded or by querying the status endpoint. - mixnet-contract: Replace all naked `-` with `saturating_sub`. diff --git a/Cargo.lock b/Cargo.lock index 225174005d..5f2b2e0634 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3178,6 +3178,7 @@ dependencies = [ "proxy-helpers", "publicsuffix", "rand 0.7.3", + "rocket", "serde", "socks5-requests", "sqlx", diff --git a/nym-wallet/src-tauri/src/main.rs b/nym-wallet/src-tauri/src/main.rs index 1fd7a69817..cb49a3974a 100644 --- a/nym-wallet/src-tauri/src/main.rs +++ b/nym-wallet/src-tauri/src/main.rs @@ -43,13 +43,12 @@ fn main() { mixnet::account::does_password_file_exist, mixnet::account::get_balance, mixnet::account::list_accounts, - mixnet::account::sign_in_decrypted_account, mixnet::account::logout, mixnet::account::remove_account_for_password, mixnet::account::remove_password, mixnet::account::show_mnemonic_for_account_in_password, - mixnet::account::sign_in_decrypted_account, mixnet::account::sign_in_with_password, + mixnet::account::sign_in_with_password_and_account_id, mixnet::account::switch_network, mixnet::account::validate_mnemonic, mixnet::admin::get_contract_settings, diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index c2b4e1eff8..79a9f2ddb0 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -4,7 +4,7 @@ use crate::error::BackendError; use crate::network::Network as WalletNetwork; use crate::network_config; use crate::nymd_client; -use crate::state::State; +use crate::state::{State, WalletAccountIds}; use crate::wallet_storage::{self, DEFAULT_LOGIN_ID}; use bip39::{Language, Mnemonic}; @@ -229,6 +229,10 @@ async fn _connect_with_mnemonic( }; // Register all the clients + { + let mut w_state = state.write().await; + w_state.logout(); + } for client in clients { let network: WalletNetwork = client.network.into(); let mut w_state = state.write().await; @@ -395,9 +399,9 @@ pub async fn sign_in_with_password( } fn extract_first_mnemonic( - stored_account: &wallet_storage::StoredLogin, + stored_login: &wallet_storage::StoredLogin, ) -> Result { - let mnemonic = match stored_account { + let mnemonic = match stored_login { wallet_storage::StoredLogin::Mnemonic(ref account) => account.mnemonic().clone(), wallet_storage::StoredLogin::Multiple(ref accounts) => { // Login using the first account in the list @@ -413,6 +417,44 @@ fn extract_first_mnemonic( Ok(mnemonic) } +#[tauri::command] +pub async fn sign_in_with_password_and_account_id( + account_id: &str, + password: &str, + state: tauri::State<'_, Arc>>, +) -> Result { + log::info!("Signing in with password"); + + // Currently we only support a single, default, id in the wallet + let login_id = wallet_storage::LoginId::new(DEFAULT_LOGIN_ID.to_string()); + let account_id = wallet_storage::AccountId::new(account_id.to_string()); + let password = wallet_storage::UserPassword::new(password.to_string()); + let stored_login = wallet_storage::load_existing_login(&login_id, &password)?; + + let mnemonic = extract_mnemonic(&stored_login, &account_id)?; + let first_login_id_when_converting = login_id.into(); + set_state_with_all_accounts(stored_login, first_login_id_when_converting, state.clone()).await?; + + _connect_with_mnemonic(mnemonic, state).await +} + +fn extract_mnemonic( + stored_login: &wallet_storage::StoredLogin, + account_id: &wallet_storage::AccountId, +) -> Result { + let mnemonic = match stored_login { + wallet_storage::StoredLogin::Mnemonic(_) => { + return Err(BackendError::WalletNoSuchAccountIdInWalletLogin); + } + wallet_storage::StoredLogin::Multiple(ref accounts) => accounts + .get_account(account_id) + .ok_or(BackendError::WalletNoSuchAccountIdInWalletLogin)? + .mnemonic() + .clone(), + }; + Ok(mnemonic) +} + #[tauri::command] pub fn remove_password() -> Result<(), BackendError> { log::info!("Removing password"); @@ -479,8 +521,28 @@ async fn set_state_with_all_accounts( log::trace!("account: {:?}", account); } + let all_account_ids: Vec = all_accounts + .iter() + .map(|account| { + let mnemonic = account.mnemonic(); + let addresses: HashMap = WalletNetwork::iter() + .map(|network| { + let config_network: Network = network.into(); + ( + network, + derive_address(mnemonic.clone(), config_network.bech32_prefix()).unwrap(), + ) + }) + .collect(); + WalletAccountIds { + id: account.id().clone(), + addresses, + } + }) + .collect(); + let mut w_state = state.write().await; - w_state.set_all_accounts(all_accounts); + w_state.set_all_accounts(all_account_ids); Ok(()) } @@ -523,16 +585,13 @@ pub async fn list_accounts( ) -> Result, BackendError> { log::trace!("Listing accounts"); let state = state.read().await; - let network: Network = state.current_network().into(); - let prefix = network.bech32_prefix(); + let network = state.current_network(); let all_accounts = state .get_all_accounts() .map(|account| AccountEntry { - id: account.id().to_string(), - address: derive_address(account.mnemonic().clone(), prefix) - .unwrap() - .to_string(), + id: account.id.to_string(), + address: account.addresses[&network].to_string(), }) .map(|account| { log::trace!("{:?}", account); @@ -552,8 +611,16 @@ pub fn show_mnemonic_for_account_in_password( let login_id = wallet_storage::LoginId::new(DEFAULT_LOGIN_ID.to_string()); let account_id = wallet_storage::AccountId::new(account_id); let password = wallet_storage::UserPassword::new(password); - let stored_account = wallet_storage::load_existing_login(&login_id, &password)?; + let mnemonic = _show_mnemonic_for_account_in_password(&login_id, &account_id, &password)?; + Ok(mnemonic.to_string()) +} +fn _show_mnemonic_for_account_in_password( + login_id: &wallet_storage::LoginId, + account_id: &wallet_storage::AccountId, + password: &wallet_storage::UserPassword, +) -> Result { + let stored_account = wallet_storage::load_existing_login(login_id, password)?; let mnemonic = match stored_account { wallet_storage::StoredLogin::Mnemonic(ref account) => account.mnemonic().clone(), wallet_storage::StoredLogin::Multiple(ref accounts) => { @@ -561,36 +628,13 @@ pub fn show_mnemonic_for_account_in_password( log::debug!("{:?}", account); } accounts - .get_account(&account_id) + .get_account(account_id) .ok_or(BackendError::WalletNoSuchAccountIdInWalletLogin)? .mnemonic() .clone() } }; - - Ok(mnemonic.to_string()) -} - -#[tauri::command] -pub async fn sign_in_decrypted_account( - account_id: &str, - state: tauri::State<'_, Arc>>, -) -> Result { - log::info!("Signing in to already decrypted account: {account_id}"); - let mnemonic = { - let state = state.read().await; - let account = &state - .get_all_accounts() - .find(|a| a.id().as_ref() == account_id) - .ok_or(BackendError::WalletNoSuchAccountIdInWalletLogin)?; - account.mnemonic().clone() - }; - - { - state.write().await.logout(); - } - - _connect_with_mnemonic(mnemonic, state).await + Ok(mnemonic) } #[cfg(test)] diff --git a/nym-wallet/src-tauri/src/state.rs b/nym-wallet/src-tauri/src/state.rs index c5d06ef8f4..a94a599a89 100644 --- a/nym-wallet/src-tauri/src/state.rs +++ b/nym-wallet/src-tauri/src/state.rs @@ -1,6 +1,5 @@ use crate::error::BackendError; use crate::network::Network; -use crate::wallet_storage::account_data::WalletAccount; use crate::{config, network_config}; use strum::IntoEnumIterator; @@ -49,7 +48,7 @@ pub struct State { // All the accounts the we get from decrypting the wallet. We hold on to these for being able to // switch accounts on-the-fly - all_accounts: Vec, + all_accounts: Vec, /// Validators that have been fetched dynamically, probably during startup. fetched_validators: config::OptionalValidators, @@ -58,6 +57,13 @@ pub struct State { validator_metadata: HashMap, } +pub(crate) struct WalletAccountIds { + // The wallet account id + pub id: crate::wallet_storage::AccountId, + // The set of corresponding network identities derived from the mnemonic + pub addresses: HashMap, +} + impl State { pub fn client(&self, network: Network) -> Result<&Client, BackendError> { self @@ -117,11 +123,11 @@ impl State { self.current_network } - pub(crate) fn set_all_accounts(&mut self, all_accounts: Vec) { + pub(crate) fn set_all_accounts(&mut self, all_accounts: Vec) { self.all_accounts = all_accounts } - pub(crate) fn get_all_accounts(&self) -> impl Iterator { + pub(crate) fn get_all_accounts(&self) -> impl Iterator { self.all_accounts.iter() } From 967692bf8832c367a63582f3419cfa8b20ec41a8 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:38:06 +0100 Subject: [PATCH 02/11] create confirm password modal --- nym-wallet/src/components/ConfirmPassword.tsx | 47 +++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 nym-wallet/src/components/ConfirmPassword.tsx diff --git a/nym-wallet/src/components/ConfirmPassword.tsx b/nym-wallet/src/components/ConfirmPassword.tsx new file mode 100644 index 0000000000..610ed0d090 --- /dev/null +++ b/nym-wallet/src/components/ConfirmPassword.tsx @@ -0,0 +1,47 @@ +import React, { useState } from 'react'; +import { Button, CircularProgress, DialogActions, DialogContent, Typography } from '@mui/material'; +import { PasswordInput } from './textfields'; + +export const ConfirmPassword = ({ + error, + isLoading, + onConfirm, + buttonTitle, +}: { + error?: string; + isLoading?: boolean; + buttonTitle: string; + onConfirm: (password: string) => void; +}) => { + const [value, setValue] = useState(''); + + return ( + <> + + + {error} + + + setValue(pswrd)} + placeholder="Confirm password" + autoFocus + /> + + + + + + ); +}; From 86a93a71e954d63bfcfdea2f2b11999feec42fc5 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:39:17 +0100 Subject: [PATCH 03/11] relocate modals to their own directory --- .../src/components/Accounts/AccountsModal.tsx | 48 -------- .../Accounts/{ => modals}/AddAccountModal.tsx | 108 ++++++------------ .../{ => modals}/EditAccountModal.tsx | 0 .../{ => modals}/ImportAccountModal.tsx | 0 .../Accounts/{ => modals}/MnemonicModal.tsx | 7 +- 5 files changed, 35 insertions(+), 128 deletions(-) delete mode 100644 nym-wallet/src/components/Accounts/AccountsModal.tsx rename nym-wallet/src/components/Accounts/{ => modals}/AddAccountModal.tsx (74%) rename nym-wallet/src/components/Accounts/{ => modals}/EditAccountModal.tsx (100%) rename nym-wallet/src/components/Accounts/{ => modals}/ImportAccountModal.tsx (100%) rename nym-wallet/src/components/Accounts/{ => modals}/MnemonicModal.tsx (92%) diff --git a/nym-wallet/src/components/Accounts/AccountsModal.tsx b/nym-wallet/src/components/Accounts/AccountsModal.tsx deleted file mode 100644 index 8210b3c562..0000000000 --- a/nym-wallet/src/components/Accounts/AccountsModal.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import React, { useContext } from 'react'; -import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Typography } from '@mui/material'; -import { Add, ArrowDownwardSharp, Close } from '@mui/icons-material'; -import { AccountsContext } from 'src/context'; -import { AccountItem } from './AccountItem'; - -export const AccountsModal = ({ onClose }: { onClose?: () => void }) => { - const { accounts, dialogToDisplay, setDialogToDisplay } = useContext(AccountsContext); - - const handleClose = () => { - setDialogToDisplay(undefined); - onClose?.(); - }; - - return ( - - - - Accounts - - - - - - Switch between accounts - - - - {accounts?.map(({ id, address }) => ( - - ))} - - - - - - - ); -}; diff --git a/nym-wallet/src/components/Accounts/AddAccountModal.tsx b/nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx similarity index 74% rename from nym-wallet/src/components/Accounts/AddAccountModal.tsx rename to nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx index 3f3aec7b62..b7079d906e 100644 --- a/nym-wallet/src/components/Accounts/AddAccountModal.tsx +++ b/nym-wallet/src/components/Accounts/modals/AddAccountModal.tsx @@ -2,24 +2,21 @@ import React, { useContext, useEffect, useState } from 'react'; import { Box, Button, - CircularProgress, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, - Stack, TextField, Typography, } from '@mui/material'; import { ArrowBackSharp } from '@mui/icons-material'; import { useClipboard } from 'use-clipboard-copy'; import { createMnemonic, validateMnemonic } from 'src/requests'; -import { AccountsContext } from 'src/context'; -import { PasswordInput } from 'src/components'; -import { Mnemonic } from '../Mnemonic'; import { Console } from 'src/utils/console'; -import { match } from 'assert'; +import { AccountsContext } from 'src/context'; +import { ConfirmPassword, Mnemonic } from 'src/components'; +import { MnemonicInput } from 'src/components/textfields'; const createAccountSteps = [ 'Copy and save mnemonic for your new account', @@ -66,27 +63,18 @@ const ImportMnemonic = ({ }; return ( - + <> - - {error && ( - - {error} - - )} - { - onChange(e.target.value); - setError(undefined); - }} - fullWidth - type="password" - /> - + + {error} + + { + onChange(mnemon); + setError(undefined); + }} + /> - - ); -}; - -const ConfirmPassword = ({ onConfirm }: { onConfirm: (password: string) => void }) => { - const [value, setValue] = useState(''); - const { isLoading, error } = useContext(AccountsContext); - - return ( - - - {error && ( - - {error} - - )} - setValue(pswrd)} - label="Confirm password" - autoFocus - /> - - - - - + ); }; @@ -191,24 +143,25 @@ export const AddAccountModal = () => { accountName: '', }); - const { dialogToDisplay, setDialogToDisplay, handleAddAccount, setError } = useContext(AccountsContext); + const { dialogToDisplay, setDialogToDisplay, handleAddAccount, setError, isLoading, error } = + useContext(AccountsContext); const generateMnemonic = async () => { const mnemon = await createMnemonic(); setData((d) => ({ ...d, mnemonic: mnemon })); }; - const handleClose = () => { - setDialogToDisplay('Accounts'); - resetState(); - }; - const resetState = () => { setData({ mnemonic: '', accountName: '' }); setStep(0); setError(undefined); }; + const handleClose = () => { + setDialogToDisplay('Accounts'); + resetState(); + }; + useEffect(() => { if (dialogToDisplay === 'Add') generateMnemonic(); if (dialogToDisplay === 'Accounts') resetState(); @@ -260,6 +213,7 @@ export const AddAccountModal = () => { case 2: return ( { if (data.accountName && data.mnemonic) { try { @@ -271,6 +225,8 @@ export const AddAccountModal = () => { } } }} + isLoading={isLoading} + error={error} /> ); default: diff --git a/nym-wallet/src/components/Accounts/EditAccountModal.tsx b/nym-wallet/src/components/Accounts/modals/EditAccountModal.tsx similarity index 100% rename from nym-wallet/src/components/Accounts/EditAccountModal.tsx rename to nym-wallet/src/components/Accounts/modals/EditAccountModal.tsx diff --git a/nym-wallet/src/components/Accounts/ImportAccountModal.tsx b/nym-wallet/src/components/Accounts/modals/ImportAccountModal.tsx similarity index 100% rename from nym-wallet/src/components/Accounts/ImportAccountModal.tsx rename to nym-wallet/src/components/Accounts/modals/ImportAccountModal.tsx diff --git a/nym-wallet/src/components/Accounts/MnemonicModal.tsx b/nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx similarity index 92% rename from nym-wallet/src/components/Accounts/MnemonicModal.tsx rename to nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx index cecc572a73..461e93b51b 100644 --- a/nym-wallet/src/components/Accounts/MnemonicModal.tsx +++ b/nym-wallet/src/components/Accounts/modals/MnemonicModal.tsx @@ -13,8 +13,7 @@ import { import { ArrowBackSharp } from '@mui/icons-material'; import { AccountsContext } from 'src/context'; import { useClipboard } from 'use-clipboard-copy'; -import { Mnemonic } from '../Mnemonic'; -import { PasswordInput } from '../textfields'; +import { PasswordInput, Mnemonic } from 'src/components'; export const MnemonicModal = () => { const [password, setPassword] = useState(''); @@ -26,7 +25,7 @@ export const MnemonicModal = () => { setDialogToDisplay, accountMnemonic, setAccountMnemonic, - handleGetAcccountMnemonic, + handleGetAccountMnemonic, error, setError, isLoading, @@ -86,7 +85,7 @@ export const MnemonicModal = () => { onClick={async () => { if (accountMnemonic?.accountName) { setError(undefined); - await handleGetAcccountMnemonic({ password, accountName: accountMnemonic?.accountName }); + await handleGetAccountMnemonic({ password, accountName: accountMnemonic?.accountName }); } }} endIcon={isLoading && } From 0b585a15b751d30380003bfcfb7ca3e4025a07e5 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:39:45 +0100 Subject: [PATCH 04/11] use confirm password modal on account selection --- .../Accounts/modals/AccountsModal.tsx | 76 +++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 nym-wallet/src/components/Accounts/modals/AccountsModal.tsx diff --git a/nym-wallet/src/components/Accounts/modals/AccountsModal.tsx b/nym-wallet/src/components/Accounts/modals/AccountsModal.tsx new file mode 100644 index 0000000000..0d59306459 --- /dev/null +++ b/nym-wallet/src/components/Accounts/modals/AccountsModal.tsx @@ -0,0 +1,76 @@ +import React, { useContext, useState } from 'react'; +import { Box, Button, Dialog, DialogActions, DialogContent, DialogTitle, IconButton, Typography } from '@mui/material'; +import { Add, ArrowDownwardSharp, Close } from '@mui/icons-material'; +import { AccountsContext } from 'src/context'; +import { AccountItem } from '../AccountItem'; +import { ConfirmPasswordModal } from './ConfirmPasswordModal'; + +export const AccountsModal = () => { + const { accounts, dialogToDisplay, setDialogToDisplay, setError, handleSelectAccount, selectedAccount } = + useContext(AccountsContext); + const [accountToSwitchTo, setAccountToSwitchTo] = useState(); + + const handleClose = () => { + setDialogToDisplay(undefined); + setError(undefined); + setAccountToSwitchTo(undefined); + }; + + if (accountToSwitchTo) + return ( + { + handleClose(); + setDialogToDisplay('Accounts'); + }} + onConfirm={async (password) => { + const isSuccessful = await handleSelectAccount({ password, accountName: accountToSwitchTo }); + if (isSuccessful) handleClose(); + }} + /> + ); + + return ( + + + + Accounts + + + + + + Switch between accounts + + + + {accounts?.map(({ id, address }) => ( + { + if (selectedAccount?.id !== id) { + setAccountToSwitchTo(id); + } + }} + /> + ))} + + + + + + + ); +}; From a4988e35477c77b8eb8d039016bc043508f5eb6b Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:39:56 +0100 Subject: [PATCH 05/11] tidy up --- nym-wallet/src/components/index.ts | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/nym-wallet/src/components/index.ts b/nym-wallet/src/components/index.ts index b688f8a81f..daa73d0e78 100644 --- a/nym-wallet/src/components/index.ts +++ b/nym-wallet/src/components/index.ts @@ -1,19 +1,21 @@ -export * from './ErrorFallback'; -export * from './CopyToClipboard'; -export * from './NymCard'; -export * from './Nav'; -export * from './NodeTypeSelector'; -export * from './RequestStatus'; -export * from './NoClientError'; -export * from './SuccessResponse'; -export * from './TransactionDetails'; -export * from './NymLogo'; -export * from './Fee'; export * from './AppBar'; -export * from './NetworkSelector'; export * from './ClientAddress'; +export * from './ConfirmPassword'; +export * from './CopyToClipboard'; +export * from './ErrorFallback'; +export * from './Fee'; export * from './InfoToolTip'; +export * from './LoadingPage'; +export * from './Mnemonic'; +export * from './Nav'; +export * from './NetworkSelector'; +export * from './NoClientError'; +export * from './NodeTypeSelector'; +export * from './NymCard'; +export * from './NymLogo'; +export * from './RequestStatus'; +export * from './SuccessResponse'; +export * from './textfields'; export * from './Title'; export * from './TokenPoolSelector'; -export * from './LoadingPage'; -export * from './textfields'; +export * from './TransactionDetails'; From a0d3144837096e47707029385890bfdd36446c69 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:40:18 +0100 Subject: [PATCH 06/11] extend component props --- nym-wallet/src/components/textfields.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/nym-wallet/src/components/textfields.tsx b/nym-wallet/src/components/textfields.tsx index 835e6beb23..c03306d01c 100644 --- a/nym-wallet/src/components/textfields.tsx +++ b/nym-wallet/src/components/textfields.tsx @@ -36,10 +36,11 @@ export const MnemonicInput: React.FC<{ export const PasswordInput: React.FC<{ password: string; error?: string; - label: string; + label?: string; + placeholder?: string; autoFocus?: boolean; onUpdatePassword: (password: string) => void; -}> = ({ password, label, error, autoFocus, onUpdatePassword }) => { +}> = ({ password, label, placeholder, error, autoFocus, onUpdatePassword }) => { const [showPassword, setShowPassword] = useState(false); return ( @@ -47,6 +48,7 @@ export const PasswordInput: React.FC<{ onUpdatePassword(e.target.value)} From 830dbcecfc494aca197090670bf09bd0bc3d338b Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:41:06 +0100 Subject: [PATCH 07/11] extend component props --- nym-wallet/src/components/Accounts/AccountItem.tsx | 14 +++++++++++--- nym-wallet/src/components/Accounts/Accounts.tsx | 8 ++++---- 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/nym-wallet/src/components/Accounts/AccountItem.tsx b/nym-wallet/src/components/Accounts/AccountItem.tsx index 8344d355a4..c5b785319c 100644 --- a/nym-wallet/src/components/Accounts/AccountItem.tsx +++ b/nym-wallet/src/components/Accounts/AccountItem.tsx @@ -4,8 +4,16 @@ import { useClipboard } from 'use-clipboard-copy'; import { AccountsContext } from 'src/context'; import { AccountAvatar } from './AccountAvatar'; -export const AccountItem = ({ name, address }: { name: string; address: string }) => { - const { selectedAccount, handleSelectAccount, setDialogToDisplay, setAccountMnemonic } = useContext(AccountsContext); +export const AccountItem = ({ + name, + address, + onSelectAccount, +}: { + name: string; + address: string; + onSelectAccount: () => void; +}) => { + const { selectedAccount, setDialogToDisplay, setAccountMnemonic } = useContext(AccountsContext); const { copy, copied } = useClipboard({ copiedTimeout: 1000 }); return ( - handleSelectAccount(name)}> + diff --git a/nym-wallet/src/components/Accounts/Accounts.tsx b/nym-wallet/src/components/Accounts/Accounts.tsx index a59b59c95f..2cf5873e9e 100644 --- a/nym-wallet/src/components/Accounts/Accounts.tsx +++ b/nym-wallet/src/components/Accounts/Accounts.tsx @@ -1,9 +1,9 @@ import React, { useContext, useState } from 'react'; import { AccountsContext, AppContext } from 'src/context'; -import { EditAccountModal } from './EditAccountModal'; -import { AddAccountModal } from './AddAccountModal'; -import { AccountsModal } from './AccountsModal'; -import { MnemonicModal } from './MnemonicModal'; +import { EditAccountModal } from './modals/EditAccountModal'; +import { AddAccountModal } from './modals/AddAccountModal'; +import { AccountsModal } from './modals/AccountsModal'; +import { MnemonicModal } from './modals/MnemonicModal'; import { AccountOverview } from './AccountOverview'; import { MultiAccountHowTo } from './MultiAccountHowTo'; From 1e3c8ed3e090c52d3630cb22f62ccf086e7cc3c8 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:41:25 +0100 Subject: [PATCH 08/11] confirm password modal --- .../Accounts/modals/ConfirmPasswordModal.tsx | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 nym-wallet/src/components/Accounts/modals/ConfirmPasswordModal.tsx diff --git a/nym-wallet/src/components/Accounts/modals/ConfirmPasswordModal.tsx b/nym-wallet/src/components/Accounts/modals/ConfirmPasswordModal.tsx new file mode 100644 index 0000000000..5fd48b2da6 --- /dev/null +++ b/nym-wallet/src/components/Accounts/modals/ConfirmPasswordModal.tsx @@ -0,0 +1,34 @@ +import React, { useContext } from 'react'; +import { Box, Dialog, DialogTitle, IconButton, Typography } from '@mui/material'; +import { ArrowBack } from '@mui/icons-material'; +import { ConfirmPassword } from 'src/components/ConfirmPassword'; +import { AccountsContext } from 'src/context'; + +export const ConfirmPasswordModal = ({ + accountName, + onClose, + onConfirm, +}: { + accountName?: string; + onClose: () => void; + onConfirm: (password: string) => Promise; +}) => { + const { isLoading, error } = useContext(AccountsContext); + + return ( + + + + Switch account + + + + + + Confirm password + + + + + ); +}; From 20828d0d28cfcda6045cea69ab48bd64c84cee1a Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:43:22 +0100 Subject: [PATCH 09/11] rework account selection functions --- nym-wallet/src/context/accounts.tsx | 18 +++++++++++------- nym-wallet/src/context/main.tsx | 8 ++++---- 2 files changed, 15 insertions(+), 11 deletions(-) diff --git a/nym-wallet/src/context/accounts.tsx b/nym-wallet/src/context/accounts.tsx index 51794db671..8445ce2be2 100644 --- a/nym-wallet/src/context/accounts.tsx +++ b/nym-wallet/src/context/accounts.tsx @@ -16,11 +16,11 @@ type TAccounts = { setAccountMnemonic: Dispatch>; handleAddAccount: (data: { accountName: string; mnemonic: string; password: string }) => void; setDialogToDisplay: (dialog?: TAccountsDialog) => void; - handleSelectAccount: (accountId: string) => void; + handleSelectAccount: (data: { accountName: string; password: string }) => Promise; handleAccountToEdit: (accountId: string) => void; handleEditAccount: (account: AccountEntry) => void; handleImportAccount: (account: AccountEntry) => void; - handleGetAcccountMnemonic: (data: { password: string; accountName: string }) => void; + handleGetAccountMnemonic: (data: { password: string; accountName: string }) => void; }; export type TAccountsDialog = 'Accounts' | 'Add' | 'Edit' | 'Import' | 'Mnemonic'; @@ -75,15 +75,19 @@ export const AccountsProvider: React.FC = ({ children }) => { const handleAccountToEdit = (accountName: string) => setAccountToEdit(accounts?.find((acc) => acc.id === accountName)); - const handleSelectAccount = async (accountName: string) => { - if (accountName !== selectedAccount?.id) { - await onAccountChange(accountName); + const handleSelectAccount = async ({ accountName, password }: { accountName: string; password: string }) => { + try { + await onAccountChange({ accountId: accountName, password }); const match = accounts?.find((acc) => acc.id === accountName); setSelectedAccount(match); + return true; + } catch (e) { + setError('Error switching account. Please check your password'); + return false; } }; - const handleGetAcccountMnemonic = async ({ password, accountName }: { password: string; accountName: string }) => { + const handleGetAccountMnemonic = async ({ password, accountName }: { password: string; accountName: string }) => { try { setIsLoading(true); const mnemonic = await showMnemonicForAccount({ password, accountName }); @@ -124,7 +128,7 @@ export const AccountsProvider: React.FC = ({ children }) => { handleAccountToEdit, handleSelectAccount, handleImportAccount, - handleGetAcccountMnemonic, + handleGetAccountMnemonic, }), [accounts, selectedAccount, accountToEdit, dialogToDisplay, isLoading, error, accountMnemonic], )} diff --git a/nym-wallet/src/context/main.tsx b/nym-wallet/src/context/main.tsx index d860336014..1f97606d89 100644 --- a/nym-wallet/src/context/main.tsx +++ b/nym-wallet/src/context/main.tsx @@ -55,7 +55,7 @@ type TAppContext = { handleShowTerminal: () => void; signInWithPassword: (password: string) => void; logOut: () => void; - onAccountChange: (accountId: string) => void; + onAccountChange: ({ accountId, password }: { accountId: string; password: string }) => void; }; export const AppContext = createContext({} as TAppContext); @@ -165,15 +165,15 @@ export const AppProvider = ({ children }: { children: React.ReactNode }) => { enqueueSnackbar('Successfully logged out', { variant: 'success' }); }; - const onAccountChange = async (accountId: string) => { + const onAccountChange = async ({ accountId, password }: { accountId: string; password: string }) => { if (network) { setIsLoading(true); try { - await switchAccount(accountId); + await switchAccount({ accountId, password }); await loadAccount(network); enqueueSnackbar('Account switch success', { variant: 'success', preventDuplicate: true }); } catch (e) { - enqueueSnackbar(`Error swtiching account: ${e}`, { variant: 'error' }); + throw new Error(`Error swtiching account: ${e}`); } finally { setIsLoading(false); } From 8a37df64b5ccd573170d43657f72ddd0840c1d44 Mon Sep 17 00:00:00 2001 From: fmtabbara Date: Tue, 17 May 2022 15:43:37 +0100 Subject: [PATCH 10/11] update methods --- nym-wallet/src/context/mocks/accounts.tsx | 13 ++++++------- nym-wallet/src/requests/account.ts | 4 ++-- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/nym-wallet/src/context/mocks/accounts.tsx b/nym-wallet/src/context/mocks/accounts.tsx index 8b85530b63..4374f812cc 100644 --- a/nym-wallet/src/context/mocks/accounts.tsx +++ b/nym-wallet/src/context/mocks/accounts.tsx @@ -36,14 +36,13 @@ export const MockAccountsProvider: React.FC = ({ children }) => { const handleAccountToEdit = (accountName: string) => setAccountToEdit(accounts?.find((acc) => acc.id === accountName)); - const handleSelectAccount = async (accountName: string) => { - if (accountName !== selectedAccount?.id) { - const match = accounts?.find((acc) => acc.id === accountName); - setSelectedAccount(match); - } + const handleSelectAccount = async ({ accountName }: { accountName: string; password: string }) => { + const match = accounts?.find((acc) => acc.id === accountName); + setSelectedAccount(match); + return true; }; - const handleGetAcccountMnemonic = async ({ accountName }: { password: string; accountName: string }) => { + const handleGetAccountMnemonic = async ({ accountName }: { password: string; accountName: string }) => { try { setIsLoading(true); const mnemonic = 'test mnemonic'; @@ -73,7 +72,7 @@ export const MockAccountsProvider: React.FC = ({ children }) => { handleAccountToEdit, handleSelectAccount, handleImportAccount, - handleGetAcccountMnemonic, + handleGetAccountMnemonic, }), [accounts, selectedAccount, accountToEdit, dialogToDisplay, isLoading, error, accountMnemonic], )} diff --git a/nym-wallet/src/requests/account.ts b/nym-wallet/src/requests/account.ts index 171776aef5..5a3287b360 100644 --- a/nym-wallet/src/requests/account.ts +++ b/nym-wallet/src/requests/account.ts @@ -62,6 +62,6 @@ export const showMnemonicForAccount = async ({ password, accountName }: { passwo return res; }; -export const switchAccount = async (accountId: string) => { - await invoke('sign_in_decrypted_account', { accountId }); +export const switchAccount = async ({ accountId, password }: { accountId: string; password: string }) => { + await invoke('sign_in_with_password_and_account_id', { accountId, password }); }; From 37c06f338fbe145e7aff789c0f0860bd8ce5cd82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Tue, 17 May 2022 21:56:19 +0200 Subject: [PATCH 11/11] wallet: just print account id in log statement --- nym-wallet/src-tauri/src/operations/mixnet/account.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nym-wallet/src-tauri/src/operations/mixnet/account.rs b/nym-wallet/src-tauri/src/operations/mixnet/account.rs index 79a9f2ddb0..becbf34dc0 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/account.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/account.rs @@ -518,7 +518,7 @@ async fn set_state_with_all_accounts( .collect(); for account in &all_accounts { - log::trace!("account: {:?}", account); + log::trace!("account: {:?}", account.id()); } let all_account_ids: Vec = all_accounts