Browse Source

Window modality fixes + improved password dialog

283
Neil Booth 9 years ago
parent
commit
37b474716b
  1. 10
      gui/qt/installwizard.py
  2. 35
      gui/qt/main_window.py
  3. 136
      gui/qt/password_dialog.py
  4. 26
      plugins/keepkey/qt.py
  5. 24
      plugins/trezor/qt.py

10
gui/qt/installwizard.py

@ -407,11 +407,11 @@ class InstallWizard(WindowModalDialog, MessageBoxMixin):
return self.exec_() return self.exec_()
def password_dialog(self): def password_dialog(self):
msg = _("Please choose a password to encrypt your wallet keys.")+'\n'\ from password_dialog import PasswordDialog
+_("Leave these fields empty if you want to disable encryption.") msg = _("Please choose a password to encrypt your wallet keys.\n"
from password_dialog import make_password_dialog, run_password_dialog "Leave these fields empty if you want to disable encryption.")
self.set_layout( make_password_dialog(self, None, msg) ) dialog = PasswordDialog(self, None, _("Choose a password"), msg, True)
return run_password_dialog(self, None, self)[2] return dialog.run()[2]
def run(self, action): def run(self, action):
if self.storage.file_exists and action != 'new': if self.storage.file_exists and action != 'new':

35
gui/qt/main_window.py

@ -1852,8 +1852,39 @@ class ElectrumWindow(QMainWindow, MessageBoxMixin, PrintError):
def change_password_dialog(self): def change_password_dialog(self):
from password_dialog import PasswordDialog from password_dialog import PasswordDialog
d = PasswordDialog(self.wallet, self)
d.run() if self.wallet and self.wallet.is_watching_only():
self.show_error(_('This is a watching-only wallet'))
return
msg = (_('Your wallet is encrypted. Use this dialog to change your '
'password. To disable wallet encryption, enter an empty new '
'password.') if self.wallet.use_encryption
else _('Your wallet keys are not encrypted'))
d = PasswordDialog(self, self.wallet, _("Set Password"), msg, True)
ok, password, new_password = d.run()
if not ok:
return
try:
self.wallet.check_password(password)
except BaseException as e:
self.show_error(str(e))
return
try:
self.wallet.update_password(password, new_password)
except:
traceback.print_exc(file=sys.stdout)
self.show_error(_('Failed to update password'))
return
if new_password:
msg = _('Password was updated successfully')
else:
msg = _('This wallet is not encrypted')
self.show_message(msg, title=_("Success"))
self.update_lock_icon() self.update_lock_icon()
def toggle_search(self): def toggle_search(self):

136
gui/qt/password_dialog.py

