Wallet file encryption:
- a keypair is derived from the wallet password - only the public key is retained in memory - wallets must opened and closed explicitly with the daemon
This commit is contained in:
@@ -159,18 +159,26 @@ class ElectrumGui:
|
||||
w.bring_to_top()
|
||||
break
|
||||
else:
|
||||
try:
|
||||
wallet = self.daemon.load_wallet(path)
|
||||
except BaseException as e:
|
||||
QMessageBox.information(None, _('Error'), str(e), _('OK'))
|
||||
return
|
||||
if wallet is None:
|
||||
if not os.path.exists(path):
|
||||
wizard = InstallWizard(self.config, self.app, self.plugins, path)
|
||||
wallet = wizard.run_and_get_wallet()
|
||||
if not wallet:
|
||||
return
|
||||
wallet.start_threads(self.daemon.network)
|
||||
self.daemon.add_wallet(wallet)
|
||||
else:
|
||||
from password_dialog import PasswordDialog
|
||||
msg = _("The file '%s' is encrypted.") % os.path.basename(path)
|
||||
password_getter = lambda: PasswordDialog(msg=msg).run()
|
||||
while True:
|
||||
try:
|
||||
wallet = self.daemon.load_wallet(path, password_getter)
|
||||
break
|
||||
except UserCancelled:
|
||||
return
|
||||
except BaseException as e:
|
||||
QMessageBox.information(None, _('Error'), str(e), _('OK'))
|
||||
continue
|
||||
w = self.create_window_for_wallet(wallet)
|
||||
if uri:
|
||||
w.pay_to_URI(uri)
|
||||
|
||||
@@ -294,8 +294,9 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
||||
|
||||
def pw_layout(self, msg, kind):
|
||||
playout = PasswordLayout(None, msg, kind, self.next_button)
|
||||
playout.encrypt_cb.setChecked(True)
|
||||
self.set_main_layout(playout.layout())
|
||||
return playout.new_password()
|
||||
return playout.new_password(), playout.encrypt_cb.isChecked()
|
||||
|
||||
@wizard_dialog
|
||||
def request_password(self, run_next):
|
||||
|
||||
@@ -1680,19 +1680,13 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
self.send_button.setVisible(not self.wallet.is_watching_only())
|
||||
|
||||
def change_password_dialog(self):
|
||||
from password_dialog import PasswordDialog, PW_CHANGE
|
||||
|
||||
msg = (_('Your wallet is encrypted. Use this dialog to change your '
|
||||
'password. To disable wallet encryption, enter an empty new '
|
||||
'password.') if self.wallet.has_password()
|
||||
else _('Your wallet keys are not encrypted'))
|
||||
d = PasswordDialog(self, self.wallet, msg, PW_CHANGE)
|
||||
ok, password, new_password = d.run()
|
||||
from password_dialog import ChangePasswordDialog
|
||||
d = ChangePasswordDialog(self, self.wallet)
|
||||
ok, password, new_password, encrypt_file = d.run()
|
||||
if not ok:
|
||||
return
|
||||
|
||||
try:
|
||||
self.wallet.update_password(password, new_password)
|
||||
self.wallet.update_password(password, new_password, encrypt_file)
|
||||
except BaseException as e:
|
||||
self.show_error(str(e))
|
||||
return
|
||||
@@ -1700,8 +1694,7 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
traceback.print_exc(file=sys.stdout)
|
||||
self.show_error(_('Failed to update password'))
|
||||
return
|
||||
|
||||
msg = _('Password was updated successfully') if new_password else _('This wallet is not encrypted')
|
||||
msg = _('Password was updated successfully') if new_password else _('Password is disabled, this wallet is not protected')
|
||||
self.show_message(msg, title=_("Success"))
|
||||
self.update_lock_icon()
|
||||
|
||||
@@ -1972,24 +1965,10 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
|
||||
d.exec_()
|
||||
|
||||
def password_dialog(self, msg=None, parent=None):
|
||||
from password_dialog import PasswordDialog
|
||||
parent = parent or self
|
||||
d = WindowModalDialog(parent, _("Enter Password"))
|
||||
pw = QLineEdit()
|
||||
pw.setEchoMode(2)
|
||||
vbox = QVBoxLayout()
|
||||
if not msg:
|
||||
msg = _('Please enter your password')
|
||||
vbox.addWidget(QLabel(msg))
|
||||
grid = QGridLayout()
|
||||
grid.setSpacing(8)
|
||||
grid.addWidget(QLabel(_('Password')), 1, 0)
|
||||
grid.addWidget(pw, 1, 1)
|
||||
vbox.addLayout(grid)
|
||||
vbox.addLayout(Buttons(CancelButton(d), OkButton(d)))
|
||||
d.setLayout(vbox)
|
||||
run_hook('password_dialog', pw, grid, 1)
|
||||
if not d.exec_(): return
|
||||
return unicode(pw.text())
|
||||
d = PasswordDialog(parent, msg)
|
||||
return d.run()
|
||||
|
||||
|
||||
def tx_from_text(self, txt):
|
||||
|
||||
@@ -30,6 +30,8 @@ from util import *
|
||||
import re
|
||||
import math
|
||||
|
||||
from electrum.plugins import run_hook
|
||||
|
||||
def check_password_strength(password):
|
||||
|
||||
'''
|
||||
@@ -92,7 +94,7 @@ class PasswordLayout(object):
|
||||
logo_grid.addWidget(label, 0, 1, 1, 2)
|
||||
vbox.addLayout(logo_grid)
|
||||
|
||||
m1 = _('New Password:') if kind == PW_NEW else _('Password:')
|
||||
m1 = _('New Password:') if kind == PW_CHANGE else _('Password:')
|
||||
msgs = [m1, _('Confirm Password:')]
|
||||
if wallet and wallet.has_password():
|
||||
grid.addWidget(QLabel(_('Current Password:')), 0, 0)
|
||||
@@ -115,8 +117,15 @@ class PasswordLayout(object):
|
||||
grid.addWidget(self.pw_strength, 3, 0, 1, 2)
|
||||
self.new_pw.textChanged.connect(self.pw_changed)
|
||||
|
||||
self.encrypt_cb = QCheckBox(_('Encrypt wallet file'))
|
||||
self.encrypt_cb.setEnabled(False)
|
||||
grid.addWidget(self.encrypt_cb, 4, 0, 1, 2)
|
||||
self.encrypt_cb.setVisible(kind != PW_PASSPHRASE)
|
||||
|
||||
def enable_OK():
|
||||
OK_button.setEnabled(self.new_pw.text() == self.conf_pw.text())
|
||||
ok = self.new_pw.text() == self.conf_pw.text()
|
||||
OK_button.setEnabled(ok)
|
||||
self.encrypt_cb.setEnabled(ok and bool(self.new_pw.text()))
|
||||
self.new_pw.textChanged.connect(enable_OK)
|
||||
self.conf_pw.textChanged.connect(enable_OK)
|
||||
|
||||
@@ -153,20 +162,54 @@ class PasswordLayout(object):
|
||||
return pw
|
||||
|
||||
|
||||
class PasswordDialog(WindowModalDialog):
|
||||
class ChangePasswordDialog(WindowModalDialog):
|
||||
|
||||
def __init__(self, parent, wallet, msg, kind):
|
||||
def __init__(self, parent, wallet):
|
||||
WindowModalDialog.__init__(self, parent)
|
||||
is_encrypted = wallet.storage.is_encrypted()
|
||||
if not wallet.has_password():
|
||||
msg = _('Your wallet is not protected.')
|
||||
msg += ' ' + _('Use this dialog to add a password to your wallet.')
|
||||
else:
|
||||
if not is_encrypted:
|
||||
msg = _('Your bitcoins are password protected. However, your wallet file is not encrypted.')
|
||||
else:
|
||||
msg = _('Your wallet is password protected and encrypted.')
|
||||
msg += ' ' + _('Use this dialog to change your password.')
|
||||
OK_button = OkButton(self)
|
||||
self.playout = PasswordLayout(wallet, msg, kind, OK_button)
|
||||
self.playout = PasswordLayout(wallet, msg, PW_CHANGE, OK_button)
|
||||
self.setWindowTitle(self.playout.title())
|
||||
vbox = QVBoxLayout(self)
|
||||
vbox.addLayout(self.playout.layout())
|
||||
vbox.addStretch(1)
|
||||
vbox.addLayout(Buttons(CancelButton(self), OK_button))
|
||||
self.playout.encrypt_cb.setChecked(is_encrypted or not wallet.has_password())
|
||||
|
||||
def run(self):
|
||||
if not self.exec_():
|
||||
return False, None, None
|
||||
return False, None, None, None
|
||||
return True, self.playout.old_password(), self.playout.new_password(), self.playout.encrypt_cb.isChecked()
|
||||
|
||||
return True, self.playout.old_password(), self.playout.new_password()
|
||||
|
||||
class PasswordDialog(WindowModalDialog):
|
||||
|
||||
def __init__(self, parent=None, msg=None):
|
||||
msg = msg or _('Please enter your password')
|
||||
WindowModalDialog.__init__(self, parent, _("Enter Password"))
|
||||
self.pw = pw = QLineEdit()
|
||||
pw.setEchoMode(2)
|
||||
vbox = QVBoxLayout()
|
||||
vbox.addWidget(QLabel(msg))
|
||||
grid = QGridLayout()
|
||||
grid.setSpacing(8)
|
||||
grid.addWidget(QLabel(_('Password')), 1, 0)
|
||||
grid.addWidget(pw, 1, 1)
|
||||
vbox.addLayout(grid)
|
||||
vbox.addLayout(Buttons(CancelButton(self), OkButton(self)))
|
||||
self.setLayout(vbox)
|
||||
run_hook('password_dialog', pw, grid, 1)
|
||||
|
||||
def run(self):
|
||||
if not self.exec_():
|
||||
return
|
||||
return unicode(self.pw.text())
|
||||
|
||||
@@ -19,6 +19,8 @@ class ElectrumGui:
|
||||
if not storage.file_exists:
|
||||
print "Wallet not found. try 'electrum create'"
|
||||
exit()
|
||||
password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None
|
||||
storage.read(password)
|
||||
|
||||
self.done = 0
|
||||
self.last_balance = ""
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import tty, sys
|
||||
import curses, datetime, locale
|
||||
from decimal import Decimal
|
||||
import getpass
|
||||
|
||||
from electrum.util import format_satoshis, set_verbosity
|
||||
from electrum.util import StoreDict
|
||||
@@ -21,7 +22,8 @@ class ElectrumGui:
|
||||
if not storage.file_exists:
|
||||
print "Wallet not found. try 'electrum create'"
|
||||
exit()
|
||||
|
||||
password = getpass.getpass('Password:', stream=None) if storage.is_encrypted() else None
|
||||
storage.read(password)
|
||||
self.wallet = Wallet(storage)
|
||||
self.wallet.start_threads(self.network)
|
||||
self.contacts = StoreDict(self.config, 'contacts')
|
||||
|
||||
Reference in New Issue
Block a user