wizard: do not use on storage object during wallet creation
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
|
import copy
|
||||||
import traceback
|
import traceback
|
||||||
from functools import partial
|
from functools import partial
|
||||||
from typing import List, TYPE_CHECKING, Tuple, NamedTuple, Any
|
from typing import List, TYPE_CHECKING, Tuple, NamedTuple, Any
|
||||||
@@ -65,12 +66,12 @@ class WizardStackItem(NamedTuple):
|
|||||||
|
|
||||||
class BaseWizard(object):
|
class BaseWizard(object):
|
||||||
|
|
||||||
def __init__(self, config: SimpleConfig, plugins: Plugins, storage: WalletStorage):
|
def __init__(self, config: SimpleConfig, plugins: Plugins):
|
||||||
super(BaseWizard, self).__init__()
|
super(BaseWizard, self).__init__()
|
||||||
self.config = config
|
self.config = config
|
||||||
self.plugins = plugins
|
self.plugins = plugins
|
||||||
self.storage = storage
|
self.data = {}
|
||||||
self.wallet = None # type: Abstract_Wallet
|
self.pw_args = None
|
||||||
self._stack = [] # type: List[WizardStackItem]
|
self._stack = [] # type: List[WizardStackItem]
|
||||||
self.plugin = None
|
self.plugin = None
|
||||||
self.keystores = []
|
self.keystores = []
|
||||||
@@ -83,7 +84,7 @@ class BaseWizard(object):
|
|||||||
def run(self, *args):
|
def run(self, *args):
|
||||||
action = args[0]
|
action = args[0]
|
||||||
args = args[1:]
|
args = args[1:]
|
||||||
storage_data = self.storage.get_all_data()
|
storage_data = copy.deepcopy(self.data)
|
||||||
self._stack.append(WizardStackItem(action, args, storage_data))
|
self._stack.append(WizardStackItem(action, args, storage_data))
|
||||||
if not action:
|
if not action:
|
||||||
return
|
return
|
||||||
@@ -110,7 +111,7 @@ class BaseWizard(object):
|
|||||||
stack_item = self._stack.pop()
|
stack_item = self._stack.pop()
|
||||||
# try to undo side effects since we last entered 'previous' frame
|
# try to undo side effects since we last entered 'previous' frame
|
||||||
# FIXME only self.storage is properly restored
|
# FIXME only self.storage is properly restored
|
||||||
self.storage.overwrite_all_data(stack_item.storage_data)
|
self.data = copy.deepcopy(stack_item.storage_data)
|
||||||
# rerun 'previous' frame
|
# rerun 'previous' frame
|
||||||
self.run(stack_item.action, *stack_item.args)
|
self.run(stack_item.action, *stack_item.args)
|
||||||
|
|
||||||
@@ -118,8 +119,7 @@ class BaseWizard(object):
|
|||||||
self._stack = []
|
self._stack = []
|
||||||
|
|
||||||
def new(self):
|
def new(self):
|
||||||
name = os.path.basename(self.storage.path)
|
title = _("Create new wallet")
|
||||||
title = _("Create") + ' ' + name
|
|
||||||
message = '\n'.join([
|
message = '\n'.join([
|
||||||
_("What kind of wallet do you want to create?")
|
_("What kind of wallet do you want to create?")
|
||||||
])
|
])
|
||||||
@@ -132,36 +132,35 @@ class BaseWizard(object):
|
|||||||
choices = [pair for pair in wallet_kinds if pair[0] in wallet_types]
|
choices = [pair for pair in wallet_kinds if pair[0] in wallet_types]
|
||||||
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type)
|
self.choice_dialog(title=title, message=message, choices=choices, run_next=self.on_wallet_type)
|
||||||
|
|
||||||
def upgrade_storage(self):
|
def upgrade_storage(self, storage):
|
||||||
exc = None
|
exc = None
|
||||||
def on_finished():
|
def on_finished():
|
||||||
if exc is None:
|
if exc is None:
|
||||||
self.wallet = Wallet(self.storage)
|
|
||||||
self.terminate()
|
self.terminate()
|
||||||
else:
|
else:
|
||||||
raise exc
|
raise exc
|
||||||
def do_upgrade():
|
def do_upgrade():
|
||||||
nonlocal exc
|
nonlocal exc
|
||||||
try:
|
try:
|
||||||
self.storage.upgrade()
|
storage.upgrade()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
exc = e
|
exc = e
|
||||||
self.waiting_dialog(do_upgrade, _('Upgrading wallet format...'), on_finished=on_finished)
|
self.waiting_dialog(do_upgrade, _('Upgrading wallet format...'), on_finished=on_finished)
|
||||||
|
|
||||||
def load_2fa(self):
|
def load_2fa(self):
|
||||||
self.storage.put('wallet_type', '2fa')
|
self.data['wallet_type'] = '2fa'
|
||||||
self.storage.put('use_trustedcoin', True)
|
self.data['use_trustedcoin'] = True
|
||||||
self.plugin = self.plugins.load_plugin('trustedcoin')
|
self.plugin = self.plugins.load_plugin('trustedcoin')
|
||||||
|
|
||||||
def on_wallet_type(self, choice):
|
def on_wallet_type(self, choice):
|
||||||
self.wallet_type = choice
|
self.data['wallet_type'] = self.wallet_type = choice
|
||||||
if choice == 'standard':
|
if choice == 'standard':
|
||||||
action = 'choose_keystore'
|
action = 'choose_keystore'
|
||||||
elif choice == 'multisig':
|
elif choice == 'multisig':
|
||||||
action = 'choose_multisig'
|
action = 'choose_multisig'
|
||||||
elif choice == '2fa':
|
elif choice == '2fa':
|
||||||
self.load_2fa()
|
self.load_2fa()
|
||||||
action = self.storage.get_action()
|
action = self.plugin.get_action(self.data)
|
||||||
elif choice == 'imported':
|
elif choice == 'imported':
|
||||||
action = 'import_addresses_or_keys'
|
action = 'import_addresses_or_keys'
|
||||||
self.run(action)
|
self.run(action)
|
||||||
@@ -169,7 +168,7 @@ class BaseWizard(object):
|
|||||||
def choose_multisig(self):
|
def choose_multisig(self):
|
||||||
def on_multisig(m, n):
|
def on_multisig(m, n):
|
||||||
multisig_type = "%dof%d" % (m, n)
|
multisig_type = "%dof%d" % (m, n)
|
||||||
self.storage.put('wallet_type', multisig_type)
|
self.data['wallet_type'] = multisig_type
|
||||||
self.n = n
|
self.n = n
|
||||||
self.run('choose_keystore')
|
self.run('choose_keystore')
|
||||||
self.multisig_dialog(run_next=on_multisig)
|
self.multisig_dialog(run_next=on_multisig)
|
||||||
@@ -206,27 +205,24 @@ class BaseWizard(object):
|
|||||||
is_valid=v, allow_multi=True, show_wif_help=True)
|
is_valid=v, allow_multi=True, show_wif_help=True)
|
||||||
|
|
||||||
def on_import(self, text):
|
def on_import(self, text):
|
||||||
# create a temporary wallet and exploit that modifications
|
# text is already sanitized by is_address_list and is_private_keys_list
|
||||||
# will be reflected on self.storage
|
|
||||||
if keystore.is_address_list(text):
|
if keystore.is_address_list(text):
|
||||||
w = Imported_Wallet(self.storage)
|
self.data['addresses'] = {}
|
||||||
addresses = text.split()
|
for addr in text.split():
|
||||||
good_inputs, bad_inputs = w.import_addresses(addresses, write_to_disk=False)
|
assert bitcoin.is_address(addr)
|
||||||
|
self.data['addresses'][addr] = {}
|
||||||
elif keystore.is_private_key_list(text):
|
elif keystore.is_private_key_list(text):
|
||||||
|
self.data['addresses'] = {}
|
||||||
k = keystore.Imported_KeyStore({})
|
k = keystore.Imported_KeyStore({})
|
||||||
self.storage.put('keystore', k.dump())
|
|
||||||
w = Imported_Wallet(self.storage)
|
|
||||||
keys = keystore.get_private_keys(text)
|
keys = keystore.get_private_keys(text)
|
||||||
good_inputs, bad_inputs = w.import_private_keys(keys, None, write_to_disk=False)
|
for pk in keys:
|
||||||
self.keystores.append(w.keystore)
|
assert bitcoin.is_private_key(pk)
|
||||||
|
txin_type, pubkey = k.import_privkey(pk, None)
|
||||||
|
addr = bitcoin.pubkey_to_address(txin_type, pubkey)
|
||||||
|
self.data['addresses'][addr] = {'type':txin_type, 'pubkey':pubkey, 'redeem_script':None}
|
||||||
|
self.keystores.append(k)
|
||||||
else:
|
else:
|
||||||
return self.terminate()
|
return self.terminate()
|
||||||
if bad_inputs:
|
|
||||||
msg = "\n".join(f"{key[:10]}... ({msg})" for key, msg in bad_inputs[:10])
|
|
||||||
if len(bad_inputs) > 10: msg += '\n...'
|
|
||||||
self.show_error(_("The following inputs could not be imported")
|
|
||||||
+ f' ({len(bad_inputs)}):\n' + msg)
|
|
||||||
# FIXME what if len(good_inputs) == 0 ?
|
|
||||||
return self.run('create_wallet')
|
return self.run('create_wallet')
|
||||||
|
|
||||||
def restore_from_key(self):
|
def restore_from_key(self):
|
||||||
@@ -246,7 +242,7 @@ class BaseWizard(object):
|
|||||||
k = keystore.from_master_key(text)
|
k = keystore.from_master_key(text)
|
||||||
self.on_keystore(k)
|
self.on_keystore(k)
|
||||||
|
|
||||||
def choose_hw_device(self, purpose=HWD_SETUP_NEW_WALLET):
|
def choose_hw_device(self, purpose=HWD_SETUP_NEW_WALLET, storage=None):
|
||||||
title = _('Hardware Keystore')
|
title = _('Hardware Keystore')
|
||||||
# check available plugins
|
# check available plugins
|
||||||
supported_plugins = self.plugins.get_hardware_support()
|
supported_plugins = self.plugins.get_hardware_support()
|
||||||
@@ -348,7 +344,7 @@ class BaseWizard(object):
|
|||||||
xpub = self.plugin.get_xpub(device_info.device.id_, derivation, 'standard', self)
|
xpub = self.plugin.get_xpub(device_info.device.id_, derivation, 'standard', self)
|
||||||
password = keystore.Xpub.get_pubkey_from_xpub(xpub, ())
|
password = keystore.Xpub.get_pubkey_from_xpub(xpub, ())
|
||||||
try:
|
try:
|
||||||
self.storage.decrypt(password)
|
storage.decrypt(password)
|
||||||
except InvalidPassword:
|
except InvalidPassword:
|
||||||
# try to clear session so that user can type another passphrase
|
# try to clear session so that user can type another passphrase
|
||||||
devmgr = self.plugins.device_manager
|
devmgr = self.plugins.device_manager
|
||||||
@@ -539,32 +535,37 @@ class BaseWizard(object):
|
|||||||
|
|
||||||
def on_password(self, password, *, encrypt_storage,
|
def on_password(self, password, *, encrypt_storage,
|
||||||
storage_enc_version=STO_EV_USER_PW, encrypt_keystore):
|
storage_enc_version=STO_EV_USER_PW, encrypt_keystore):
|
||||||
assert not self.storage.file_exists(), "file was created too soon! plaintext keys might have been written to disk"
|
|
||||||
self.storage.set_keystore_encryption(bool(password) and encrypt_keystore)
|
|
||||||
if encrypt_storage:
|
|
||||||
self.storage.set_password(password, enc_version=storage_enc_version)
|
|
||||||
for k in self.keystores:
|
for k in self.keystores:
|
||||||
if k.may_have_password():
|
if k.may_have_password():
|
||||||
k.update_password(None, password)
|
k.update_password(None, password)
|
||||||
if self.wallet_type == 'standard':
|
if self.wallet_type == 'standard':
|
||||||
self.storage.put('seed_type', self.seed_type)
|
self.data['seed_type'] = self.seed_type
|
||||||
keys = self.keystores[0].dump()
|
keys = self.keystores[0].dump()
|
||||||
self.storage.put('keystore', keys)
|
self.data['keystore'] = keys
|
||||||
self.wallet = Standard_Wallet(self.storage)
|
|
||||||
self.run('create_addresses')
|
|
||||||
elif self.wallet_type == 'multisig':
|
elif self.wallet_type == 'multisig':
|
||||||
for i, k in enumerate(self.keystores):
|
for i, k in enumerate(self.keystores):
|
||||||
self.storage.put('x%d/'%(i+1), k.dump())
|
self.data['x%d/'%(i+1)] = k.dump()
|
||||||
self.storage.write()
|
|
||||||
self.wallet = Multisig_Wallet(self.storage)
|
|
||||||
self.run('create_addresses')
|
|
||||||
elif self.wallet_type == 'imported':
|
elif self.wallet_type == 'imported':
|
||||||
if len(self.keystores) > 0:
|
if len(self.keystores) > 0:
|
||||||
keys = self.keystores[0].dump()
|
keys = self.keystores[0].dump()
|
||||||
self.storage.put('keystore', keys)
|
self.data['keystore'] = keys
|
||||||
self.wallet = Imported_Wallet(self.storage)
|
else:
|
||||||
self.wallet.storage.write()
|
raise BaseException('Unknown wallet type')
|
||||||
self.terminate()
|
self.pw_args = password, encrypt_storage, storage_enc_version
|
||||||
|
self.terminate()
|
||||||
|
|
||||||
|
def create_storage(self, path):
|
||||||
|
if not self.pw_args:
|
||||||
|
return
|
||||||
|
password, encrypt_storage, storage_enc_version = self.pw_args
|
||||||
|
storage = WalletStorage(path)
|
||||||
|
for key, value in self.data.items():
|
||||||
|
storage.put(key, value)
|
||||||
|
storage.set_keystore_encryption(bool(password))# and encrypt_keystore)
|
||||||
|
if encrypt_storage:
|
||||||
|
storage.set_password(password, enc_version=storage_enc_version)
|
||||||
|
storage.write()
|
||||||
|
return storage
|
||||||
|
|
||||||
def show_xpub_and_add_cosigners(self, xpub):
|
def show_xpub_and_add_cosigners(self, xpub):
|
||||||
self.show_xpub_dialog(xpub=xpub, run_next=lambda x: self.run('choose_keystore'))
|
self.show_xpub_dialog(xpub=xpub, run_next=lambda x: self.run('choose_keystore'))
|
||||||
|
|||||||
@@ -530,8 +530,9 @@ class ElectrumWindow(App):
|
|||||||
else:
|
else:
|
||||||
return ''
|
return ''
|
||||||
|
|
||||||
def on_wizard_complete(self, wizard, wallet):
|
def on_wizard_complete(self, wizard, storage):
|
||||||
if wallet: # wizard returned a wallet
|
if storage:
|
||||||
|
wallet = Wallet(storage)
|
||||||
wallet.start_network(self.daemon.network)
|
wallet.start_network(self.daemon.network)
|
||||||
self.daemon.add_wallet(wallet)
|
self.daemon.add_wallet(wallet)
|
||||||
self.load_wallet(wallet)
|
self.load_wallet(wallet)
|
||||||
@@ -553,11 +554,10 @@ class ElectrumWindow(App):
|
|||||||
self.load_wallet(wallet)
|
self.load_wallet(wallet)
|
||||||
else:
|
else:
|
||||||
def launch_wizard():
|
def launch_wizard():
|
||||||
storage = WalletStorage(path, manual_upgrades=True)
|
wizard = Factory.InstallWizard(self.electrum_config, self.plugins)
|
||||||
wizard = Factory.InstallWizard(self.electrum_config, self.plugins, storage)
|
wizard.path = path
|
||||||
wizard.bind(on_wizard_complete=self.on_wizard_complete)
|
wizard.bind(on_wizard_complete=self.on_wizard_complete)
|
||||||
action = wizard.storage.get_action()
|
wizard.run('new')
|
||||||
wizard.run(action)
|
|
||||||
if not ask_if_wizard:
|
if not ask_if_wizard:
|
||||||
launch_wizard()
|
launch_wizard()
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -25,8 +25,8 @@ from .password_dialog import PasswordDialog
|
|||||||
|
|
||||||
# global Variables
|
# global Variables
|
||||||
is_test = (platform == "linux")
|
is_test = (platform == "linux")
|
||||||
test_seed = "time taxi field recycle tiny license olive virus report rare steel portion achieve"
|
|
||||||
test_seed = "grape impose jazz bind spatial mind jelly tourist tank today holiday stomach"
|
test_seed = "grape impose jazz bind spatial mind jelly tourist tank today holiday stomach"
|
||||||
|
test_seed = "time taxi field recycle tiny license olive virus report rare steel portion achieve"
|
||||||
test_xpub = "xpub661MyMwAqRbcEbvVtRRSjqxVnaWVUMewVzMiURAKyYratih4TtBpMypzzefmv8zUNebmNVzB3PojdC5sV2P9bDgMoo9B3SARw1MXUUfU1GL"
|
test_xpub = "xpub661MyMwAqRbcEbvVtRRSjqxVnaWVUMewVzMiURAKyYratih4TtBpMypzzefmv8zUNebmNVzB3PojdC5sV2P9bDgMoo9B3SARw1MXUUfU1GL"
|
||||||
|
|
||||||
Builder.load_string('''
|
Builder.load_string('''
|
||||||
@@ -629,7 +629,7 @@ class WizardKnownOTPDialog(WizardOTPDialogBase):
|
|||||||
|
|
||||||
def abort_wallet_creation(self):
|
def abort_wallet_creation(self):
|
||||||
self._on_release = True
|
self._on_release = True
|
||||||
os.unlink(self.wizard.storage.path)
|
os.unlink(self.path)
|
||||||
self.wizard.terminate()
|
self.wizard.terminate()
|
||||||
self.dismiss()
|
self.dismiss()
|
||||||
|
|
||||||
@@ -972,7 +972,8 @@ class InstallWizard(BaseWizard, Widget):
|
|||||||
t.start()
|
t.start()
|
||||||
|
|
||||||
def terminate(self, **kwargs):
|
def terminate(self, **kwargs):
|
||||||
self.dispatch('on_wizard_complete', self.wallet)
|
storage = self.create_storage(self.path)
|
||||||
|
self.dispatch('on_wizard_complete', storage)
|
||||||
|
|
||||||
def choice_dialog(self, **kwargs):
|
def choice_dialog(self, **kwargs):
|
||||||
choices = kwargs['choices']
|
choices = kwargs['choices']
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ from electrum.plugin import run_hook
|
|||||||
from electrum.base_wizard import GoBack
|
from electrum.base_wizard import GoBack
|
||||||
from electrum.util import (UserCancelled, PrintError, profiler,
|
from electrum.util import (UserCancelled, PrintError, profiler,
|
||||||
WalletFileException, BitcoinException, get_new_wallet_name)
|
WalletFileException, BitcoinException, get_new_wallet_name)
|
||||||
|
from electrum.wallet import Wallet
|
||||||
|
|
||||||
from .installwizard import InstallWizard
|
from .installwizard import InstallWizard
|
||||||
|
|
||||||
@@ -227,12 +228,18 @@ class ElectrumGui(PrintError):
|
|||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
if not wallet:
|
if not wallet:
|
||||||
wizard = InstallWizard(self.config, self.app, self.plugins, None)
|
wizard = InstallWizard(self.config, self.app, self.plugins)
|
||||||
try:
|
try:
|
||||||
if wizard.select_storage(path, self.daemon.get_wallet):
|
path, storage = wizard.select_storage(path, self.daemon.get_wallet)
|
||||||
wallet = wizard.run_and_get_wallet()
|
# storage is None if file does not exist
|
||||||
|
if storage is None:
|
||||||
|
wizard.path = path # needed by trustedcoin plugin
|
||||||
|
wizard.run('new')
|
||||||
|
storage = wizard.create_storage(path)
|
||||||
|
else:
|
||||||
|
wizard.run_upgrades(storage)
|
||||||
except UserCancelled:
|
except UserCancelled:
|
||||||
pass
|
return
|
||||||
except GoBack as e:
|
except GoBack as e:
|
||||||
self.print_error('[start_new_window] Exception caught (GoBack)', e)
|
self.print_error('[start_new_window] Exception caught (GoBack)', e)
|
||||||
except (WalletFileException, BitcoinException) as e:
|
except (WalletFileException, BitcoinException) as e:
|
||||||
@@ -243,9 +250,10 @@ class ElectrumGui(PrintError):
|
|||||||
return
|
return
|
||||||
finally:
|
finally:
|
||||||
wizard.terminate()
|
wizard.terminate()
|
||||||
if not wallet:
|
# return if wallet creation is not complete
|
||||||
|
if storage is None or storage.get_action():
|
||||||
return
|
return
|
||||||
|
wallet = Wallet(storage)
|
||||||
if not self.daemon.get_wallet(wallet.storage.path):
|
if not self.daemon.get_wallet(wallet.storage.path):
|
||||||
# wallet was not in memory
|
# wallet was not in memory
|
||||||
wallet.start_network(self.daemon.network)
|
wallet.start_network(self.daemon.network)
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ from .network_dialog import NetworkChoiceLayout
|
|||||||
from .util import (MessageBoxMixin, Buttons, icon_path, ChoicesLayout, WWLabel,
|
from .util import (MessageBoxMixin, Buttons, icon_path, ChoicesLayout, WWLabel,
|
||||||
InfoButton)
|
InfoButton)
|
||||||
from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW
|
from .password_dialog import PasswordLayout, PasswordLayoutForHW, PW_NEW
|
||||||
|
from electrum.plugin import run_hook
|
||||||
|
|
||||||
MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\
|
MSG_ENTER_PASSWORD = _("Choose a password to encrypt your wallet keys.") + '\n'\
|
||||||
+ _("Leave this field empty if you want to disable encryption.")
|
+ _("Leave this field empty if you want to disable encryption.")
|
||||||
@@ -110,8 +110,8 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
|
|
||||||
accept_signal = pyqtSignal()
|
accept_signal = pyqtSignal()
|
||||||
|
|
||||||
def __init__(self, config, app, plugins, storage):
|
def __init__(self, config, app, plugins):
|
||||||
BaseWizard.__init__(self, config, plugins, storage)
|
BaseWizard.__init__(self, config, plugins)
|
||||||
QDialog.__init__(self, None)
|
QDialog.__init__(self, None)
|
||||||
self.setWindowTitle('Electrum - ' + _('Install Wizard'))
|
self.setWindowTitle('Electrum - ' + _('Install Wizard'))
|
||||||
self.app = app
|
self.app = app
|
||||||
@@ -186,8 +186,8 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
vbox.addLayout(hbox2)
|
vbox.addLayout(hbox2)
|
||||||
self.set_layout(vbox, title=_('Electrum wallet'))
|
self.set_layout(vbox, title=_('Electrum wallet'))
|
||||||
|
|
||||||
self.storage = WalletStorage(path, manual_upgrades=True)
|
self.temp_storage = WalletStorage(path, manual_upgrades=True)
|
||||||
wallet_folder = os.path.dirname(self.storage.path)
|
wallet_folder = os.path.dirname(self.temp_storage.path)
|
||||||
|
|
||||||
def on_choose():
|
def on_choose():
|
||||||
path, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
|
path, __ = QFileDialog.getOpenFileName(self, "Select your wallet file", wallet_folder)
|
||||||
@@ -199,25 +199,25 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
wallet_from_memory = get_wallet_from_daemon(path)
|
wallet_from_memory = get_wallet_from_daemon(path)
|
||||||
try:
|
try:
|
||||||
if wallet_from_memory:
|
if wallet_from_memory:
|
||||||
self.storage = wallet_from_memory.storage
|
self.temp_storage = wallet_from_memory.storage
|
||||||
else:
|
else:
|
||||||
self.storage = WalletStorage(path, manual_upgrades=True)
|
self.temp_storage = WalletStorage(path, manual_upgrades=True)
|
||||||
self.next_button.setEnabled(True)
|
self.next_button.setEnabled(True)
|
||||||
except BaseException:
|
except BaseException:
|
||||||
traceback.print_exc(file=sys.stderr)
|
traceback.print_exc(file=sys.stderr)
|
||||||
self.storage = None
|
self.temp_storage = None
|
||||||
self.next_button.setEnabled(False)
|
self.next_button.setEnabled(False)
|
||||||
if self.storage:
|
if self.temp_storage:
|
||||||
if not self.storage.file_exists():
|
if not self.temp_storage.file_exists():
|
||||||
msg =_("This file does not exist.") + '\n' \
|
msg =_("This file does not exist.") + '\n' \
|
||||||
+ _("Press 'Next' to create this wallet, or choose another file.")
|
+ _("Press 'Next' to create this wallet, or choose another file.")
|
||||||
pw = False
|
pw = False
|
||||||
elif not wallet_from_memory:
|
elif not wallet_from_memory:
|
||||||
if self.storage.is_encrypted_with_user_pw():
|
if self.temp_storage.is_encrypted_with_user_pw():
|
||||||
msg = _("This file is encrypted with a password.") + '\n' \
|
msg = _("This file is encrypted with a password.") + '\n' \
|
||||||
+ _('Enter your password or choose another file.')
|
+ _('Enter your password or choose another file.')
|
||||||
pw = True
|
pw = True
|
||||||
elif self.storage.is_encrypted_with_hw_device():
|
elif self.temp_storage.is_encrypted_with_hw_device():
|
||||||
msg = _("This file is encrypted using a hardware device.") + '\n' \
|
msg = _("This file is encrypted using a hardware device.") + '\n' \
|
||||||
+ _("Press 'Next' to choose device to decrypt.")
|
+ _("Press 'Next' to choose device to decrypt.")
|
||||||
pw = False
|
pw = False
|
||||||
@@ -242,24 +242,24 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
|
|
||||||
button.clicked.connect(on_choose)
|
button.clicked.connect(on_choose)
|
||||||
self.name_e.textChanged.connect(on_filename)
|
self.name_e.textChanged.connect(on_filename)
|
||||||
n = os.path.basename(self.storage.path)
|
n = os.path.basename(self.temp_storage.path)
|
||||||
self.name_e.setText(n)
|
self.name_e.setText(n)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
if self.loop.exec_() != 2: # 2 = next
|
if self.loop.exec_() != 2: # 2 = next
|
||||||
return
|
raise UserCancelled
|
||||||
if self.storage.file_exists() and not self.storage.is_encrypted():
|
if self.temp_storage.file_exists() and not self.temp_storage.is_encrypted():
|
||||||
break
|
break
|
||||||
if not self.storage.file_exists():
|
if not self.temp_storage.file_exists():
|
||||||
break
|
break
|
||||||
wallet_from_memory = get_wallet_from_daemon(self.storage.path)
|
wallet_from_memory = get_wallet_from_daemon(self.temp_storage.path)
|
||||||
if wallet_from_memory:
|
if wallet_from_memory:
|
||||||
return wallet_from_memory
|
return wallet_from_memory
|
||||||
if self.storage.file_exists() and self.storage.is_encrypted():
|
if self.temp_storage.file_exists() and self.temp_storage.is_encrypted():
|
||||||
if self.storage.is_encrypted_with_user_pw():
|
if self.temp_storage.is_encrypted_with_user_pw():
|
||||||
password = self.pw_e.text()
|
password = self.pw_e.text()
|
||||||
try:
|
try:
|
||||||
self.storage.decrypt(password)
|
self.temp_storage.decrypt(password)
|
||||||
break
|
break
|
||||||
except InvalidPassword as e:
|
except InvalidPassword as e:
|
||||||
QMessageBox.information(None, _('Error'), str(e))
|
QMessageBox.information(None, _('Error'), str(e))
|
||||||
@@ -268,9 +268,9 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
traceback.print_exc(file=sys.stdout)
|
traceback.print_exc(file=sys.stdout)
|
||||||
QMessageBox.information(None, _('Error'), str(e))
|
QMessageBox.information(None, _('Error'), str(e))
|
||||||
return
|
return
|
||||||
elif self.storage.is_encrypted_with_hw_device():
|
elif self.temp_storage.is_encrypted_with_hw_device():
|
||||||
try:
|
try:
|
||||||
self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET)
|
self.run('choose_hw_device', HWD_SETUP_DECRYPT_WALLET, self.temp_storage)
|
||||||
except InvalidPassword as e:
|
except InvalidPassword as e:
|
||||||
QMessageBox.information(
|
QMessageBox.information(
|
||||||
None, _('Error'),
|
None, _('Error'),
|
||||||
@@ -282,31 +282,32 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
traceback.print_exc(file=sys.stdout)
|
traceback.print_exc(file=sys.stdout)
|
||||||
QMessageBox.information(None, _('Error'), str(e))
|
QMessageBox.information(None, _('Error'), str(e))
|
||||||
return
|
return
|
||||||
if self.storage.is_past_initial_decryption():
|
if self.temp_storage.is_past_initial_decryption():
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
raise Exception('Unexpected encryption version')
|
raise Exception('Unexpected encryption version')
|
||||||
return True
|
|
||||||
|
|
||||||
def run_and_get_wallet(self):
|
return self.temp_storage.path, self.temp_storage if self.temp_storage.file_exists() else None
|
||||||
path = self.storage.path
|
|
||||||
if self.storage.requires_split():
|
def run_upgrades(self, storage):
|
||||||
|
path = storage.path
|
||||||
|
if storage.requires_split():
|
||||||
self.hide()
|
self.hide()
|
||||||
msg = _("The wallet '{}' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n"
|
msg = _("The wallet '{}' contains multiple accounts, which are no longer supported since Electrum 2.7.\n\n"
|
||||||
"Do you want to split your wallet into multiple files?").format(path)
|
"Do you want to split your wallet into multiple files?").format(path)
|
||||||
if not self.question(msg):
|
if not self.question(msg):
|
||||||
return
|
return
|
||||||
file_list = '\n'.join(self.storage.split_accounts())
|
file_list = '\n'.join(storage.split_accounts())
|
||||||
msg = _('Your accounts have been moved to') + ':\n' + file_list + '\n\n'+ _('Do you want to delete the old file') + ':\n' + path
|
msg = _('Your accounts have been moved to') + ':\n' + file_list + '\n\n'+ _('Do you want to delete the old file') + ':\n' + path
|
||||||
if self.question(msg):
|
if self.question(msg):
|
||||||
os.remove(path)
|
os.remove(path)
|
||||||
self.show_warning(_('The file was removed'))
|
self.show_warning(_('The file was removed'))
|
||||||
return
|
return
|
||||||
|
|
||||||
action = self.storage.get_action()
|
action = storage.get_action()
|
||||||
if action and action not in ('new', 'upgrade_storage'):
|
if action: #< and action not in ('new', 'upgrade_storage'):
|
||||||
self.hide()
|
self.hide()
|
||||||
msg = _("The file '{}' contains an incompletely created wallet.\n"
|
msg = _("The file '{}' contains an incompletely created wallet.\n"
|
||||||
"Do you want to complete its creation now?").format(path)
|
"Do you want to complete its creation now?").format(path)
|
||||||
@@ -316,13 +317,15 @@ class InstallWizard(QDialog, MessageBoxMixin, BaseWizard):
|
|||||||
self.show_warning(_('The file was removed'))
|
self.show_warning(_('The file was removed'))
|
||||||
return
|
return
|
||||||
self.show()
|
self.show()
|
||||||
if action:
|
self.data = storage.data
|
||||||
# self.wallet is set in run
|
|
||||||
self.run(action)
|
self.run(action)
|
||||||
return self.wallet
|
for k, v in self.data.items():
|
||||||
|
storage.put(k, v)
|
||||||
|
storage.write()
|
||||||
|
return
|
||||||
|
|
||||||
self.wallet = Wallet(self.storage)
|
if storage.requires_upgrade():
|
||||||
return self.wallet
|
self.upgrade_storage(storage)
|
||||||
|
|
||||||
def finished(self):
|
def finished(self):
|
||||||
"""Called in hardware client wrapper, in order to close popups."""
|
"""Called in hardware client wrapper, in order to close popups."""
|
||||||
|
|||||||
@@ -200,7 +200,7 @@ class Plugin(TrustedCoinPlugin):
|
|||||||
|
|
||||||
def go_online_dialog(self, wizard: InstallWizard):
|
def go_online_dialog(self, wizard: InstallWizard):
|
||||||
msg = [
|
msg = [
|
||||||
_("Your wallet file is: {}.").format(os.path.abspath(wizard.storage.path)),
|
_("Your wallet file is: {}.").format(os.path.abspath(wizard.path)),
|
||||||
_("You need to be online in order to complete the creation of "
|
_("You need to be online in order to complete the creation of "
|
||||||
"your wallet. If you generated your seed on an offline "
|
"your wallet. If you generated your seed on an offline "
|
||||||
'computer, click on "{}" to close this window, move your '
|
'computer, click on "{}" to close this window, move your '
|
||||||
@@ -209,6 +209,7 @@ class Plugin(TrustedCoinPlugin):
|
|||||||
_('If you are online, click on "{}" to continue.').format(_('Next'))
|
_('If you are online, click on "{}" to continue.').format(_('Next'))
|
||||||
]
|
]
|
||||||
msg = '\n\n'.join(msg)
|
msg = '\n\n'.join(msg)
|
||||||
|
wizard.create_storage(wizard.path)
|
||||||
wizard.reset_stack()
|
wizard.reset_stack()
|
||||||
wizard.confirm_dialog(title='', message=msg, run_next = lambda x: wizard.run('accept_terms_of_use'))
|
wizard.confirm_dialog(title='', message=msg, run_next = lambda x: wizard.run('accept_terms_of_use'))
|
||||||
|
|
||||||
|
|||||||
@@ -578,12 +578,9 @@ class TrustedCoinPlugin(BasePlugin):
|
|||||||
|
|
||||||
def on_password(self, wizard, password, encrypt_storage, k1, k2):
|
def on_password(self, wizard, password, encrypt_storage, k1, k2):
|
||||||
k1.update_password(None, password)
|
k1.update_password(None, password)
|
||||||
wizard.storage.set_keystore_encryption(bool(password))
|
wizard.data['x1/'] = k1.dump()
|
||||||
if encrypt_storage:
|
wizard.data['x2/'] = k2.dump()
|
||||||
wizard.storage.set_password(password, enc_version=STO_EV_USER_PW)
|
wizard.pw_args = password, encrypt_storage, STO_EV_USER_PW
|
||||||
wizard.storage.put('x1/', k1.dump())
|
|
||||||
wizard.storage.put('x2/', k2.dump())
|
|
||||||
wizard.storage.write()
|
|
||||||
self.go_online_dialog(wizard)
|
self.go_online_dialog(wizard)
|
||||||
|
|
||||||
def restore_wallet(self, wizard):
|
def restore_wallet(self, wizard):
|
||||||
@@ -618,34 +615,26 @@ class TrustedCoinPlugin(BasePlugin):
|
|||||||
self.create_keystore(wizard, seed, passphrase)
|
self.create_keystore(wizard, seed, passphrase)
|
||||||
|
|
||||||
def on_restore_pw(self, wizard, seed, passphrase, password, encrypt_storage):
|
def on_restore_pw(self, wizard, seed, passphrase, password, encrypt_storage):
|
||||||
storage = wizard.storage
|
|
||||||
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed, passphrase)
|
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed, passphrase)
|
||||||
k1 = keystore.from_xprv(xprv1)
|
k1 = keystore.from_xprv(xprv1)
|
||||||
k2 = keystore.from_xprv(xprv2)
|
k2 = keystore.from_xprv(xprv2)
|
||||||
k1.add_seed(seed)
|
k1.add_seed(seed)
|
||||||
k1.update_password(None, password)
|
k1.update_password(None, password)
|
||||||
k2.update_password(None, password)
|
k2.update_password(None, password)
|
||||||
storage.put('x1/', k1.dump())
|
wizard.data['x1/'] = k1.dump()
|
||||||
storage.put('x2/', k2.dump())
|
wizard.data['x2/'] = k2.dump()
|
||||||
long_user_id, short_id = get_user_id(storage)
|
long_user_id, short_id = get_user_id(wizard.data)
|
||||||
xtype = xpub_type(xpub1)
|
xtype = xpub_type(xpub1)
|
||||||
xpub3 = make_xpub(get_signing_xpub(xtype), long_user_id)
|
xpub3 = make_xpub(get_signing_xpub(xtype), long_user_id)
|
||||||
k3 = keystore.from_xpub(xpub3)
|
k3 = keystore.from_xpub(xpub3)
|
||||||
storage.put('x3/', k3.dump())
|
wizard.data['x3/'] = k3.dump()
|
||||||
|
wizard.pw_args = password, encrypt_storage, STO_EV_USER_PW
|
||||||
storage.set_keystore_encryption(bool(password))
|
|
||||||
if encrypt_storage:
|
|
||||||
storage.set_password(password, enc_version=STO_EV_USER_PW)
|
|
||||||
|
|
||||||
wizard.wallet = Wallet_2fa(storage)
|
|
||||||
wizard.create_addresses()
|
|
||||||
|
|
||||||
|
|
||||||
def create_remote_key(self, email, wizard):
|
def create_remote_key(self, email, wizard):
|
||||||
xpub1 = wizard.storage.get('x1/')['xpub']
|
xpub1 = wizard.data['x1/']['xpub']
|
||||||
xpub2 = wizard.storage.get('x2/')['xpub']
|
xpub2 = wizard.data['x2/']['xpub']
|
||||||
# Generate third key deterministically.
|
# Generate third key deterministically.
|
||||||
long_user_id, short_id = get_user_id(wizard.storage)
|
long_user_id, short_id = get_user_id(wizard.data)
|
||||||
xtype = xpub_type(xpub1)
|
xtype = xpub_type(xpub1)
|
||||||
xpub3 = make_xpub(get_signing_xpub(xtype), long_user_id)
|
xpub3 = make_xpub(get_signing_xpub(xtype), long_user_id)
|
||||||
# secret must be sent by the server
|
# secret must be sent by the server
|
||||||
@@ -709,16 +698,14 @@ class TrustedCoinPlugin(BasePlugin):
|
|||||||
wizard.terminate()
|
wizard.terminate()
|
||||||
else:
|
else:
|
||||||
k3 = keystore.from_xpub(xpub3)
|
k3 = keystore.from_xpub(xpub3)
|
||||||
wizard.storage.put('x3/', k3.dump())
|
wizard.data['x3/'] = k3.dump()
|
||||||
wizard.storage.put('use_trustedcoin', True)
|
wizard.data['use_trustedcoin'] = True
|
||||||
wizard.storage.write()
|
wizard.terminate()
|
||||||
wizard.wallet = Wallet_2fa(wizard.storage)
|
|
||||||
wizard.run('create_addresses')
|
|
||||||
|
|
||||||
def on_reset_auth(self, wizard, short_id, seed, passphrase, xpub3):
|
def on_reset_auth(self, wizard, short_id, seed, passphrase, xpub3):
|
||||||
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed, passphrase)
|
xprv1, xpub1, xprv2, xpub2 = self.xkeys_from_seed(seed, passphrase)
|
||||||
if (wizard.storage.get('x1/')['xpub'] != xpub1 or
|
if (wizard.data['x1/']['xpub'] != xpub1 or
|
||||||
wizard.storage.get('x2/')['xpub'] != xpub2):
|
wizard.data['x2/']['xpub'] != xpub2):
|
||||||
wizard.show_message(_('Incorrect seed'))
|
wizard.show_message(_('Incorrect seed'))
|
||||||
return
|
return
|
||||||
r = server.get_challenge(short_id)
|
r = server.get_challenge(short_id)
|
||||||
|
|||||||
@@ -102,20 +102,6 @@ class JsonDB(PrintError):
|
|||||||
self.modified = True
|
self.modified = True
|
||||||
self.data.pop(key)
|
self.data.pop(key)
|
||||||
|
|
||||||
def get_all_data(self) -> dict:
|
|
||||||
with self.db_lock:
|
|
||||||
return copy.deepcopy(self.data)
|
|
||||||
|
|
||||||
def overwrite_all_data(self, data: dict) -> None:
|
|
||||||
try:
|
|
||||||
json.dumps(data, cls=util.MyEncoder)
|
|
||||||
except:
|
|
||||||
self.print_error(f"json error: cannot save {repr(data)}")
|
|
||||||
return
|
|
||||||
with self.db_lock:
|
|
||||||
self.modified = True
|
|
||||||
self.data = copy.deepcopy(data)
|
|
||||||
|
|
||||||
@profiler
|
@profiler
|
||||||
def write(self):
|
def write(self):
|
||||||
with self.db_lock:
|
with self.db_lock:
|
||||||
|
|||||||
Reference in New Issue
Block a user