@ -23,9 +23,27 @@ from util import *
import re import re
import math import math
def check_password_strength(password):
'''
Check the strength of the password entered by the user and return back the same
:param password: password entered by user in New Password
:return: password strength Weak or Medium or Strong
'''
password = unicode(password)
n = math.log(len(set(password)))
num = re.search("[0-9]", password) is not None and re.match("^[0-9]*$", password) is None
caps = password != password.upper() and password != password.lower()
extra = re.match("^[a-zA-Z0-9]*$", password) is None
score = len(password)*( n + caps + num + extra)/20
password_strength = {0:"Weak",1:"Medium",2:"Strong",3:"Very Strong"}
return password_strength[min(3, int(score))]
class PasswordDialog(WindowModalDialog):
def make_password_dialog(self, wallet, msg, new_pass=True): def __init__(self, parent, wallet, title, msg, new_pass):
WindowModalDialog.__init__(self, parent, title)
self.wallet = wallet
self.pw = QLineEdit() self.pw = QLineEdit()
self.pw.setEchoMode(2) self.pw.setEchoMode(2)
@ -44,8 +62,6 @@ def make_password_dialog(self, wallet, msg, new_pass=True):
grid.setColumnStretch(1,1) grid.setColumnStretch(1,1)
logo = QLabel() logo = QLabel()
lockfile = ":icons/lock.png" if wallet and wallet.use_encryption else ":icons/unlock.png"
logo.setPixmap(QPixmap(lockfile).scaledToWidth(36))
logo.setAlignment(Qt.AlignCenter) logo.setAlignment(Qt.AlignCenter)
grid.addWidget(logo, 0, 0) grid.addWidget(logo, 0, 0)
@ -60,6 +76,11 @@ def make_password_dialog(self, wallet, msg, new_pass=True):
if wallet and wallet.use_encryption: if wallet and wallet.use_encryption:
grid.addWidget(QLabel(_('Password')), 0, 0) grid.addWidget(QLabel(_('Password')), 0, 0)
grid.addWidget(self.pw, 0, 1) grid.addWidget(self.pw, 0, 1)
lockfile = ":icons/lock.png"
else:
self.pw = None
lockfile = ":icons/unlock.png"
logo.setPixmap(QPixmap(lockfile).scaledToWidth(36))
grid.addWidget(QLabel(_('New Password') if new_pass else _('Password')), 1, 0) grid.addWidget(QLabel(_('New Password') if new_pass else _('Password')), 1, 0)
grid.addWidget(self.new_pw, 1, 1) grid.addWidget(self.new_pw, 1, 1)
@ -68,106 +89,39 @@ def make_password_dialog(self, wallet, msg, new_pass=True):
grid.addWidget(self.conf_pw, 2, 1) grid.addWidget(self.conf_pw, 2, 1)
vbox.addLayout(grid) vbox.addLayout(grid)
#Password Strength Label # Password Strength Label
self.pw_strength = QLabel() self.pw_strength = QLabel()
grid.addWidget(self.pw_strength, 3, 0, 1, 2) grid.addWidget(self.pw_strength, 3, 0, 1, 2)
self.new_pw.textChanged.connect(lambda: update_password_strength(self.pw_strength, self.new_pw.text())) self.new_pw.textChanged.connect(self.pw_changed)
self.conf_pw.textChanged.connect(self.check_OKButton)
self.OKButton = OkButton(self)
vbox.addStretch(1) vbox.addStretch(1)
vbox.addLayout(Buttons(CancelButton(self), OkButton(self))) vbox.addLayout(Buttons(CancelButton(self), self.OKButton))
return vbox self.setLayout(vbox)
def run_password_dialog(self, wallet, parent):
if wallet and wallet.is_watching_only():
QMessageBox.information(parent, _('Error'), _('This is a watching-only wallet'), _('OK'))
return False, None, None
if not self.exec_():
return False, None, None
password = unicode(self.pw.text()) if wallet and wallet.use_encryption else None
new_password = unicode(self.new_pw.text())
new_password2 = unicode(self.conf_pw.text())
if new_password != new_password2:
QMessageBox.warning(parent, _('Error'), _('Passwords do not match'), _('OK'))
# Retry
return run_password_dialog(self, wallet, parent)
if not new_password:
new_password = None
return True, password, new_password def pw_changed(self):
password = self.new_pw.text()
def check_password_strength(password):
'''
Check the strength of the password entered by the user and return back the same
:param password: password entered by user in New Password
:return: password strength Weak or Medium or Strong
'''
password = unicode(password)
n = math.log(len(set(password)))
num = re.search("[0-9]", password) is not None and re.match("^[0-9]*$", password) is None
caps = password != password.upper() and password != password.lower()
extra = re.match("^[a-zA-Z0-9]*$", password) is None
score = len(password)*( n + caps + num + extra)/20
password_strength = {0:"Weak",1:"Medium",2:"Strong",3:"Very Strong"}
return password_strength[min(3, int(score))]
def update_password_strength(pw_strength_label,password):
'''
call the function check_password_strength and update the label pw_strength interactively as the user is typing the password
:param pw_strength_label: the label pw_strength
:param password: password entered in New Password text box
:return: None
'''
if password: if password:
colors = {"Weak":"Red","Medium":"Blue","Strong":"Green", "Very Strong":"Green"} colors = {"Weak":"Red", "Medium":"Blue", "Strong":"Green",
"Very Strong":"Green"}
strength = check_password_strength(password) strength = check_password_strength(password)
label = _("Password Strength")+ ": "+"<font color=" + colors[strength] + ">" + strength + "</font>" label = (_("Password Strength") + ": " + "<font color="
+ colors[strength] + ">" + strength + "</font>")
else: else:
label = "" label = ""
pw_strength_label.setText(label) self.pw_strength.setText(label)
self.check_OKButton()
class PasswordDialog(WindowModalDialog):
def __init__(self, wallet, parent):
WindowModalDialog.__init__(self, parent,_("Set Password"))
self.wallet = wallet
self.parent = parent
msg = (_('Your wallet is encrypted. Use this dialog to change your password.') + ' '\
+_('To disable wallet encryption, enter an empty new password.')) \
if wallet.use_encryption else _('Your wallet keys are not encrypted')
self.setLayout(make_password_dialog(self, wallet, msg))
def check_OKButton(self):
self.OKButton.setEnabled(self.new_pw.text() == self.conf_pw.text())
def run(self): def run(self):
ok, password, new_password = run_password_dialog(self, self.wallet, self.parent) if not self.exec_():
if not ok:
return
try:
self.wallet.check_password(password)
except BaseException as e:
QMessageBox.warning(self.parent, _('Error'), str(e), _('OK'))
return False, None, None return False, None, None
try: password = unicode(self.pw.text()) if self.pw else None
self.wallet.update_password(password, new_password) new_password = unicode(self.new_pw.text())
except: new_password2 = unicode(self.conf_pw.text())
import traceback, sys
traceback.print_exc(file=sys.stdout)
QMessageBox.warning(self.parent, _('Error'), _('Failed to update password'), _('OK'))
return
if new_password: return True, password or None, new_password or None
QMessageBox.information(self.parent, _('Success'), _('Password was updated successfully'), _('OK'))
else:
QMessageBox.information(self.parent, _('Success'), _('This wallet is not encrypted'), _('OK'))

