wizard: add password only once all keystores are known
This commit is contained in:
parent
b907a668ec
commit
3ac357171a
|
@ -159,13 +159,8 @@ class BaseWizard(object):
|
|||
self.restore_keys_dialog(title=title, message=message, run_next=self.on_restore_from_key, is_valid=v)
|
||||
|
||||
def on_restore_from_key(self, text):
|
||||
def f(password):
|
||||
k = keystore.from_keys(text, password)
|
||||
self.on_keystore(k, password)
|
||||
if keystore.is_private(text):
|
||||
self.run('request_password', run_next=f)
|
||||
else:
|
||||
f(None)
|
||||
k = keystore.from_keys(text)
|
||||
self.on_keystore(k)
|
||||
|
||||
def choose_hw_device(self):
|
||||
title = _('Hardware Keystore')
|
||||
|
@ -228,43 +223,36 @@ class BaseWizard(object):
|
|||
|
||||
def on_seed(self, seed, add_passphrase, is_bip39):
|
||||
self.is_bip39 = is_bip39
|
||||
f = lambda x: self.run('on_passphrase', seed, x)
|
||||
f = lambda x: self.run('create_keystore', seed, x)
|
||||
if add_passphrase:
|
||||
self.request_passphrase(run_next=f)
|
||||
else:
|
||||
f('')
|
||||
|
||||
def on_passphrase(self, seed, passphrase):
|
||||
f = lambda x: self.run('on_password', seed, passphrase, x)
|
||||
self.request_password(run_next=f)
|
||||
|
||||
def on_password(self, seed, passphrase, password):
|
||||
def create_keystore(self, seed, passphrase):
|
||||
if self.is_bip39:
|
||||
f = lambda account_id: self.run('on_bip44', seed, passphrase, password, account_id)
|
||||
f = lambda account_id: self.run('on_bip44', seed, passphrase, account_id)
|
||||
self.account_id_dialog(run_next=f)
|
||||
else:
|
||||
k = keystore.from_seed(seed, passphrase, password)
|
||||
self.on_keystore(k, password)
|
||||
k = keystore.from_seed(seed, passphrase)
|
||||
self.on_keystore(k)
|
||||
|
||||
def on_bip44(self, seed, passphrase, password, account_id):
|
||||
def on_bip44(self, seed, passphrase, account_id):
|
||||
import keystore
|
||||
k = keystore.BIP32_KeyStore({})
|
||||
bip32_seed = keystore.bip39_to_seed(seed, passphrase)
|
||||
derivation = "m/44'/0'/%d'"%account_id
|
||||
k.add_xprv_from_seed(bip32_seed, derivation, password)
|
||||
self.on_keystore(k, password)
|
||||
k.add_xprv_from_seed(bip32_seed, derivation)
|
||||
self.on_keystore(k)
|
||||
|
||||
def on_keystore(self, k, password):
|
||||
def on_keystore(self, k):
|
||||
if self.wallet_type == 'standard':
|
||||
self.storage.put('keystore', k.dump())
|
||||
self.wallet = Standard_Wallet(self.storage)
|
||||
self.run('create_addresses')
|
||||
self.keystores.append(k)
|
||||
self.run('create_wallet')
|
||||
elif self.wallet_type == 'multisig':
|
||||
|
||||
if k.xpub in map(lambda x: x.xpub, self.keystores):
|
||||
raise BaseException('duplicate key')
|
||||
self.keystores.append(k)
|
||||
|
||||
if len(self.keystores) == 1:
|
||||
xpub = k.get_master_public_key()
|
||||
self.stack = []
|
||||
|
@ -272,11 +260,29 @@ class BaseWizard(object):
|
|||
elif len(self.keystores) < self.n:
|
||||
self.run('choose_keystore')
|
||||
else:
|
||||
for i, k in enumerate(self.keystores):
|
||||
self.storage.put('x%d/'%(i+1), k.dump())
|
||||
self.storage.write()
|
||||
self.wallet = Multisig_Wallet(self.storage)
|
||||
self.run('create_addresses')
|
||||
self.run('create_wallet')
|
||||
|
||||
def create_wallet(self):
|
||||
if any(k.may_have_password() for k in self.keystores):
|
||||
self.request_password(run_next=self.on_password)
|
||||
else:
|
||||
self.on_password(None)
|
||||
|
||||
def on_password(self, password):
|
||||
self.storage.put('use_encryption', bool(password))
|
||||
for k in self.keystores:
|
||||
if k.may_have_password():
|
||||
k.update_password(None, password)
|
||||
if self.wallet_type == 'standard':
|
||||
self.storage.put('keystore', k.dump())
|
||||
self.wallet = Standard_Wallet(self.storage)
|
||||
self.run('create_addresses')
|
||||
elif self.wallet_type == 'multisig':
|
||||
for i, k in enumerate(self.keystores):
|
||||
self.storage.put('x%d/'%(i+1), k.dump())
|
||||
self.storage.write()
|
||||
self.wallet = Multisig_Wallet(self.storage)
|
||||
self.run('create_addresses')
|
||||
|
||||
def show_xpub_and_add_cosigners(self, xpub):
|
||||
self.show_xpub_dialog(xpub=xpub, run_next=lambda x: self.run('choose_keystore'))
|
||||
|
|
|
@ -49,12 +49,14 @@ class KeyStore(PrintError):
|
|||
def can_import(self):
|
||||
return False
|
||||
|
||||
|
||||
class Software_KeyStore(KeyStore):
|
||||
|
||||
def __init__(self):
|
||||
KeyStore.__init__(self)
|
||||
|
||||
def may_have_password(self):
|
||||
return not self.is_watching_only()
|
||||
|
||||
def sign_message(self, sequence, message, password):
|
||||
sec = self.get_private_key(sequence, password)
|
||||
key = regenerate_key(sec)
|
||||
|
@ -161,12 +163,10 @@ class Deterministic_KeyStore(Software_KeyStore):
|
|||
def can_change_password(self):
|
||||
return not self.is_watching_only()
|
||||
|
||||
def add_seed(self, seed, password):
|
||||
def add_seed(self, seed):
|
||||
if self.seed:
|
||||
raise Exception("a seed exists")
|
||||
self.seed_version, self.seed = self.format_seed(seed)
|
||||
if password:
|
||||
self.seed = pw_encode(self.seed, password)
|
||||
|
||||
def get_seed(self, password):
|
||||
return pw_decode(self.seed, password).encode('utf8')
|
||||
|
@ -179,9 +179,6 @@ class Xpub:
|
|||
self.xpub_receive = None
|
||||
self.xpub_change = None
|
||||
|
||||
def add_master_public_key(self, xpub):
|
||||
self.xpub = xpub
|
||||
|
||||
def get_master_public_key(self):
|
||||
return self.xpub
|
||||
|
||||
|
@ -237,9 +234,6 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
|
|||
d['xprv'] = self.xprv
|
||||
return d
|
||||
|
||||
def add_master_private_key(self, xprv, password):
|
||||
self.xprv = pw_encode(xprv, password)
|
||||
|
||||
def get_master_private_key(self, password):
|
||||
return pw_decode(self.xprv, password)
|
||||
|
||||
|
@ -297,15 +291,14 @@ class BIP32_KeyStore(Deterministic_KeyStore, Xpub):
|
|||
def get_mnemonic(self, password):
|
||||
return self.get_seed(password)
|
||||
|
||||
def add_xprv(self, xprv, password):
|
||||
xpub = bitcoin.xpub_from_xprv(xprv)
|
||||
self.add_master_private_key(xprv, password)
|
||||
self.add_master_public_key(xpub)
|
||||
def add_xprv(self, xprv):
|
||||
self.xprv = xprv
|
||||
self.xpub = bitcoin.xpub_from_xprv(xprv)
|
||||
|
||||
def add_xprv_from_seed(self, bip32_seed, derivation, password):
|
||||
def add_xprv_from_seed(self, bip32_seed, derivation):
|
||||
xprv, xpub = bip32_root(bip32_seed)
|
||||
xprv, xpub = bip32_private_derivation(xprv, "m/", derivation)
|
||||
self.add_xprv(xprv, password)
|
||||
self.add_xprv(xprv)
|
||||
|
||||
def can_sign(self, xpub):
|
||||
return xpub == self.xpub and self.xprv is not None
|
||||
|
@ -328,9 +321,9 @@ class Old_KeyStore(Deterministic_KeyStore):
|
|||
d['mpk'] = self.mpk.encode('hex')
|
||||
return d
|
||||
|
||||
def add_seed(self, seed, password):
|
||||
Deterministic_KeyStore.add_seed(self, seed, password)
|
||||
self.mpk = self.mpk_from_seed(self.get_seed(password))
|
||||
def add_seed(self, seed):
|
||||
Deterministic_KeyStore.add_seed(self, seed)
|
||||
self.mpk = self.mpk_from_seed(seed)
|
||||
|
||||
def add_master_public_key(self, mpk):
|
||||
self.mpk = mpk.decode('hex')
|
||||
|
@ -469,6 +462,9 @@ class Hardware_KeyStore(KeyStore, Xpub):
|
|||
self.derivation = d.get('derivation')
|
||||
self.handler = None
|
||||
|
||||
def may_have_password(self):
|
||||
return False
|
||||
|
||||
def is_deterministic(self):
|
||||
return True
|
||||
|
||||
|
@ -623,22 +619,21 @@ is_bip32_key = lambda x: is_xprv(x) or is_xpub(x)
|
|||
def bip44_derivation(account_id):
|
||||
return "m/44'/0'/%d'"% int(account_id)
|
||||
|
||||
def from_seed(seed, passphrase, password):
|
||||
def from_seed(seed, passphrase):
|
||||
if is_old_seed(seed):
|
||||
keystore = Old_KeyStore({})
|
||||
keystore.add_seed(seed, password)
|
||||
keystore.add_seed(seed)
|
||||
elif is_new_seed(seed):
|
||||
keystore = BIP32_KeyStore({})
|
||||
keystore.add_seed(seed, password)
|
||||
keystore.add_seed(seed)
|
||||
bip32_seed = Mnemonic.mnemonic_to_seed(seed, passphrase)
|
||||
keystore.add_xprv_from_seed(bip32_seed, "m/", password)
|
||||
keystore.add_xprv_from_seed(bip32_seed, "m/")
|
||||
return keystore
|
||||
|
||||
def from_private_key_list(text, password):
|
||||
def from_private_key_list(text):
|
||||
keystore = Imported_KeyStore({})
|
||||
for x in text.split():
|
||||
keystore.import_key(x, None)
|
||||
keystore.update_password(None, password)
|
||||
return keystore
|
||||
|
||||
def from_old_mpk(mpk):
|
||||
|
@ -647,36 +642,36 @@ def from_old_mpk(mpk):
|
|||
return keystore
|
||||
|
||||
def from_xpub(xpub):
|
||||
keystore = BIP32_KeyStore({})
|
||||
keystore.add_master_public_key(xpub)
|
||||
return keystore
|
||||
k = BIP32_KeyStore({})
|
||||
k.xpub = xpub
|
||||
return k
|
||||
|
||||
def from_xprv(xprv, password):
|
||||
def from_xprv(xprv):
|
||||
xpub = bitcoin.xpub_from_xprv(xprv)
|
||||
keystore = BIP32_KeyStore({})
|
||||
keystore.add_master_private_key(xprv, password)
|
||||
keystore.add_master_public_key(xpub)
|
||||
return keystore
|
||||
k = BIP32_KeyStore({})
|
||||
k.xprv = xprv
|
||||
k.xpub = xpub
|
||||
return k
|
||||
|
||||
def xprv_from_seed(seed, password):
|
||||
def xprv_from_seed(seed):
|
||||
# do not store the seed, only the master xprv
|
||||
xprv, xpub = bip32_root(Mnemonic.mnemonic_to_seed(seed, ''))
|
||||
return from_xprv(xprv, password)
|
||||
return from_xprv(xprv)
|
||||
|
||||
def xpub_from_seed(seed, passphrase):
|
||||
def xpub_from_seed(seed):
|
||||
# store only master xpub
|
||||
xprv, xpub = bip32_root(Mnemonic.mnemonic_to_seed(seed,''))
|
||||
return from_xpub(xpub)
|
||||
|
||||
def from_keys(text, password):
|
||||
def from_keys(text):
|
||||
if is_xprv(text):
|
||||
k = from_xprv(text, password)
|
||||
k = from_xprv(text)
|
||||
elif is_old_mpk(text):
|
||||
k = from_old_mpk(text)
|
||||
elif is_xpub(text):
|
||||
k = from_xpub(text)
|
||||
elif is_private_key_list(text):
|
||||
k = from_private_key_list(text, password)
|
||||
k = from_private_key_list(text)
|
||||
else:
|
||||
raise BaseException('Invalid key')
|
||||
return k
|
||||
|
|
|
@ -352,14 +352,20 @@ class TrustedCoinPlugin(BasePlugin):
|
|||
seed = self.make_seed()
|
||||
wizard.show_seed_dialog(run_next=wizard.confirm_seed, seed_text=seed)
|
||||
|
||||
def create_keystore(self, wizard, seed, password):
|
||||
def create_keystore(self, wizard, seed, passphrase):
|
||||
assert passphrase == ''
|
||||
# this overloads the wizard's method
|
||||
words = seed.split()
|
||||
n = len(words)/2
|
||||
keystore1 = keystore.xprv_from_seed(' '.join(words[0:n]), password)
|
||||
keystore2 = keystore.xpub_from_seed(' '.join(words[n:]))
|
||||
wizard.storage.put('x1/', keystore1.dump())
|
||||
wizard.storage.put('x2/', keystore2.dump())
|
||||
k1 = keystore.xprv_from_seed(' '.join(words[0:n]))
|
||||
k2 = keystore.xpub_from_seed(' '.join(words[n:]))
|
||||
wizard.request_password(run_next=lambda pw: self.on_password(wizard, pw, k1, k2))
|
||||
|
||||
def on_password(self, wizard, password, k1, k2):
|
||||
k1.update_password(None, password)
|
||||
wizard.storage.put('use_encryption', bool(password))
|
||||
wizard.storage.put('x1/', k1.dump())
|
||||
wizard.storage.put('x2/', k2.dump())
|
||||
wizard.storage.write()
|
||||
msg = [
|
||||
_("Your wallet file is: %s.")%os.path.abspath(wizard.storage.path),
|
||||
|
@ -389,14 +395,17 @@ class TrustedCoinPlugin(BasePlugin):
|
|||
storage = wizard.storage
|
||||
words = seed.split()
|
||||
n = len(words)/2
|
||||
keystore1 = keystore.xprv_from_seed(' '.join(words[0:n]), password)
|
||||
keystore2 = keystore.xprv_from_seed(' '.join(words[n:]), password)
|
||||
storage.put('x1/', keystore1.dump())
|
||||
storage.put('x2/', keystore2.dump())
|
||||
k1 = keystore.xprv_from_seed(' '.join(words[0:n]))
|
||||
k2 = keystore.xprv_from_seed(' '.join(words[n:]))
|
||||
k1.update_password(None, password)
|
||||
k2.update_password(None, password)
|
||||
long_user_id, short_id = get_user_id(storage)
|
||||
xpub3 = make_xpub(signing_xpub, long_user_id)
|
||||
keystore3 = keystore.from_xpub(xpub3)
|
||||
storage.put('x3/', keystore3.dump())
|
||||
k3 = keystore.from_xpub(xpub3)
|
||||
storage.put('use_encryption', bool(password))
|
||||
storage.put('x1/', k1.dump())
|
||||
storage.put('x2/', k2.dump())
|
||||
storage.put('x3/', k3.dump())
|
||||
wizard.wallet = Wallet(storage)
|
||||
wizard.create_addresses()
|
||||
|
||||
|
@ -436,8 +445,8 @@ class TrustedCoinPlugin(BasePlugin):
|
|||
if not self.setup_google_auth(wizard, short_id, otp_secret):
|
||||
wizard.show_message("otp error")
|
||||
return
|
||||
keystore3 = keystore.from_xpub(xpub3)
|
||||
wizard.storage.put('x3/', keystore3.dump())
|
||||
k3 = keystore.from_xpub(xpub3)
|
||||
wizard.storage.put('x3/', k3.dump())
|
||||
wizard.storage.put('use_trustedcoin', True)
|
||||
wizard.storage.write()
|
||||
wizard.wallet = Wallet(wizard.storage)
|
||||
|
|
Loading…
Reference in New Issue