have registrar methods return the names they did (and did not) register; when encrypting owner/private keys, allow the registrar to specify scrypt parameters (taken from the environment)

This commit is contained in:
Jude Nelson
2017-10-25 15:43:48 -04:00
parent 05e37da5cf
commit f2f7d5a7cb

View File

@@ -37,10 +37,10 @@ import time
import tempfile
import hashlib
import keylib
from keylib import ECPrivateKey
import blockstack_zones
import virtualchain
from virtualchain.lib.ecdsalib import ecdsa_private_key
from .queue import get_queue_state, in_queue, cleanup_preorder_queue, queue_removeall
from .queue import queue_find_accepted, queuedb_find
@@ -198,6 +198,7 @@ class RegistrarWorker(threading.Thread):
"""
Given a preordered name, go register it.
Return the result of broadcasting the registration operation on success (idempotent--if already broadcasted, then return the broadcast information).
* {'status': True, 'transaction_hash': ...}
Return {'error': ...} on error
Return {'error': ..., 'already_registered': True} if the name is already registered
Return {'error': ..., 'not_preordered': True} if the name was not preordered
@@ -205,19 +206,21 @@ class RegistrarWorker(threading.Thread):
if proxy is None:
proxy = get_default_proxy(config_path=config_path)
if not is_name_registered( name_data['fqu'], proxy=proxy ):
# ignore grace period, since we can send a register just as a name expires
if not is_name_registered( name_data['fqu'], proxy=proxy, config_path=config_path, include_grace=False ):
if in_queue( "preorder", name_data['fqu'], path=queue_path ):
if not in_queue("register", name_data['fqu'], path=queue_path):
# was preordered but not registered
# send the registration
log.debug("async_register({}, zonefile={}, profile={}, transfer_address={})".format(
name_data['fqu'], name_data.get('zonefile'), name_data.get('profile'),
log.debug("async_register({}, zonefile={}, zonefile_hash={}, profile={}, transfer_address={})".format(
name_data['fqu'], name_data.get('zonefile'), name_data.get('zonefile_hash'), name_data.get('profile'),
name_data.get('transfer_address')))
res = async_register( name_data['fqu'], payment_privkey_info, owner_privkey_info,
name_data=name_data, proxy=proxy, config_path=config_path,
queue_path=queue_path )
return res
else:
# already queued
reg_result = queuedb_find( "register", name_data['fqu'], limit=1, path=queue_path )
@@ -390,8 +393,9 @@ class RegistrarWorker(threading.Thread):
"""
Find all confirmed preorders, and register them.
Return {'status': True} on success
Return {'error': ...} on error
Return {'error': ..., 'names': ..., 'failed': ...} on error
'names' maps to the list of queued name data for names that were registered
'failed' maps to the list of queued name data for names that were not registered
"""
if proxy is None:
@@ -399,6 +403,10 @@ class RegistrarWorker(threading.Thread):
ret = {'status': True}
preorders = cls.get_confirmed_preorders( config_path, queue_path )
failed_names = []
succeeded_names = []
for preorder in preorders:
log.debug("Preorder for '%s' (%s) is confirmed!" % (preorder['fqu'], preorder['tx_hash']))
@@ -419,12 +427,19 @@ class RegistrarWorker(threading.Thread):
else:
log.error("Failed to register preordered name %s: %s" % (preorder['fqu'], res['error']))
queue_add_error_msg('preorder', preorder['fqu'], res['error'], path=queue_path)
ret = {'error': 'Failed to preorder a name'}
ret = {'error': 'Failed to preorder a name'}
failed_names.append(preorder['fqu'])
else:
# clear
log.debug("Sent register for %s" % preorder['fqu'] )
queue_removeall( [preorder], path=queue_path )
succeeded_names.append(preorder['fqu'])
ret['names'] = succeeded_names
if 'error' in ret:
ret['failed'] = failed_names
return ret
@@ -734,7 +749,7 @@ class RegistrarWorker(threading.Thread):
atlas_peers_res = {}
try:
atlas_peers_res = get_atlas_peers( server_hostport, proxy = get_default_proxy() )
atlas_peers_res = get_atlas_peers( server_hostport, proxy = get_default_proxy(config_path) )
assert 'error' not in atlas_peers_res
servers += atlas_peers_res['peers']
@@ -1169,7 +1184,7 @@ def set_wallet(payment_keypair, owner_keypair, data_keypair, config_path=None, p
state.payment_address = payment_keypair[0]
state.owner_address = owner_keypair[0]
state.data_pubkey = ECPrivateKey(data_keypair[1]).public_key().to_hex()
state.data_pubkey = ecdsa_private_key(data_keypair[1]).public_key().to_hex()
if keylib.key_formatting.get_pubkey_format(state.data_pubkey) == 'hex_compressed':
state.data_pubkey = keylib.key_formatting.decompress(state.data_pubkey)
@@ -1309,10 +1324,21 @@ def preorder(fqu, cost_satoshis, zonefile_data, profile, transfer_address, min_p
# save the current privkey_info, scrypted with our password
passwd = get_secret('BLOCKSTACK_CLIENT_WALLET_PASSWORD')
if passwd:
name_data['owner_privkey'] = aes_encrypt(
str(owner_key), hexlify( passwd ))
name_data['payment_privkey'] = aes_encrypt(
str(payment_key), hexlify( passwd ))
# if this module is being used by a library, it may want to set its own scrypt params since the performance/security
# trade-off may be worth it. These would be set as a JSON dict in BLOCKSTACK_CLIENT_SCRYPT_PARAMS
scrypt_params = {}
if os.environ.get('BLOCKSTACK_CLIENT_CRYPTO_PARAMS') is not None:
scrypt_params = os.environ['BLOCKSTACK_CLIENT_CRYPTO_PARAMS']
log.warning("Using custom crypt parameters: {}".format(scrypt_params))
scrypt_params = json.loads(scrypt_params)
# sanity check: must be numerics!
for (k, v) in scrypt_params.items():
assert isinstance(v, (int,long,float)), 'Only numeric kwargs are allwed'
name_data['owner_privkey'] = aes_encrypt(str(owner_key), hexlify(passwd), **scrypt_params)
name_data['payment_privkey'] = aes_encrypt(str(payment_key), hexlify(passwd), **scrypt_params)
else:
log.warn("Registrar couldn't access wallet password to encrypt privkey," +
" sheepishly refusing to store the private key unencrypted.")