mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-04-21 01:46:59 +08:00
in test mode, allow callers to create wallets without data keys
This commit is contained in:
@@ -65,6 +65,7 @@ from .schemas import *
|
||||
|
||||
import virtualchain
|
||||
from virtualchain.lib.ecdsalib import *
|
||||
import keylib
|
||||
|
||||
from .logger import get_logger
|
||||
|
||||
@@ -111,23 +112,34 @@ def encrypt_wallet(decrypted_wallet, password, test_legacy=False):
|
||||
wallet = {
|
||||
'owner_addresses': [owner_address],
|
||||
'payment_addresses': decrypted_wallet['payment_addresses'],
|
||||
'data_pubkey': data_pubkey,
|
||||
'data_pubkeys': [data_pubkey],
|
||||
'version': decrypted_wallet['version'],
|
||||
'enc': None, # to be filled in
|
||||
}
|
||||
|
||||
if data_pubkey:
|
||||
wallet['data_pubkey'] = data_pubkey
|
||||
wallet['data_pubkeys'] = [data_pubkey]
|
||||
|
||||
wallet_enc = {
|
||||
'owner_privkey': decrypted_wallet['owner_privkey'],
|
||||
'payment_privkey': decrypted_wallet['payment_privkey'],
|
||||
'data_privkey': data_privkey_info
|
||||
}
|
||||
|
||||
if data_privkey_info:
|
||||
wallet_enc['data_privkey'] = data_privkey_info
|
||||
|
||||
# extra sanity check: make sure that when re-combined with the wallet,
|
||||
# we're still valid
|
||||
recombined_wallet = copy.deepcopy(wallet)
|
||||
recombined_wallet.update(wallet_enc)
|
||||
jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT)
|
||||
try:
|
||||
jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT)
|
||||
except ValidationError as ve:
|
||||
if test_legacy:
|
||||
# no data key is allowed if we're testing the absence of a data key
|
||||
jsonschema.validate(recombined_wallet, WALLET_SCHEMA_CURRENT_NODATAKEY)
|
||||
else:
|
||||
raise
|
||||
|
||||
# good to go!
|
||||
# encrypt secrets
|
||||
@@ -139,8 +151,13 @@ def encrypt_wallet(decrypted_wallet, password, test_legacy=False):
|
||||
wallet['enc'] = encrypted_secret_str
|
||||
|
||||
# sanity check
|
||||
if not test_legacy:
|
||||
try:
|
||||
jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
|
||||
except ValidationError as ve:
|
||||
if test_legacy:
|
||||
jsonschema.validate(wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
|
||||
else:
|
||||
raise
|
||||
|
||||
return wallet
|
||||
|
||||
@@ -183,7 +200,16 @@ def make_wallet(password, config_path=CONFIG_PATH, payment_privkey_info=None, ow
|
||||
return encrypted_wallet
|
||||
|
||||
# sanity check
|
||||
jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
|
||||
try:
|
||||
jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT)
|
||||
except ValidationError as ve:
|
||||
if test_legacy:
|
||||
# no data key is permitted
|
||||
assert BLOCKSTACK_TEST
|
||||
jsonschema.validate(encrypted_wallet, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
|
||||
else:
|
||||
raise
|
||||
|
||||
return encrypted_wallet
|
||||
|
||||
else:
|
||||
@@ -216,7 +242,8 @@ def make_legacy_wallet_keys(data, password):
|
||||
# the owner, payment, and data private keys; not all wallets define
|
||||
# these keys separately (and have instead relied on us being able to
|
||||
# generate them from the master private key).
|
||||
child_keys = legacy_hdwallet.get_child_keypairs(count=3, include_privkey=True)
|
||||
# These keys were *not* compressed in the past.
|
||||
child_keys = legacy_hdwallet.get_child_keypairs(count=3, include_privkey=True, compressed=False)
|
||||
|
||||
# note: payment_keypair = child[0]; owner_keypair = child[1]
|
||||
key_defaults = {
|
||||
@@ -261,6 +288,8 @@ def make_legacy_wallet_013_keys(data, password):
|
||||
if virtualchain.is_singlesig(owner_privkey):
|
||||
data_privkey = owner_privkey
|
||||
else:
|
||||
# data private key gets instantiated from the first owner private key,
|
||||
# if we have a multisig key bundle.
|
||||
data_privkey = owner_privkey['private_keys'][0]
|
||||
|
||||
key_defaults = {
|
||||
@@ -272,6 +301,24 @@ def make_legacy_wallet_013_keys(data, password):
|
||||
return key_defaults
|
||||
|
||||
|
||||
def get_data_key_from_owner_key_LEGACY(owner_privkey):
|
||||
"""
|
||||
Given the owner private key, select a data private key to use.
|
||||
|
||||
THIS IS ONLY FOR LEGACY CLIENTS THAT DO NOT HAVE DATA PRIVATE KEYS
|
||||
DEFINED IN THEIR WALLETS.
|
||||
"""
|
||||
data_privkey = None
|
||||
if virtualchain.is_singlesig(owner_privkey):
|
||||
data_privkey = owner_privkey
|
||||
else:
|
||||
# data private key gets instantiated from the first owner private key,
|
||||
# if we have a multisig key bundle.
|
||||
data_privkey = owner_privkey['private_keys'][0]
|
||||
|
||||
return data_privkey
|
||||
|
||||
|
||||
def decrypt_wallet_legacy(data, key_defaults, password):
|
||||
"""
|
||||
Decrypt 0.14.1 and earlier wallets, given the wallet data, the default key values,
|
||||
@@ -314,7 +361,7 @@ def decrypt_wallet_legacy(data, key_defaults, password):
|
||||
default_privkey = key_defaults[keyname]
|
||||
new_wallet[keyname_privkey] = default_privkey
|
||||
new_wallet[keyname_addresses] = [
|
||||
virtualchain.address_reencode( keylib.ecdsa_private_key(default_privkey, compressed=False).public_key().address() )
|
||||
virtualchain.address_reencode( keylib.ECPrivateKey(default_privkey, compressed=False).public_key().address() )
|
||||
]
|
||||
|
||||
return {'status': True, 'wallet': new_wallet}
|
||||
@@ -349,9 +396,22 @@ def decrypt_wallet_current(data, password):
|
||||
try:
|
||||
jsonschema.validate(new_wallet, WALLET_SCHEMA_CURRENT)
|
||||
except ValidationError, ve:
|
||||
if BLOCKSTACK_DEBUG:
|
||||
log.exception(ve)
|
||||
return {'error': 'Wallet secrets do not match wallet schema'}
|
||||
# maybe one without a data key?
|
||||
try:
|
||||
jsonschema.validate(new_wallet, WALLET_SCHEMA_CURRENT_NODATAKEY)
|
||||
except ValidationError, ve:
|
||||
if BLOCKSTACK_DEBUG:
|
||||
log.exception(ve)
|
||||
return {'error': 'Wallet secrets do not match wallet schema'}
|
||||
|
||||
# no data key. Give one and revalidate.
|
||||
# data key defaults to owner private key
|
||||
data_privkey = get_data_key_from_owner_key_LEGACY(new_wallet['owner_privkey'])
|
||||
new_wallet['data_privkey'] = data_privkey
|
||||
new_wallet['data_pubkey'] = get_pubkey_hex(data_privkey)
|
||||
new_wallet['data_pubkeys'] = [new_wallet['data_pubkey']]
|
||||
|
||||
jsonschema.validate(new_wallet, WALLET_SCHEMA_CURRENT)
|
||||
|
||||
return {'status': True, 'wallet': new_wallet}
|
||||
|
||||
@@ -501,6 +561,13 @@ def decrypt_wallet(data, password, config_path=CONFIG_PATH):
|
||||
else:
|
||||
wallet_info = decrypt_wallet_current(data, password)
|
||||
|
||||
# No matter what we do, do not save this wallet if it is current.
|
||||
# First, it's not necessary if the wallet is not legacy.
|
||||
# Second, the data private key is dynamically filled-in for data-key-less wallets,
|
||||
# and we do not want to preserve this (i.e. we want the user to select a data key
|
||||
# and switch over to using it).
|
||||
migrated = False
|
||||
|
||||
if 'error' in wallet_info:
|
||||
log.error("Failed to decrypt wallet; {}".format(wallet_info['error']))
|
||||
return {'error': 'Failed to decrypt wallet'}
|
||||
@@ -555,10 +622,15 @@ def write_wallet(data, path=None, config_path=CONFIG_PATH, test_legacy=False):
|
||||
try:
|
||||
jsonschema.validate(data, ENCRYPTED_WALLET_SCHEMA_CURRENT)
|
||||
except ValidationError as ve:
|
||||
if BLOCKSTACK_DEBUG:
|
||||
log.exception(ve)
|
||||
if test_legacy:
|
||||
# allow no-data-key wallets
|
||||
jsonschema.validate(data, ENCRYPTED_WALLET_SCHEMA_CURRENT_NODATAKEY)
|
||||
|
||||
else:
|
||||
if BLOCKSTACK_DEBUG:
|
||||
log.exception(ve)
|
||||
|
||||
return {'error': 'Invalid wallet data'}
|
||||
return {'error': 'Invalid wallet data'}
|
||||
|
||||
data = json.dumps(data)
|
||||
with open(path, 'w') as f:
|
||||
@@ -1120,7 +1192,7 @@ def wallet_setup(config_path=CONFIG_PATH, interactive=True, wallet_data=None, wa
|
||||
wallet = res['wallet']
|
||||
migrated = res['migrated']
|
||||
|
||||
res = write_wallet(wallet, path=wallet_path)
|
||||
res = write_wallet(wallet, path=wallet_path, test_legacy=test_legacy)
|
||||
if 'error' in res:
|
||||
return res
|
||||
|
||||
|
||||
Reference in New Issue
Block a user