diff --git a/electrum/gui/kivy/main_window.py b/electrum/gui/kivy/main_window.py index 1228e24ad..e19b45ce2 100644 --- a/electrum/gui/kivy/main_window.py +++ b/electrum/gui/kivy/main_window.py @@ -326,6 +326,7 @@ class ElectrumWindow(App): self.wallet = None # type: Optional[Abstract_Wallet] self.pause_time = 0 self.asyncio_loop = asyncio.get_event_loop() + self.pin_code = None App.__init__(self)#, **kwargs) @@ -619,9 +620,13 @@ class ElectrumWindow(App): return wallet = self.daemon.load_wallet(path, None) if wallet: - if platform == 'android' and wallet.has_password(): + if wallet.has_password(): + def on_success(x): + # save pin_code so that we can create backups + self.pin_code = x + self.load_wallet(wallet) self.password_dialog(wallet=wallet, msg=_('Enter PIN code'), - on_success=lambda x: self.load_wallet(wallet), on_failure=self.stop) + on_success=on_success, on_failure=self.stop) else: self.load_wallet(wallet) else: @@ -637,6 +642,7 @@ class ElectrumWindow(App): if not storage.is_encrypted_with_user_pw(): raise Exception("Kivy GUI does not support this type of encrypted wallet files.") def on_password(pw): + self.pin_code = pw storage.decrypt(pw) self._on_decrypted_storage(storage) self.password_dialog(wallet=storage, msg=_('Enter PIN code'), @@ -1196,7 +1202,7 @@ class ElectrumWindow(App): self.show_info(_("Your PIN code was updated")) on_failure = lambda: self.show_error(_("PIN codes do not match")) self._password_dialog.init(self, wallet=self.wallet, msg=message, - on_success=on_success, on_failure=on_failure, is_change=1) + on_success=on_success, on_failure=on_failure, is_change=True) self._password_dialog.open() def change_backup_password(self): @@ -1209,16 +1215,15 @@ class ElectrumWindow(App): def on_success(old_password, new_password): backup_pubkey = WalletStorage.get_eckey_from_password(new_password).get_public_key_hex() # TODO: use a unique PIN for all wallets - self.electrum_config.set_key('pin_code', old_password) self.electrum_config.set_key('backup_pubkey', backup_pubkey) self.show_info(_("Backup password set")) on_failure = lambda: self.show_error(_("Passwords do not match")) self._password_dialog.init(self, wallet=self.wallet, msg=message, - on_success=on_success, on_failure=on_failure, is_change=1, is_backup=True) + on_success=on_success, on_failure=on_failure, is_change=True, is_backup=True) self._password_dialog.open() def save_backup(self): - new_path = self.wallet.save_backup() + new_path = self.wallet.save_backup(pin_code=self.pin_code) if new_path: self.show_info(_("Backup saved:") + f"\n{new_path}") else: diff --git a/electrum/gui/kivy/uix/dialogs/password_dialog.py b/electrum/gui/kivy/uix/dialogs/password_dialog.py index 1642c3cbe..86b3567aa 100644 --- a/electrum/gui/kivy/uix/dialogs/password_dialog.py +++ b/electrum/gui/kivy/uix/dialogs/password_dialog.py @@ -114,24 +114,34 @@ class PasswordDialog(Factory.Popup): def init(self, app: 'ElectrumWindow', *, wallet: Union['Abstract_Wallet', 'WalletStorage'] = None, msg: str, on_success: Callable = None, on_failure: Callable = None, - is_change: int = 0, is_backup: bool = False): + is_change: bool = False, is_backup: bool = False): self.app = app self.is_backup = is_backup self.wallet = wallet self.message = msg self.on_success = on_success self.on_failure = on_failure - self.ids.kb.password = '' - self.ids.textinput_generic_password.text = '' self.success = False self.is_change = is_change self.pw = None self.new_password = None self.title = 'Electrum' + (' - ' + self.wallet.basename() if self.wallet else '') - #self.ids.cb_generic_password.active = False + self.level = 1 if is_backup else 0 + self.is_generic = self.is_backup + self.update_screen() + + def update_screen(self): + self.ids.kb.password = '' + self.ids.textinput_generic_password.text = '' + if self.level == 0: + self.message = _('Enter your PIN') + elif self.level == 1: + self.message = _('Enter a strong password for your backup') if self.is_backup else _('Enter new PIN') + elif self.level == 2: + self.message = _('Confirm backup password') if self.is_backup else _('Confirm new PIN') def check_password(self, password): - if self.is_change > 1: + if self.level > 0: return True try: self.wallet.check_password(password) @@ -162,6 +172,7 @@ class PasswordDialog(Factory.Popup): text += c kb.password = text + def on_password(self, pw: str): if self.is_generic: if len(pw) < 6: @@ -169,25 +180,20 @@ class PasswordDialog(Factory.Popup): return if len(pw) >= 6: if self.check_password(pw): - if self.is_change == 0: + if self.is_change is False: self.success = True self.pw = pw self.message = _('Please wait...') self.dismiss() - elif self.is_change == 1: + elif self.level == 0: + self.level = 1 self.pw = pw - self.message = _('Enter a strong password for your backup') if self.is_backup else _('Enter new PIN') - self.ids.kb.password = '' - self.ids.textinput_generic_password.text = '' - self.is_change = 2 - self.is_generic = self.is_backup - elif self.is_change == 2: + self.update_screen() + elif self.level == 1: + self.level = 2 self.new_password = pw - self.message = _('Confirm backup password') if self.is_backup else _('Confirm new PIN') - self.ids.kb.password = '' - self.ids.textinput_generic_password.text = '' - self.is_change = 3 - elif self.is_change == 3: + self.update_screen() + elif self.level == 2: self.success = pw == self.new_password self.is_generic = False self.dismiss() diff --git a/electrum/wallet.py b/electrum/wallet.py index cc8d33d88..811739495 100644 --- a/electrum/wallet.py +++ b/electrum/wallet.py @@ -263,19 +263,21 @@ class Abstract_Wallet(AddressSynchronizer, ABC): if self.storage: self.db.write(self.storage) - def save_backup(self): + def save_backup(self, pin_code=None): new_db = WalletDB(self.db.dump(), manual_upgrades=False) new_db.put('is_backup', True) new_path = os.path.join(get_backup_dir(self.config), self.basename() + '.backup') if new_path is None: return new_storage = WalletStorage(new_path) - if 'ANDROID_DATA' in os.environ: - pin_code = self.config.get('pin_code') + if pin_code: + backup_pubkey = self.config.get('backup_pubkey') + if backup_pubkey is None: + return w2 = Wallet(new_db, None, config=self.config) w2.update_password(pin_code, None) new_storage._encryption_version = StorageEncryptionVersion.USER_PASSWORD - new_storage.pubkey = self.config.get('backup_pubkey') + new_storage.pubkey = backup_pubkey else: new_storage._encryption_version = self.storage._encryption_version new_storage.pubkey = self.storage.pubkey