26
plugins/keepkey/qt.py

@ -1,4 +1,4 @@
from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton from PyQt4.Qt import QMessageBox, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore
from electrum_gui.qt.util import * from electrum_gui.qt.util import *
from electrum_gui.qt.main_window import StatusBarButton, ElectrumWindow from electrum_gui.qt.main_window import StatusBarButton, ElectrumWindow
@ -73,7 +73,7 @@ class Plugin(KeepKeyPlugin):
return return
get_label = lambda: self.get_client().features.label get_label = lambda: self.get_client().features.label
update_label = lambda: current_label_label.setText("Label: %s" % get_label()) update_label = lambda: current_label_label.setText("Label: %s" % get_label())
d = QDialog() d = WindowModalDialog(window, _("KeepKey Settings"))
layout = QGridLayout(d) layout = QGridLayout(d)
layout.addWidget(QLabel("KeepKey Options"),0,0) layout.addWidget(QLabel("KeepKey Options"),0,0)
layout.addWidget(QLabel("ID:"),1,0) layout.addWidget(QLabel("ID:"),1,0)
@ -132,10 +132,7 @@ class KeepKeyQtHandler:
return self.passphrase return self.passphrase
def pin_dialog(self): def pin_dialog(self):
d = QDialog(None) d = WindowModalDialog(self.win, _("Enter PIN"))
d.setModal(1)
d.setWindowTitle(_("Enter PIN"))
d.setWindowFlags(d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
matrix = PinMatrixWidget() matrix = PinMatrixWidget()
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addWidget(QLabel(self.message)) vbox.addWidget(QLabel(self.message))
@ -153,23 +150,18 @@ class KeepKeyQtHandler:
self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else '' self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else ''
else: else:
assert type(self.win) is InstallWizard assert type(self.win) is InstallWizard
from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog from electrum_gui.qt.password_dialog import PasswordDialog
d = QDialog() d = PasswordDialog(self.win, None, None, self.message, False)
d.setModal(1) confirmed, p, passphrase = d.run()
d.setLayout(make_password_dialog(d, None, self.message, False))
confirmed, p, passphrase = run_password_dialog(d, None, None)
if not confirmed: if not confirmed:
QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK')) self.win.show_critical(_("Password request canceled"))
self.passphrase = None self.passphrase = None
else: else:
self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else '' self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else ''
self.done.set() self.done.set()
def message_dialog(self): def message_dialog(self):
self.d = QDialog() self.d = WindowModalDialog(self.win, _('Please Check KeepKey Device'))
self.d.setModal(1)
self.d.setWindowTitle('Please Check KeepKey Device')
self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
l = QLabel(self.message) l = QLabel(self.message)
vbox = QVBoxLayout(self.d) vbox = QVBoxLayout(self.d)
vbox.addWidget(l) vbox.addWidget(l)
@ -182,5 +174,3 @@ class KeepKeyQtHandler:
def dialog_stop(self): def dialog_stop(self):
self.d.hide() self.d.hide()

24
plugins/trezor/qt.py

@ -1,4 +1,4 @@
from PyQt4.Qt import QMessageBox, QDialog, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton from PyQt4.Qt import QMessageBox, QVBoxLayout, QLabel, QThread, SIGNAL, QGridLayout, QInputDialog, QPushButton
import PyQt4.QtCore as QtCore import PyQt4.QtCore as QtCore
from electrum_gui.qt.util import * from electrum_gui.qt.util import *
from electrum_gui.qt.main_window import StatusBarButton, ElectrumWindow from electrum_gui.qt.main_window import StatusBarButton, ElectrumWindow
@ -46,10 +46,7 @@ class TrezorQtHandler:
return self.passphrase return self.passphrase
def pin_dialog(self): def pin_dialog(self):
d = QDialog(None) d = WindowModalDialog(self.win, _("Enter PIN"))
d.setModal(1)
d.setWindowTitle(_("Enter PIN"))
d.setWindowFlags(d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
matrix = PinMatrixWidget() matrix = PinMatrixWidget()
vbox = QVBoxLayout() vbox = QVBoxLayout()
vbox.addWidget(QLabel(self.message)) vbox.addWidget(QLabel(self.message))
@ -67,23 +64,18 @@ class TrezorQtHandler:
self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else '' self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else ''
else: else:
assert type(self.win) is InstallWizard assert type(self.win) is InstallWizard
from electrum_gui.qt.password_dialog import make_password_dialog, run_password_dialog from electrum_gui.qt.password_dialog import PasswordDialog
d = QDialog() d = PasswordDialog(self.win, None, None, self.message, False)
d.setModal(1) confirmed, p, passphrase = d.run()
d.setLayout(make_password_dialog(d, None, self.message, False))
confirmed, p, passphrase = run_password_dialog(d, None, None)
if not confirmed: if not confirmed:
QMessageBox.critical(None, _('Error'), _("Password request canceled"), _('OK')) self.win.show_critical(_("Password request canceled"))
self.passphrase = None self.passphrase = None
else: else:
self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else '' self.passphrase = unicodedata.normalize('NFKD', unicode(passphrase)) if passphrase else ''
self.done.set() self.done.set()
def message_dialog(self): def message_dialog(self):
self.d = QDialog() self.d = WindowModalDialog(self.win, _('Please Check Trezor Device'))
self.d.setModal(1)
self.d.setWindowTitle('Please Check Trezor Device')
self.d.setWindowFlags(self.d.windowFlags() | QtCore.Qt.WindowStaysOnTopHint)
l = QLabel(self.message) l = QLabel(self.message)
vbox = QVBoxLayout(self.d) vbox = QVBoxLayout(self.d)
vbox.addWidget(l) vbox.addWidget(l)
@ -171,7 +163,7 @@ class Plugin(TrezorPlugin):
return return
get_label = lambda: self.get_client().features.label get_label = lambda: self.get_client().features.label
update_label = lambda: current_label_label.setText("Label: %s" % get_label()) update_label = lambda: current_label_label.setText("Label: %s" % get_label())
d = QDialog() d = WindowModalDialog(window, _("Trezor Settings"))
layout = QGridLayout(d) layout = QGridLayout(d)
layout.addWidget(QLabel("Trezor Options"),0,0) layout.addWidget(QLabel("Trezor Options"),0,0)
layout.addWidget(QLabel("ID:"),1,0) layout.addWidget(QLabel("ID:"),1,0)

Loading…
Cancel
Save