mirror of
https://github.com/alexgo-io/stacks-puppet-node.git
synced 2026-06-06 06:00:08 +08:00
allow data to be stored without signatures or public keys or version tags
This commit is contained in:
@@ -324,12 +324,8 @@ def serialize_mutable_data(data_text_or_json, data_privkey=None, data_pubkey=Non
|
||||
assert data_privkey or (data_pubkey and data_signature)
|
||||
|
||||
if data_signature is None:
|
||||
data_str = None
|
||||
if isinstance(data_text_or_json, (str, unicode)):
|
||||
data_str = str(data_text_or_json)
|
||||
else:
|
||||
data_str = json.dumps(data_text_or_json)
|
||||
|
||||
assert isinstance(data_text_or_json, (str, unicode)), "data must be a string"
|
||||
data_str = str(data_text_or_json)
|
||||
data_signature = sign_data_payload( data_str, data_privkey )
|
||||
|
||||
# make sure it's compressed
|
||||
@@ -343,7 +339,7 @@ def serialize_mutable_data(data_text_or_json, data_privkey=None, data_pubkey=Non
|
||||
return res
|
||||
|
||||
|
||||
def parse_mutable_data_v2(mutable_data_json_txt, public_key_hex, public_key_hash=None, data_hash=None):
|
||||
def parse_mutable_data_v2(mutable_data_json_txt, public_key_hex, public_key_hash=None, data_hash=None, raw=False):
|
||||
"""
|
||||
Version 2 parser
|
||||
Parse a piece of mutable data back into the serialized payload.
|
||||
@@ -353,51 +349,64 @@ def parse_mutable_data_v2(mutable_data_json_txt, public_key_hex, public_key_hash
|
||||
Return None on error
|
||||
"""
|
||||
|
||||
parts = mutable_data_json_txt.split(".", 3)
|
||||
if len(parts) != 4:
|
||||
log.debug("Malformed data: {}".format(mutable_data_json_txt))
|
||||
return None
|
||||
|
||||
if parts[0] != 'bsk2':
|
||||
log.debug("Not v2 data")
|
||||
return None
|
||||
pubk_hex = None
|
||||
sig_b64 = None
|
||||
data_txt = None
|
||||
original_data_txt = None
|
||||
|
||||
pubk_hex = str(parts[1])
|
||||
sig_b64 = str(parts[2])
|
||||
data_txt = str(parts[3])
|
||||
if not raw:
|
||||
# format: bsk2.pubkey.sigb64.data_len:data,
|
||||
parts = mutable_data_json_txt.split(".", 3)
|
||||
if len(parts) != 4:
|
||||
log.debug("Malformed data: {}".format(mutable_data_json_txt))
|
||||
return None
|
||||
|
||||
if parts[0] != 'bsk2':
|
||||
log.debug("Not v2 data")
|
||||
return None
|
||||
|
||||
# basic sanity checks
|
||||
if not re.match('^[0-9a-fA-F]+$', pubk_hex):
|
||||
log.debug("Not a v2 mutable datum: Invalid public key")
|
||||
return None
|
||||
pubk_hex = str(parts[1])
|
||||
sig_b64 = str(parts[2])
|
||||
data_txt = str(parts[3])
|
||||
|
||||
if not re.match(schemas.OP_BASE64_PATTERN_SECTION, sig_b64):
|
||||
log.debug("Not a v2 mutable datum: Invalid signature data")
|
||||
return None
|
||||
# basic sanity checks
|
||||
if not re.match('^[0-9a-fA-F]+$', pubk_hex):
|
||||
log.debug("Not a v2 mutable datum: Invalid public key")
|
||||
return None
|
||||
|
||||
try:
|
||||
sig_bin = base64.b64decode(sig_b64)
|
||||
except:
|
||||
log.error("Incorrect base64-encoding")
|
||||
return None
|
||||
if not re.match(schemas.OP_BASE64_PATTERN_SECTION, sig_b64):
|
||||
log.debug("Not a v2 mutable datum: Invalid signature data")
|
||||
return None
|
||||
|
||||
# data_txt must be a netstring (format: 'len(payload):payload,')
|
||||
serialized_len = len(data_txt)
|
||||
data_txt = parse_data_payload(data_txt)
|
||||
if data_txt is None:
|
||||
log.debug("Invalid data payload of {} bytes".format(serialized_len))
|
||||
return None
|
||||
try:
|
||||
sig_bin = base64.b64decode(sig_b64)
|
||||
except:
|
||||
log.error("Incorrect base64-encoding")
|
||||
return None
|
||||
|
||||
# data_txt must be a netstring (format: 'len(payload):payload,')
|
||||
serialized_len = len(data_txt)
|
||||
original_data_txt = data_txt[:]
|
||||
data_txt = parse_data_payload(data_txt)
|
||||
if data_txt is None:
|
||||
log.debug("Invalid data payload of {} bytes".format(serialized_len))
|
||||
return None
|
||||
|
||||
else:
|
||||
data_txt = mutable_data_json_txt
|
||||
original_data_txt = mutable_data_json_txt
|
||||
|
||||
# shortcut: if hash is given, we're done
|
||||
if data_hash is not None:
|
||||
dh = hash_data_payload( data_txt )
|
||||
dh = hash_data_payload( str(data_txt) )
|
||||
if dh == data_hash:
|
||||
# done!
|
||||
log.debug("Verified with hash {}".format(data_hash))
|
||||
return data_txt
|
||||
|
||||
else:
|
||||
log.debug("Hash mismatch: expected {}, got {}".format(data_hash, dh))
|
||||
log.debug("Hash mismatch: expected {}, got {}\noriginal_data_text ({}): '{}'\nlen(original_data_text): {}\nparsed payload: '{}'\nhash_data_payload: {}".format(
|
||||
data_hash, dh, type(original_data_txt), original_data_txt, len(original_data_txt), parse_data_payload(original_data_txt), hash_data_payload(data_txt)))
|
||||
|
||||
# validate
|
||||
if keylib.key_formatting.get_pubkey_format(pubk_hex) == 'hex_compressed':
|
||||
@@ -448,7 +457,7 @@ def parse_mutable_data_v2(mutable_data_json_txt, public_key_hex, public_key_hash
|
||||
return None
|
||||
|
||||
|
||||
def parse_mutable_data(mutable_data_json_txt, public_key, public_key_hash=None, data_hash=None):
|
||||
def parse_mutable_data(mutable_data_json_txt, public_key, public_key_hash=None, data_hash=None, bsk_version=None):
|
||||
"""
|
||||
Given the serialized JSON for a piece of mutable data,
|
||||
parse it into a JSON document. Verify that it was
|
||||
@@ -461,8 +470,14 @@ def parse_mutable_data(mutable_data_json_txt, public_key, public_key_hash=None,
|
||||
"""
|
||||
|
||||
# newer version?
|
||||
if mutable_data_json_txt.startswith("bsk2."):
|
||||
return parse_mutable_data_v2(mutable_data_json_txt, public_key, public_key_hash=public_key_hash, data_hash=data_hash)
|
||||
if mutable_data_json_txt.startswith("bsk2.") or bsk_version == 2:
|
||||
raw = False
|
||||
if not mutable_data_json_txt.startswith("bsk2."):
|
||||
# raw data; will authenticate with data hash
|
||||
raw = True
|
||||
assert data_hash
|
||||
|
||||
return parse_mutable_data_v2(mutable_data_json_txt, public_key, public_key_hash=public_key_hash, data_hash=data_hash, raw=raw)
|
||||
|
||||
# legacy parser
|
||||
assert public_key is not None or public_key_hash is not None, 'Need a public key or public key hash'
|
||||
@@ -675,7 +690,7 @@ def get_driver_urls( fq_data_id, storage_drivers ):
|
||||
|
||||
|
||||
def get_mutable_data(fq_data_id, data_pubkey, urls=None, data_address=None, data_hash=None,
|
||||
owner_address=None, blockchain_id=None, drivers=None, decode=True):
|
||||
owner_address=None, blockchain_id=None, drivers=None, decode=True, bsk_version=None):
|
||||
"""
|
||||
Low-level call to get mutable data, given a fully-qualified data name.
|
||||
|
||||
@@ -702,7 +717,7 @@ def get_mutable_data(fq_data_id, data_pubkey, urls=None, data_address=None, data
|
||||
h for h in storage_handlers if h.__name__ == d
|
||||
)
|
||||
|
||||
log.debug('get_mutable_data {} fqu={}'.format(fq_data_id, fqu))
|
||||
log.debug('get_mutable_data {} fqu={} bsk_version={}'.format(fq_data_id, fqu, bsk_version))
|
||||
for storage_handler in handlers_to_use:
|
||||
if not getattr(storage_handler, 'get_mutable_handler', None):
|
||||
continue
|
||||
@@ -767,12 +782,12 @@ def get_mutable_data(fq_data_id, data_pubkey, urls=None, data_address=None, data
|
||||
data = None
|
||||
if data_pubkey is not None or data_address is not None or data_hash is not None:
|
||||
data = parse_mutable_data(
|
||||
data_txt, data_pubkey, public_key_hash=data_address, data_hash=data_hash
|
||||
data_txt, data_pubkey, public_key_hash=data_address, data_hash=data_hash, bsk_version=bsk_version
|
||||
)
|
||||
|
||||
if data is None and owner_address is not None:
|
||||
data = parse_mutable_data(
|
||||
data_txt, None, public_key_hash=owner_address
|
||||
data_txt, None, public_key_hash=owner_address, bsk_version=bsk_version
|
||||
)
|
||||
|
||||
if data is None:
|
||||
@@ -868,7 +883,7 @@ def put_immutable_data(data_text, txid, data_hash=None, required=None, skip=None
|
||||
return None if successes == 0 and required_successes == len(set(required) - set(skip)) else data_hash
|
||||
|
||||
|
||||
def put_mutable_data(fq_data_id, data_text_or_json, sign=True, data_privkey=None, data_pubkey=None, data_signature=None, profile=False, blockchain_id=None, required=None, skip=None, required_exclusive=False):
|
||||
def put_mutable_data(fq_data_id, data_text_or_json, sign=True, raw=False, data_privkey=None, data_pubkey=None, data_signature=None, profile=False, blockchain_id=None, required=None, skip=None, required_exclusive=False):
|
||||
"""
|
||||
Given the unserialized data, store it into our mutable data stores.
|
||||
Do so in a best-effort way. This method fails if all storage providers fail,
|
||||
@@ -877,6 +892,8 @@ def put_mutable_data(fq_data_id, data_text_or_json, sign=True, data_privkey=None
|
||||
@required: list of required drivers to use. All of them must succeed for this method to succeed.
|
||||
@skip: list of drivers we can skip. None of them will be tried.
|
||||
@required_exclusive: if True, then only the required drivers will be tried (none of the loaded but not-required drivers will be invoked)
|
||||
@sign: if True, then a private key is required. if False, then simply store the data without serializing it or including a public key and signature.
|
||||
@raw: If True, then the data will be put as-is without any ancilliary metadata. Requires sign=False
|
||||
|
||||
Return True on success
|
||||
Return False on error
|
||||
@@ -885,6 +902,10 @@ def put_mutable_data(fq_data_id, data_text_or_json, sign=True, data_privkey=None
|
||||
global storage_handlers
|
||||
assert len(storage_handlers) > 0, "No storage handlers initialized"
|
||||
|
||||
# sanity check: only take structured data if this is a profile
|
||||
if not isinstance(data_text_or_json, (str, unicode)):
|
||||
assert profile, "Structured data is only supported when profile=True"
|
||||
|
||||
required = [] if required is None else required
|
||||
skip = [] if skip is None else skip
|
||||
|
||||
@@ -910,13 +931,13 @@ def put_mutable_data(fq_data_id, data_text_or_json, sign=True, data_privkey=None
|
||||
assert data_signature is not None
|
||||
|
||||
serialized_data = None
|
||||
if sign:
|
||||
if sign or not raw:
|
||||
serialized_data = serialize_mutable_data(data_text_or_json, data_privkey=data_privkey, data_pubkey=data_pubkey, data_signature=data_signature, profile=profile)
|
||||
else:
|
||||
serialized_data = data_text_or_json
|
||||
|
||||
if BLOCKSTACK_TEST:
|
||||
log.debug("data: {}".format(serialized_data))
|
||||
log.debug("data ({}): {}".format(type(serialized_data), serialized_data))
|
||||
|
||||
successes = 0
|
||||
required_successes = 0
|
||||
|
||||
Reference in New Issue
Block a user