@@ -14,14 +14,14 @@ cfg_wasm32! {
1414 use crate :: lp_wallet:: mnemonics_wasm_db:: { WalletsDb , WalletsDBError } ;
1515 use mm2_core:: mm_ctx:: from_ctx;
1616 use mm2_db:: indexed_db:: { ConstructibleDb , DbLocked , InitDbResult } ;
17- use mnemonics_wasm_db:: { read_all_wallet_names, read_encrypted_passphrase_if_available , save_encrypted_passphrase} ;
17+ use mnemonics_wasm_db:: { delete_wallet , read_all_wallet_names, read_encrypted_passphrase , save_encrypted_passphrase} ;
1818 use std:: sync:: Arc ;
1919
2020 type WalletsDbLocked <' a> = DbLocked <' a, WalletsDb >;
2121}
2222
2323cfg_native ! {
24- use mnemonics_storage:: { read_all_wallet_names, read_encrypted_passphrase_if_available , save_encrypted_passphrase, WalletsStorageError } ;
24+ use mnemonics_storage:: { delete_wallet , read_all_wallet_names, read_encrypted_passphrase , save_encrypted_passphrase, WalletsStorageError } ;
2525}
2626#[ cfg( not( target_arch = "wasm32" ) ) ] mod mnemonics_storage;
2727#[ cfg( target_arch = "wasm32" ) ] mod mnemonics_wasm_db;
@@ -69,13 +69,16 @@ pub enum ReadPassphraseError {
6969 WalletsStorageError ( String ) ,
7070 #[ display( fmt = "Error decrypting passphrase: {}" , _0) ]
7171 DecryptionError ( String ) ,
72+ #[ display( fmt = "Internal error: {}" , _0) ]
73+ Internal ( String ) ,
7274}
7375
7476impl From < ReadPassphraseError > for WalletInitError {
7577 fn from ( e : ReadPassphraseError ) -> Self {
7678 match e {
7779 ReadPassphraseError :: WalletsStorageError ( e) => WalletInitError :: WalletsStorageError ( e) ,
7880 ReadPassphraseError :: DecryptionError ( e) => WalletInitError :: MnemonicError ( e) ,
81+ ReadPassphraseError :: Internal ( e) => WalletInitError :: InternalError ( e) ,
7982 }
8083 }
8184}
@@ -121,25 +124,39 @@ async fn encrypt_and_save_passphrase(
121124 . mm_err ( |e| WalletInitError :: WalletsStorageError ( e. to_string ( ) ) )
122125}
123126
124- /// Reads and decrypts the passphrase from a file associated with the given wallet name, if available.
125- ///
126- /// This function first checks if a passphrase is available. If a passphrase is found,
127- /// since it is stored in an encrypted format, it decrypts it before returning. If no passphrase is found,
128- /// it returns `None`.
129- ///
130- /// # Returns
131- /// `MmInitResult<String>` - The decrypted passphrase or an error if any operation fails.
127+ /// A convenience wrapper that calls [`try_load_wallet_passphrase`] for the currently active wallet.
128+ async fn try_load_active_wallet_passphrase (
129+ ctx : & MmArc ,
130+ wallet_password : & str ,
131+ ) -> MmResult < Option < String > , ReadPassphraseError > {
132+ let wallet_name = ctx
133+ . wallet_name
134+ . get ( )
135+ . ok_or ( ReadPassphraseError :: Internal (
136+ "`wallet_name` not initialized yet!" . to_string ( ) ,
137+ ) ) ?
138+ . clone ( )
139+ . ok_or_else ( || {
140+ ReadPassphraseError :: Internal ( "Cannot read stored passphrase: no active wallet is set." . to_string ( ) )
141+ } ) ?;
142+
143+ try_load_wallet_passphrase ( ctx, & wallet_name, wallet_password) . await
144+ }
145+
146+ /// Loads (reads from storage and decrypts) a passphrase for a specific wallet by name.
132147///
133- /// # Errors
134- /// Returns specific `MmInitError` variants for different failure scenarios .
135- async fn read_and_decrypt_passphrase_if_available (
148+ /// Returns `Ok(None)` if the passphrase is not found in storage. This is an expected
149+ /// outcome for a new wallet or when using a legacy config where the passphrase is not saved .
150+ async fn try_load_wallet_passphrase (
136151 ctx : & MmArc ,
152+ wallet_name : & str ,
137153 wallet_password : & str ,
138154) -> MmResult < Option < String > , ReadPassphraseError > {
139- match read_encrypted_passphrase_if_available ( ctx)
155+ let encrypted = read_encrypted_passphrase ( ctx, wallet_name )
140156 . await
141- . mm_err ( |e| ReadPassphraseError :: WalletsStorageError ( e. to_string ( ) ) ) ?
142- {
157+ . mm_err ( |e| ReadPassphraseError :: WalletsStorageError ( e. to_string ( ) ) ) ?;
158+
159+ match encrypted {
143160 Some ( encrypted_passphrase) => {
144161 let mnemonic = decrypt_mnemonic ( & encrypted_passphrase, wallet_password)
145162 . mm_err ( |e| ReadPassphraseError :: DecryptionError ( e. to_string ( ) ) ) ?;
@@ -171,7 +188,7 @@ async fn retrieve_or_create_passphrase(
171188 wallet_name : & str ,
172189 wallet_password : & str ,
173190) -> WalletInitResult < Option < String > > {
174- match read_and_decrypt_passphrase_if_available ( ctx, wallet_password) . await ? {
191+ match try_load_active_wallet_passphrase ( ctx, wallet_password) . await ? {
175192 Some ( passphrase_from_file) => {
176193 // If an existing passphrase is found, return it
177194 Ok ( Some ( passphrase_from_file) )
@@ -202,7 +219,7 @@ async fn confirm_or_encrypt_and_store_passphrase(
202219 passphrase : & str ,
203220 wallet_password : & str ,
204221) -> WalletInitResult < Option < String > > {
205- match read_and_decrypt_passphrase_if_available ( ctx, wallet_password) . await ? {
222+ match try_load_active_wallet_passphrase ( ctx, wallet_password) . await ? {
206223 Some ( passphrase_from_file) if passphrase == passphrase_from_file => {
207224 // If an existing passphrase is found and it matches the provided passphrase, return it
208225 Ok ( Some ( passphrase_from_file) )
@@ -238,7 +255,7 @@ async fn decrypt_validate_or_save_passphrase(
238255 // Decrypt the provided encrypted passphrase
239256 let decrypted_passphrase = decrypt_mnemonic ( & encrypted_passphrase_data, wallet_password) ?;
240257
241- match read_and_decrypt_passphrase_if_available ( ctx, wallet_password) . await ? {
258+ match try_load_active_wallet_passphrase ( ctx, wallet_password) . await ? {
242259 Some ( passphrase_from_file) if decrypted_passphrase == passphrase_from_file => {
243260 // If an existing passphrase is found and it matches the decrypted passphrase, return it
244261 Ok ( Some ( decrypted_passphrase) )
@@ -476,7 +493,13 @@ impl From<WalletsDBError> for MnemonicRpcError {
476493}
477494
478495impl From < ReadPassphraseError > for MnemonicRpcError {
479- fn from ( e : ReadPassphraseError ) -> Self { MnemonicRpcError :: WalletsStorageError ( e. to_string ( ) ) }
496+ fn from ( e : ReadPassphraseError ) -> Self {
497+ match e {
498+ ReadPassphraseError :: DecryptionError ( e) => MnemonicRpcError :: InvalidPassword ( e) ,
499+ ReadPassphraseError :: WalletsStorageError ( e) => MnemonicRpcError :: WalletsStorageError ( e) ,
500+ ReadPassphraseError :: Internal ( e) => MnemonicRpcError :: Internal ( e) ,
501+ }
502+ }
480503}
481504
482505/// Retrieves the wallet mnemonic in the requested format.
@@ -513,15 +536,27 @@ impl From<ReadPassphraseError> for MnemonicRpcError {
513536pub async fn get_mnemonic_rpc ( ctx : MmArc , req : GetMnemonicRequest ) -> MmResult < GetMnemonicResponse , MnemonicRpcError > {
514537 match req. mnemonic_format {
515538 MnemonicFormat :: Encrypted => {
516- let encrypted_mnemonic = read_encrypted_passphrase_if_available ( & ctx)
539+ let wallet_name = ctx
540+ . wallet_name
541+ . get ( )
542+ . ok_or ( MnemonicRpcError :: Internal (
543+ "`wallet_name` not initialized yet!" . to_string ( ) ,
544+ ) ) ?
545+ . as_ref ( )
546+ . ok_or_else ( || {
547+ MnemonicRpcError :: Internal (
548+ "Cannot get encrypted mnemonic: This operation requires an active named wallet." . to_string ( ) ,
549+ )
550+ } ) ?;
551+ let encrypted_mnemonic = read_encrypted_passphrase ( & ctx, wallet_name)
517552 . await ?
518553 . ok_or_else ( || MnemonicRpcError :: InvalidRequest ( "Wallet mnemonic file not found" . to_string ( ) ) ) ?;
519554 Ok ( GetMnemonicResponse {
520555 mnemonic : encrypted_mnemonic. into ( ) ,
521556 } )
522557 } ,
523558 MnemonicFormat :: PlainText ( wallet_password) => {
524- let plaintext_mnemonic = read_and_decrypt_passphrase_if_available ( & ctx, & wallet_password)
559+ let plaintext_mnemonic = try_load_active_wallet_passphrase ( & ctx, & wallet_password)
525560 . await ?
526561 . ok_or_else ( || MnemonicRpcError :: InvalidRequest ( "Wallet mnemonic file not found" . to_string ( ) ) ) ?;
527562 Ok ( GetMnemonicResponse {
@@ -584,7 +619,7 @@ pub async fn change_mnemonic_password(ctx: MmArc, req: ChangeMnemonicPasswordReq
584619 . as_ref ( )
585620 . ok_or_else ( || MnemonicRpcError :: Internal ( "`wallet_name` cannot be None!" . to_string ( ) ) ) ?;
586621 // read mnemonic for a wallet_name using current user's password.
587- let mnemonic = read_and_decrypt_passphrase_if_available ( & ctx, & req. current_password )
622+ let mnemonic = try_load_active_wallet_passphrase ( & ctx, & req. current_password )
588623 . await ?
589624 . ok_or ( MmError :: new ( MnemonicRpcError :: Internal ( format ! (
590625 "{wallet_name}: wallet mnemonic file not found"
@@ -596,3 +631,48 @@ pub async fn change_mnemonic_password(ctx: MmArc, req: ChangeMnemonicPasswordReq
596631
597632 Ok ( ( ) )
598633}
634+
635+ #[ derive( Debug , Deserialize ) ]
636+ pub struct DeleteWalletRequest {
637+ /// The name of the wallet to be deleted.
638+ pub wallet_name : String ,
639+ /// The password to confirm wallet deletion.
640+ pub password : String ,
641+ }
642+
643+ /// Deletes a wallet. Requires password confirmation.
644+ /// The active wallet cannot be deleted.
645+ pub async fn delete_wallet_rpc ( ctx : MmArc , req : DeleteWalletRequest ) -> MmResult < ( ) , MnemonicRpcError > {
646+ let active_wallet = ctx
647+ . wallet_name
648+ . get ( )
649+ . ok_or ( MnemonicRpcError :: Internal (
650+ "`wallet_name` not initialized yet!" . to_string ( ) ,
651+ ) ) ?
652+ . as_ref ( ) ;
653+
654+ if active_wallet == Some ( & req. wallet_name ) {
655+ return MmError :: err ( MnemonicRpcError :: InvalidRequest ( format ! (
656+ "Cannot delete wallet '{}' as it is currently active." ,
657+ req. wallet_name
658+ ) ) ) ;
659+ }
660+
661+ // Verify the password by attempting to decrypt the mnemonic.
662+ let maybe_mnemonic = try_load_wallet_passphrase ( & ctx, & req. wallet_name , & req. password ) . await ?;
663+
664+ match maybe_mnemonic {
665+ Some ( _) => {
666+ // Password is correct, proceed with deletion.
667+ delete_wallet ( & ctx, & req. wallet_name ) . await ?;
668+ Ok ( ( ) )
669+ } ,
670+ None => {
671+ // This case implies no mnemonic file was found for the given wallet.
672+ MmError :: err ( MnemonicRpcError :: InvalidRequest ( format ! (
673+ "Wallet '{}' not found." ,
674+ req. wallet_name
675+ ) ) )
676+ } ,
677+ }
678+ }
0 commit comments