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):
|
if wallet := self._wallets.get(wallet_key):
|
||||||
return wallet
|
return wallet
|
||||||
wallet = self._load_wallet(path, password, upgrade=upgrade, config=self.config)
|
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)
|
wallet.start_network(self.network)
|
||||||
self.add_wallet(wallet)
|
self.add_wallet(wallet)
|
||||||
self.update_recently_opened_wallets(path)
|
self.update_recently_opened_wallets(path)
|
||||||
|
|||||||
@@ -308,7 +308,6 @@ class ElectrumGui(BaseElectrumGui, Logger):
|
|||||||
self.build_tray_menu()
|
self.build_tray_menu()
|
||||||
w.warn_if_testnet()
|
w.warn_if_testnet()
|
||||||
w.warn_if_watching_only()
|
w.warn_if_watching_only()
|
||||||
w.require_full_encryption()
|
|
||||||
return w
|
return w
|
||||||
|
|
||||||
def count_wizards_in_progress(func):
|
def count_wizards_in_progress(func):
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ def protected(func):
|
|||||||
password = None
|
password = None
|
||||||
msg = kwargs.get('message')
|
msg = kwargs.get('message')
|
||||||
while self.wallet.has_keystore_encryption():
|
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:
|
if password is None:
|
||||||
# User cancelled password input
|
# User cancelled password input
|
||||||
return
|
return
|
||||||
@@ -330,6 +330,45 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
self._coroutines_scheduled[fut] = name
|
self._coroutines_scheduled[fut] = name
|
||||||
self.need_update.set()
|
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):
|
def on_fx_history(self):
|
||||||
self.history_model.refresh('fx_history')
|
self.history_model.refresh('fx_history')
|
||||||
self.address_list.refresh_all()
|
self.address_list.refresh_all()
|
||||||
@@ -580,24 +619,6 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
])
|
])
|
||||||
self.show_warning(msg, title=_('Watch-only wallet'))
|
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):
|
def warn_if_testnet(self):
|
||||||
if not constants.net.TESTNET:
|
if not constants.net.TESTNET:
|
||||||
return
|
return
|
||||||
@@ -724,6 +745,8 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
self.wallet_menu.addSeparator()
|
self.wallet_menu.addSeparator()
|
||||||
|
|
||||||
self.password_menu = self.wallet_menu.addAction(_("&Password"), self.change_password_dialog)
|
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.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 = self.wallet_menu.addMenu(_("&Private keys"))
|
||||||
self.private_keys_menu.addAction(_("&Sweep"), self.sweep_key_dialog)
|
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."))
|
"Payments are more likely to succeed with a more complete graph."))
|
||||||
|
|
||||||
def update_lock_icon(self):
|
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)
|
self.password_button.setIcon(icon)
|
||||||
|
|
||||||
def update_buttons_on_seed(self):
|
def update_buttons_on_seed(self):
|
||||||
@@ -1897,6 +1920,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, Logger, QtEventListener):
|
|||||||
return
|
return
|
||||||
self._update_wallet_password(
|
self._update_wallet_password(
|
||||||
old_password=old_password, new_password=new_password, encrypt_storage=encrypt_file)
|
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):
|
def _update_wallet_password(self, *, old_password, new_password, encrypt_storage: bool):
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -502,9 +502,6 @@ class Abstract_Wallet(ABC, Logger, EventListener):
|
|||||||
def has_channels(self):
|
def has_channels(self):
|
||||||
return self.lnworker is not None and len(self.lnworker._channels) > 0
|
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:
|
def can_have_lightning(self) -> bool:
|
||||||
""" whether this wallet can create new channels """
|
""" whether this wallet can create new channels """
|
||||||
# we want static_remotekey to be a wallet address
|
# 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
|
# save changes. force full rewrite to rm remnants of old password
|
||||||
if self.storage and self.storage.file_exists():
|
if self.storage and self.storage.file_exists():
|
||||||
self.db.write_and_force_consolidation()
|
self.db.write_and_force_consolidation()
|
||||||
# if wallet was previously unlocked, update password in memory
|
# if wallet was previously unlocked, reset password_in_memory
|
||||||
if self.requires_unlock():
|
self.lock_wallet()
|
||||||
self.unlock(new_pw)
|
|
||||||
|
|
||||||
@abstractmethod
|
@abstractmethod
|
||||||
def _update_password_for_keystore(self, old_pw: Optional[str], new_pw: Optional[str]) -> None:
|
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.check_password(password)
|
||||||
self._password_in_memory = password
|
self._password_in_memory = password
|
||||||
|
|
||||||
|
def lock_wallet(self):
|
||||||
|
self._password_in_memory = None
|
||||||
|
|
||||||
def get_unlocked_password(self):
|
def get_unlocked_password(self):
|
||||||
return self._password_in_memory
|
return self._password_in_memory
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user