kivy: request PIN code on startup
This commit is contained in:
parent
95780a39a3
commit
b75d82491b
@ -285,7 +285,8 @@
|
|||||||
|
|
||||||
<KButton@Button>:
|
<KButton@Button>:
|
||||||
size_hint: 1, None
|
size_hint: 1, None
|
||||||
height: '48dp'
|
height: '60dp'
|
||||||
|
font_size: '30dp'
|
||||||
on_release:
|
on_release:
|
||||||
self.parent.update_amount(self.text)
|
self.parent.update_amount(self.text)
|
||||||
|
|
||||||
|
|||||||
@ -244,6 +244,7 @@ class ElectrumWindow(App):
|
|||||||
self.tabs = None
|
self.tabs = None
|
||||||
self.is_exit = False
|
self.is_exit = False
|
||||||
self.wallet = None
|
self.wallet = None
|
||||||
|
self.pause_time = 0
|
||||||
|
|
||||||
App.__init__(self)#, **kwargs)
|
App.__init__(self)#, **kwargs)
|
||||||
|
|
||||||
@ -445,7 +446,6 @@ class ElectrumWindow(App):
|
|||||||
#win.softinput_mode = 'below_target'
|
#win.softinput_mode = 'below_target'
|
||||||
self.on_size(win, win.size)
|
self.on_size(win, win.size)
|
||||||
self.init_ui()
|
self.init_ui()
|
||||||
self.load_wallet_by_name(self.electrum_config.get_wallet_path())
|
|
||||||
# init plugins
|
# init plugins
|
||||||
run_hook('init_kivy', self)
|
run_hook('init_kivy', self)
|
||||||
# fiat currency
|
# fiat currency
|
||||||
@ -467,6 +467,8 @@ class ElectrumWindow(App):
|
|||||||
self.network.register_callback(self.on_fee, ['fee'])
|
self.network.register_callback(self.on_fee, ['fee'])
|
||||||
self.network.register_callback(self.on_quotes, ['on_quotes'])
|
self.network.register_callback(self.on_quotes, ['on_quotes'])
|
||||||
self.network.register_callback(self.on_history, ['on_history'])
|
self.network.register_callback(self.on_history, ['on_history'])
|
||||||
|
# load wallet
|
||||||
|
self.load_wallet_by_name(self.electrum_config.get_wallet_path())
|
||||||
# URI passed in config
|
# URI passed in config
|
||||||
uri = self.electrum_config.get('url')
|
uri = self.electrum_config.get('url')
|
||||||
if uri:
|
if uri:
|
||||||
@ -484,17 +486,18 @@ class ElectrumWindow(App):
|
|||||||
wallet.start_threads(self.daemon.network)
|
wallet.start_threads(self.daemon.network)
|
||||||
self.daemon.add_wallet(wallet)
|
self.daemon.add_wallet(wallet)
|
||||||
self.load_wallet(wallet)
|
self.load_wallet(wallet)
|
||||||
self.on_resume()
|
|
||||||
|
|
||||||
def load_wallet_by_name(self, path):
|
def load_wallet_by_name(self, path):
|
||||||
if not path:
|
if not path:
|
||||||
return
|
return
|
||||||
|
if self.wallet and self.wallet.storage.path == path:
|
||||||
|
return
|
||||||
wallet = self.daemon.load_wallet(path, None)
|
wallet = self.daemon.load_wallet(path, None)
|
||||||
if wallet:
|
if wallet:
|
||||||
if wallet != self.wallet:
|
if wallet.has_password():
|
||||||
self.stop_wallet()
|
self.password_dialog(wallet, _('Enter PIN code'), lambda x: self.load_wallet(wallet), self.stop)
|
||||||
|
else:
|
||||||
self.load_wallet(wallet)
|
self.load_wallet(wallet)
|
||||||
self.on_resume()
|
|
||||||
else:
|
else:
|
||||||
Logger.debug('Electrum: Wallet not found. Launching install wizard')
|
Logger.debug('Electrum: Wallet not found. Launching install wizard')
|
||||||
storage = WalletStorage(path)
|
storage = WalletStorage(path)
|
||||||
@ -504,6 +507,7 @@ class ElectrumWindow(App):
|
|||||||
wizard.run(action)
|
wizard.run(action)
|
||||||
|
|
||||||
def on_stop(self):
|
def on_stop(self):
|
||||||
|
Logger.info('on_stop')
|
||||||
self.stop_wallet()
|
self.stop_wallet()
|
||||||
|
|
||||||
def stop_wallet(self):
|
def stop_wallet(self):
|
||||||
@ -617,6 +621,8 @@ class ElectrumWindow(App):
|
|||||||
|
|
||||||
@profiler
|
@profiler
|
||||||
def load_wallet(self, wallet):
|
def load_wallet(self, wallet):
|
||||||
|
if self.wallet:
|
||||||
|
self.stop_wallet()
|
||||||
self.wallet = wallet
|
self.wallet = wallet
|
||||||
self.update_wallet()
|
self.update_wallet()
|
||||||
# Once GUI has been initialized check if we want to announce something
|
# Once GUI has been initialized check if we want to announce something
|
||||||
@ -625,6 +631,7 @@ class ElectrumWindow(App):
|
|||||||
self.receive_screen.clear()
|
self.receive_screen.clear()
|
||||||
self.update_tabs()
|
self.update_tabs()
|
||||||
run_hook('load_wallet', wallet, self)
|
run_hook('load_wallet', wallet, self)
|
||||||
|
print('load wallet done', self.wallet)
|
||||||
|
|
||||||
def update_status(self, *dt):
|
def update_status(self, *dt):
|
||||||
self.num_blocks = self.network.get_local_height()
|
self.num_blocks = self.network.get_local_height()
|
||||||
@ -684,12 +691,16 @@ class ElectrumWindow(App):
|
|||||||
Logger.Error('Notification: needs plyer; `sudo pip install plyer`')
|
Logger.Error('Notification: needs plyer; `sudo pip install plyer`')
|
||||||
|
|
||||||
def on_pause(self):
|
def on_pause(self):
|
||||||
|
self.pause_time = time.time()
|
||||||
# pause nfc
|
# pause nfc
|
||||||
if self.nfcscanner:
|
if self.nfcscanner:
|
||||||
self.nfcscanner.nfc_disable()
|
self.nfcscanner.nfc_disable()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def on_resume(self):
|
def on_resume(self):
|
||||||
|
now = time.time()
|
||||||
|
if self.wallet.has_password and now - self.pause_time > 60:
|
||||||
|
self.password_dialog(self.wallet, _('Enter PIN'), None, self.stop)
|
||||||
if self.nfcscanner:
|
if self.nfcscanner:
|
||||||
self.nfcscanner.nfc_enable()
|
self.nfcscanner.nfc_enable()
|
||||||
|
|
||||||
@ -875,7 +886,8 @@ class ElectrumWindow(App):
|
|||||||
|
|
||||||
def protected(self, msg, f, args):
|
def protected(self, msg, f, args):
|
||||||
if self.wallet.has_password():
|
if self.wallet.has_password():
|
||||||
self.password_dialog(msg, f, args)
|
on_success = lambda pw: f(*(args + (pw,)))
|
||||||
|
self.password_dialog(self.wallet, msg, on_success, lambda: None)
|
||||||
else:
|
else:
|
||||||
f(*(args + (None,)))
|
f(*(args + (None,)))
|
||||||
|
|
||||||
@ -887,7 +899,7 @@ class ElectrumWindow(App):
|
|||||||
|
|
||||||
def _delete_wallet(self, b):
|
def _delete_wallet(self, b):
|
||||||
if b:
|
if b:
|
||||||
basename = os.path.basename(self.wallet.storage.path)
|
basename = self.wallet.basename()
|
||||||
self.protected(_("Enter your PIN code to confirm deletion of {}").format(basename), self.__delete_wallet, ())
|
self.protected(_("Enter your PIN code to confirm deletion of {}").format(basename), self.__delete_wallet, ())
|
||||||
|
|
||||||
def __delete_wallet(self, pw):
|
def __delete_wallet(self, pw):
|
||||||
@ -925,40 +937,23 @@ class ElectrumWindow(App):
|
|||||||
if passphrase:
|
if passphrase:
|
||||||
label.text += '\n\n' + _('Passphrase') + ': ' + passphrase
|
label.text += '\n\n' + _('Passphrase') + ': ' + passphrase
|
||||||
|
|
||||||
def change_password(self, cb):
|
def password_dialog(self, wallet, msg, on_success, on_failure):
|
||||||
if self.wallet.has_password():
|
|
||||||
self.protected(_("Changing PIN code.") + '\n' + _("Enter your current PIN:"), self._change_password, (cb,))
|
|
||||||
else:
|
|
||||||
self._change_password(cb, None)
|
|
||||||
|
|
||||||
def _change_password(self, cb, old_password):
|
|
||||||
if self.wallet.has_password():
|
|
||||||
if old_password is None:
|
|
||||||
return
|
|
||||||
try:
|
|
||||||
self.wallet.check_password(old_password)
|
|
||||||
except InvalidPassword:
|
|
||||||
self.show_error("Invalid PIN")
|
|
||||||
return
|
|
||||||
self.password_dialog(_('Enter new PIN'), self._change_password2, (cb, old_password,))
|
|
||||||
|
|
||||||
def _change_password2(self, cb, old_password, new_password):
|
|
||||||
self.password_dialog(_('Confirm new PIN'), self._change_password3, (cb, old_password, new_password))
|
|
||||||
|
|
||||||
def _change_password3(self, cb, old_password, new_password, confirmed_password):
|
|
||||||
if new_password == confirmed_password:
|
|
||||||
self.wallet.update_password(old_password, new_password)
|
|
||||||
cb()
|
|
||||||
else:
|
|
||||||
self.show_error("PIN numbers do not match")
|
|
||||||
|
|
||||||
def password_dialog(self, msg, f, args):
|
|
||||||
from .uix.dialogs.password_dialog import PasswordDialog
|
from .uix.dialogs.password_dialog import PasswordDialog
|
||||||
def callback(pw):
|
|
||||||
Clock.schedule_once(lambda x: f(*(args + (pw,))), 0.1)
|
|
||||||
if self._password_dialog is None:
|
if self._password_dialog is None:
|
||||||
self._password_dialog = PasswordDialog()
|
self._password_dialog = PasswordDialog()
|
||||||
self._password_dialog.init(msg, callback)
|
self._password_dialog.init(self, wallet, msg, on_success, on_failure)
|
||||||
|
self._password_dialog.open()
|
||||||
|
|
||||||
|
def change_password(self, cb):
|
||||||
|
from .uix.dialogs.password_dialog import PasswordDialog
|
||||||
|
if self._password_dialog is None:
|
||||||
|
self._password_dialog = PasswordDialog()
|
||||||
|
message = _("Changing PIN code.") + '\n' + _("Enter your current PIN:")
|
||||||
|
def on_success(old_password, new_password):
|
||||||
|
self.wallet.update_password(old_password, new_password)
|
||||||
|
self.show_info(_("Your PIN code was updated"))
|
||||||
|
on_failure = lambda: self.show_error(_("PIN codes do not match"))
|
||||||
|
self._password_dialog.init(self, self.wallet, message, on_success, on_failure, is_change=1)
|
||||||
self._password_dialog.open()
|
self._password_dialog.open()
|
||||||
|
|
||||||
def export_private_keys(self, pk_label, addr):
|
def export_private_keys(self, pk_label, addr):
|
||||||
|
|||||||
@ -802,27 +802,17 @@ class InstallWizard(BaseWizard, Widget):
|
|||||||
app = App.get_running_app()
|
app = App.get_running_app()
|
||||||
Clock.schedule_once(lambda dt: app.show_error(msg))
|
Clock.schedule_once(lambda dt: app.show_error(msg))
|
||||||
|
|
||||||
def password_dialog(self, message, callback):
|
|
||||||
popup = PasswordDialog()
|
|
||||||
popup.init(message, callback)
|
|
||||||
popup.open()
|
|
||||||
|
|
||||||
def request_password(self, run_next, force_disable_encrypt_cb=False):
|
def request_password(self, run_next, force_disable_encrypt_cb=False):
|
||||||
def callback(pin):
|
def on_success(old_pin, pin):
|
||||||
if pin:
|
assert old_pin is None
|
||||||
self.run('confirm_password', pin, run_next)
|
run_next(pin, False)
|
||||||
else:
|
def on_failure():
|
||||||
run_next(None, None)
|
self.show_error(_('PIN mismatch'))
|
||||||
self.password_dialog('Choose a PIN code', callback)
|
self.run('request_password', run_next)
|
||||||
|
popup = PasswordDialog()
|
||||||
def confirm_password(self, pin, run_next):
|
app = App.get_running_app()
|
||||||
def callback(conf):
|
popup.init(app, None, _('Choose PIN code'), on_success, on_failure, is_change=2)
|
||||||
if conf == pin:
|
popup.open()
|
||||||
run_next(pin, False)
|
|
||||||
else:
|
|
||||||
self.show_error(_('PIN mismatch'))
|
|
||||||
self.run('request_password', run_next)
|
|
||||||
self.password_dialog('Confirm your PIN code', callback)
|
|
||||||
|
|
||||||
def action_dialog(self, action, run_next):
|
def action_dialog(self, action, run_next):
|
||||||
f = getattr(self, action)
|
f = getattr(self, action)
|
||||||
|
|||||||
@ -5,35 +5,42 @@ from kivy.lang import Builder
|
|||||||
from decimal import Decimal
|
from decimal import Decimal
|
||||||
from kivy.clock import Clock
|
from kivy.clock import Clock
|
||||||
|
|
||||||
|
from electrum.util import InvalidPassword
|
||||||
|
from electrum_gui.kivy.i18n import _
|
||||||
|
|
||||||
Builder.load_string('''
|
Builder.load_string('''
|
||||||
|
|
||||||
<PasswordDialog@Popup>
|
<PasswordDialog@Popup>
|
||||||
id: popup
|
id: popup
|
||||||
title: _('PIN Code')
|
title: 'Electrum'
|
||||||
message: ''
|
message: ''
|
||||||
size_hint: 0.9, 0.9
|
|
||||||
BoxLayout:
|
BoxLayout:
|
||||||
|
size_hint: 1, 1
|
||||||
orientation: 'vertical'
|
orientation: 'vertical'
|
||||||
Widget:
|
Widget:
|
||||||
size_hint: 1, 1
|
size_hint: 1, 0.05
|
||||||
Label:
|
Label:
|
||||||
|
font_size: '20dp'
|
||||||
text: root.message
|
text: root.message
|
||||||
text_size: self.width, None
|
text_size: self.width, None
|
||||||
size: self.texture_size
|
size: self.texture_size
|
||||||
Widget:
|
Widget:
|
||||||
size_hint: 1, 1
|
size_hint: 1, 0.05
|
||||||
Label:
|
Label:
|
||||||
id: a
|
id: a
|
||||||
text: ' * '*len(kb.password) + ' o '*(6-len(kb.password))
|
font_size: '50dp'
|
||||||
|
text: '*'*len(kb.password) + '-'*(6-len(kb.password))
|
||||||
|
size: self.texture_size
|
||||||
Widget:
|
Widget:
|
||||||
size_hint: 1, 1
|
size_hint: 1, 0.05
|
||||||
GridLayout:
|
GridLayout:
|
||||||
id: kb
|
id: kb
|
||||||
|
size_hint: 1, None
|
||||||
|
height: self.minimum_height
|
||||||
update_amount: popup.update_password
|
update_amount: popup.update_password
|
||||||
password: ''
|
password: ''
|
||||||
on_password: popup.on_password(self.password)
|
on_password: popup.on_password(self.password)
|
||||||
size_hint: 1, None
|
spacing: '2dp'
|
||||||
height: '200dp'
|
|
||||||
cols: 3
|
cols: 3
|
||||||
KButton:
|
KButton:
|
||||||
text: '1'
|
text: '1'
|
||||||
@ -59,30 +66,44 @@ Builder.load_string('''
|
|||||||
text: '0'
|
text: '0'
|
||||||
KButton:
|
KButton:
|
||||||
text: '<'
|
text: '<'
|
||||||
BoxLayout:
|
|
||||||
size_hint: 1, None
|
|
||||||
height: '48dp'
|
|
||||||
Widget:
|
|
||||||
size_hint: 0.5, None
|
|
||||||
Button:
|
|
||||||
size_hint: 0.5, None
|
|
||||||
height: '48dp'
|
|
||||||
text: _('Cancel')
|
|
||||||
on_release:
|
|
||||||
popup.dismiss()
|
|
||||||
popup.callback(None)
|
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
|
||||||
class PasswordDialog(Factory.Popup):
|
class PasswordDialog(Factory.Popup):
|
||||||
|
|
||||||
#def __init__(self, message, callback):
|
def init(self, app, wallet, message, on_success, on_failure, is_change=0):
|
||||||
# Factory.Popup.__init__(self)
|
self.app = app
|
||||||
|
self.wallet = wallet
|
||||||
def init(self, message, callback):
|
|
||||||
self.message = message
|
self.message = message
|
||||||
self.callback = callback
|
self.on_success = on_success
|
||||||
|
self.on_failure = on_failure
|
||||||
self.ids.kb.password = ''
|
self.ids.kb.password = ''
|
||||||
|
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 '')
|
||||||
|
|
||||||
|
def check_password(self, password):
|
||||||
|
if self.is_change > 1:
|
||||||
|
return True
|
||||||
|
try:
|
||||||
|
self.wallet.check_password(password)
|
||||||
|
return True
|
||||||
|
except InvalidPassword as e:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def on_dismiss(self):
|
||||||
|
if not self.success:
|
||||||
|
if self.on_failure:
|
||||||
|
self.on_failure()
|
||||||
|
else:
|
||||||
|
# keep dialog open
|
||||||
|
return True
|
||||||
|
else:
|
||||||
|
if self.on_success:
|
||||||
|
args = (self.pw, self.new_password) if self.is_change else (self.pw,)
|
||||||
|
Clock.schedule_once(lambda dt: self.on_success(*args), 0.1)
|
||||||
|
|
||||||
def update_password(self, c):
|
def update_password(self, c):
|
||||||
kb = self.ids.kb
|
kb = self.ids.kb
|
||||||
@ -97,5 +118,25 @@ class PasswordDialog(Factory.Popup):
|
|||||||
|
|
||||||
def on_password(self, pw):
|
def on_password(self, pw):
|
||||||
if len(pw) == 6:
|
if len(pw) == 6:
|
||||||
self.dismiss()
|
if self.check_password(pw):
|
||||||
Clock.schedule_once(lambda dt: self.callback(pw), 0.1)
|
if self.is_change == 0:
|
||||||
|
self.success = True
|
||||||
|
self.pw = pw
|
||||||
|
self.message = _('Please wait...')
|
||||||
|
self.dismiss()
|
||||||
|
elif self.is_change == 1:
|
||||||
|
self.pw = pw
|
||||||
|
self.message = _('Enter new PIN')
|
||||||
|
self.ids.kb.password = ''
|
||||||
|
self.is_change = 2
|
||||||
|
elif self.is_change == 2:
|
||||||
|
self.new_password = pw
|
||||||
|
self.message = _('Confirm new PIN')
|
||||||
|
self.ids.kb.password = ''
|
||||||
|
self.is_change = 3
|
||||||
|
elif self.is_change == 3:
|
||||||
|
self.success = pw == self.new_password
|
||||||
|
self.dismiss()
|
||||||
|
else:
|
||||||
|
self.app.show_error(_('Wrong PIN'))
|
||||||
|
self.ids.kb.password = ''
|
||||||
|
|||||||
@ -36,9 +36,8 @@ Builder.load_string('''
|
|||||||
action: partial(root.language_dialog, self)
|
action: partial(root.language_dialog, self)
|
||||||
CardSeparator
|
CardSeparator
|
||||||
SettingsItem:
|
SettingsItem:
|
||||||
status: '' if root.disable_pin else ('ON' if root.use_encryption else 'OFF')
|
|
||||||
disabled: root.disable_pin
|
disabled: root.disable_pin
|
||||||
title: _('PIN code') + ': ' + self.status
|
title: _('PIN code')
|
||||||
description: _("Change your PIN code.")
|
description: _("Change your PIN code.")
|
||||||
action: partial(root.change_password, self)
|
action: partial(root.change_password, self)
|
||||||
CardSeparator
|
CardSeparator
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user