Qt: do not require password in memory
- do not require full encryption - do not store password on startup - add lock/unlock functions to qt GUI
This commit is contained in:
@@ -470,8 +470,6 @@ class Daemon(Logger):
|
||||
if wallet := self._wallets.get(wallet_key):
|
||||
return wallet
|
||||
wallet = self._load_wallet(path, password, upgrade=upgrade, config=self.config)
|
||||
if wallet.requires_unlock() and password is not None:
|
||||
wallet.unlock(password)
|
||||
wallet.start_network(self.network)
|
||||
self.add_wallet(wallet)
|
||||
self.update_recently_opened_wallets(path)
|
||||
|
||||
@@ -308,7 +308,6 @@ class ElectrumGui(BaseElectrumGui, Logger):
|
||||
self.build_tray_menu()
|
||||
w.warn_if_testnet()
|
||||
w.warn_if_watching_only()
|
||||
w.require_full_encryption()
|
||||
return w
|
||||
|
||||
def count_wizards_in_progress(func):
|
||||
|
||||
@@ -141,7 +141,7 @@ def protected(func):
|
||||
password = None
|
||||
msg = kwargs.get('message')
|
||||
while self.wallet.has_keystore_encryption():
|
||||
password = self.password_dialog(parent=parent, msg=msg)
|
||||
password = self.wallet.get_unlocked_password() or self.password_dialog(parent=parent, msg=msg)
|
||||
if password is None:
|
||||
# User cancelled password input
|
||||
return
|
||||
@@ -330,6 +330,45 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
self._coroutines_scheduled[fut] = name
|
||||
self.need_update.set()
|
||||
|
||||
def toggle_lock(self):
|
||||
if self.wallet.get_unlocked_password():
|
||||
self.lock_wallet()
|
||||
else:
|
||||
msg = ' '.join([
|
||||
_('Your wallet is locked.'),
|
||||
_('If you unlock it, its password will not be required to sign transactions.'),
|
||||
_('Enter your password to unlock your wallet:')
|
||||
])
|
||||
self.unlock_wallet(message=msg)
|
||||
|
||||
def update_lock_menu(self):
|
||||
self.lock_menu.setEnabled(self.wallet.has_password())
|
||||
text = _('Lock') if self.wallet.get_unlocked_password() else _('Unlock')
|
||||
self.lock_menu.setText(text)
|
||||
|
||||
@protected
|
||||
def unlock_wallet(self, password, message=None):
|
||||
self.wallet.unlock(password)
|
||||
self.update_lock_icon()
|
||||
self.update_lock_menu()
|
||||
icon = read_QIcon("unlock.png")
|
||||
msg = ' '.join([
|
||||
_('Your wallet is unlocked.'),
|
||||
_('Its password will not be required to sign transactions.'),
|
||||
])
|
||||
self.show_message(msg, icon=icon.pixmap(30))
|
||||
|
||||
def lock_wallet(self):
|
||||
self.wallet.lock_wallet()
|
||||
self.update_lock_icon()
|
||||
self.update_lock_menu()
|
||||
icon = read_QIcon("lock.png")
|
||||
msg = ' '.join([
|
||||
_('Your wallet is locked.'),
|
||||
_('Its password will be required to sign transactions.'),
|
||||
])
|
||||
self.show_message(msg, icon=icon.pixmap(30))
|
||||
|
||||
def on_fx_history(self):
|
||||
self.history_model.refresh('fx_history')
|
||||
self.address_list.refresh_all()
|
||||
@@ -580,24 +619,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
])
|
||||
self.show_warning(msg, title=_('Watch-only wallet'))
|
||||
|
||||
def require_full_encryption(self):
|
||||
if self.wallet.has_keystore_encryption() and not self.wallet.has_storage_encryption():
|
||||
msg = ' '.join([
|
||||
_("Your wallet is password-protected, but the wallet file is not encrypted."),
|
||||
_("This is no longer supported."),
|
||||
_("Please enter your password in order to encrypt your wallet file."),
|
||||
])
|
||||
while True:
|
||||
password = self.password_dialog(msg)
|
||||
if not password:
|
||||
self.close()
|
||||
raise UserCancelled()
|
||||
try:
|
||||
self.wallet.update_password(password, password, encrypt_storage=True)
|
||||
break
|
||||
except InvalidPassword as e:
|
||||
self.show_error(str(e))
|
||||
|
||||
def warn_if_testnet(self):
|
||||
if not constants.net.TESTNET:
|
||||
return
|
||||
@@ -724,6 +745,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
self.wallet_menu.addSeparator()
|
||||
|
||||
self.password_menu = self.wallet_menu.addAction(_("&Password"), self.change_password_dialog)
|
||||
self.lock_menu = self.wallet_menu.addAction(_("&Unlock"), self.toggle_lock)
|
||||
self.update_lock_menu()
|
||||
self.seed_menu = self.wallet_menu.addAction(_("&Seed"), self.show_seed_dialog)
|
||||
self.private_keys_menu = self.wallet_menu.addMenu(_("&Private keys"))
|
||||
self.private_keys_menu.addAction(_("&Sweep"), self.sweep_key_dialog)
|
||||
@@ -1864,7 +1887,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
"Payments are more likely to succeed with a more complete graph."))
|
||||
|
||||
def update_lock_icon(self):
|
||||
icon = read_QIcon("lock.png") if self.wallet.has_password() else read_QIcon("unlock.png")
|
||||
icon = read_QIcon("lock.png") if self.wallet.has_password() and (self.wallet.get_unlocked_password() is None) else read_QIcon("unlock.png")
|
||||
self.password_button.setIcon(icon)
|
||||
|
||||
def update_buttons_on_seed(self):
|
||||
@@ -1897,6 +1920,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
||||
return
|
||||
self._update_wallet_password(
|
||||
old_password=old_password, new_password=new_password, encrypt_storage=encrypt_file)
|
||||
self.update_lock_menu()
|
||||
|
||||
def _update_wallet_password(self, *, old_password, new_password, encrypt_storage: bool):
|
||||
try:
|
||||
|
||||
@@ -502,9 +502,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
def has_channels(self):
|
||||
return self.lnworker is not None and len(self.lnworker._channels) > 0
|
||||
|
||||
def requires_unlock(self):
|
||||
return self.config.ENABLE_ANCHOR_CHANNELS and self.has_channels()
|
||||
|
||||
def can_have_lightning(self) -> bool:
|
||||
""" whether this wallet can create new channels """
|
||||
# we want static_remotekey to be a wallet address
|
||||
@@ -3098,9 +3095,8 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
# save changes. force full rewrite to rm remnants of old password
|
||||
if self.storage and self.storage.file_exists():
|
||||
self.db.write_and_force_consolidation()
|
||||
# if wallet was previously unlocked, update password in memory
|
||||
if self.requires_unlock():
|
||||
self.unlock(new_pw)
|
||||
# if wallet was previously unlocked, reset password_in_memory
|
||||
self.lock_wallet()
|
||||
|
||||
@abstractmethod
|
||||
def _update_password_for_keystore(self, old_pw: Optional[str], new_pw: Optional[str]) -> None:
|
||||
@@ -3418,6 +3414,9 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
||||
self.check_password(password)
|
||||
self._password_in_memory = password
|
||||
|
||||
def lock_wallet(self):
|
||||
self._password_in_memory = None
|
||||
|
||||
def get_unlocked_password(self):
|
||||
return self._password_in_memory
|
||||
|
||||
|
||||
Reference in New Issue
Block a user