move lbryschema/lbryschema into lbrynet/schema
This commit is contained in:
parent
d12b6cddb3
commit
2dcebe48b7
42 changed files with 3892 additions and 0 deletions
lbrynet/schema
__init__.pyaddress.pybase.pyclaim.pydecode.pyencoding.pyerror.pyfee.pyhashing.py
legacy
proto
__init__.pycertificate.protocertificate_pb2.pyclaim.protoclaim_pb2.pyfee.protofee_pb2.pymetadata.protometadata_pb2.pysignature.protosignature_pb2.pysource.protosource_pb2.pystream.protostream_pb2.py
schema
signature
signer.pyuri.pyvalidator.py
13
lbrynet/schema/__init__.py
Normal file
13
lbrynet/schema/__init__.py
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import os
|
||||||
|
|
||||||
|
__version__ = "0.0.16"
|
||||||
|
|
||||||
|
BLOCKCHAIN_NAME_ENVVAR = "LBRYSCHEMA_BLOCKCHAIN_NAME"
|
||||||
|
if BLOCKCHAIN_NAME_ENVVAR in os.environ:
|
||||||
|
if os.environ[BLOCKCHAIN_NAME_ENVVAR] in ['lbrycrd_main', 'lbrycrd_regtest',
|
||||||
|
'lbrycrd_testnet']:
|
||||||
|
BLOCKCHAIN_NAME = os.environ[BLOCKCHAIN_NAME_ENVVAR]
|
||||||
|
else:
|
||||||
|
raise OSError("invalid blockchain name: %s" % os.environ[BLOCKCHAIN_NAME_ENVVAR])
|
||||||
|
else:
|
||||||
|
BLOCKCHAIN_NAME = "lbrycrd_main"
|
68
lbrynet/schema/address.py
Normal file
68
lbrynet/schema/address.py
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
import six
|
||||||
|
import lbryschema
|
||||||
|
from lbryschema.base import b58encode, b58decode, validate_b58_checksum
|
||||||
|
from lbryschema.hashing import double_sha256, hash160
|
||||||
|
from lbryschema.error import InvalidAddress
|
||||||
|
from lbryschema.schema import ADDRESS_LENGTH, ADDRESS_PREFIXES, PUBKEY_ADDRESS, SCRIPT_ADDRESS
|
||||||
|
|
||||||
|
|
||||||
|
def validate_address_length(addr_bytes):
|
||||||
|
if len(addr_bytes) != ADDRESS_LENGTH:
|
||||||
|
raise InvalidAddress("Invalid address length: %i" % len(addr_bytes))
|
||||||
|
|
||||||
|
|
||||||
|
def validate_address_prefix(addr_bytes):
|
||||||
|
if six.PY3:
|
||||||
|
prefix = addr_bytes[0]
|
||||||
|
else:
|
||||||
|
prefix = ord(addr_bytes[0])
|
||||||
|
if prefix not in ADDRESS_PREFIXES[lbryschema.BLOCKCHAIN_NAME].values():
|
||||||
|
raise InvalidAddress("Invalid address prefix: %.2X" % prefix)
|
||||||
|
|
||||||
|
|
||||||
|
def validate_lbrycrd_address_bytes(addr_bytes):
|
||||||
|
validate_address_length(addr_bytes)
|
||||||
|
validate_address_prefix(addr_bytes)
|
||||||
|
validate_b58_checksum(addr_bytes)
|
||||||
|
return addr_bytes
|
||||||
|
|
||||||
|
|
||||||
|
def decode_address(v):
|
||||||
|
"""decode and validate a b58 address"""
|
||||||
|
return validate_lbrycrd_address_bytes(b58decode(v))
|
||||||
|
|
||||||
|
|
||||||
|
def encode_address(addr_bytes):
|
||||||
|
"""validate and encode an address as b58"""
|
||||||
|
v = validate_lbrycrd_address_bytes(addr_bytes)
|
||||||
|
return b58encode(v)
|
||||||
|
|
||||||
|
|
||||||
|
def hash_160_bytes_to_address(h160, addrtype=PUBKEY_ADDRESS):
|
||||||
|
if addrtype == PUBKEY_ADDRESS:
|
||||||
|
prefix = chr(ADDRESS_PREFIXES[lbryschema.BLOCKCHAIN_NAME][PUBKEY_ADDRESS])
|
||||||
|
elif addrtype == SCRIPT_ADDRESS:
|
||||||
|
prefix = chr(ADDRESS_PREFIXES[lbryschema.BLOCKCHAIN_NAME][SCRIPT_ADDRESS])
|
||||||
|
else:
|
||||||
|
raise Exception("Invalid address prefix")
|
||||||
|
return b58encode(prefix + h160 + double_sha256(prefix + h160)[0:4])
|
||||||
|
|
||||||
|
|
||||||
|
def public_key_to_address(public_key):
|
||||||
|
return hash_160_bytes_to_address(hash160(public_key))
|
||||||
|
|
||||||
|
|
||||||
|
def address_to_hash_160(addr):
|
||||||
|
bytes = decode_address(addr)
|
||||||
|
prefix, pubkey_bytes, addr_checksum = bytes[0], bytes[1:21], bytes[21:]
|
||||||
|
if prefix == chr(ADDRESS_PREFIXES[lbryschema.BLOCKCHAIN_NAME][PUBKEY_ADDRESS]):
|
||||||
|
return PUBKEY_ADDRESS, pubkey_bytes
|
||||||
|
return SCRIPT_ADDRESS, pubkey_bytes
|
||||||
|
|
||||||
|
|
||||||
|
def is_address(addr):
|
||||||
|
try:
|
||||||
|
addr_bytes = decode_address(addr)
|
||||||
|
return True
|
||||||
|
except InvalidAddress:
|
||||||
|
return False
|
105
lbrynet/schema/base.py
Normal file
105
lbrynet/schema/base.py
Normal file
|
@ -0,0 +1,105 @@
|
||||||
|
import six
|
||||||
|
from lbryschema.schema import ADDRESS_CHECKSUM_LENGTH
|
||||||
|
from lbryschema.hashing import double_sha256
|
||||||
|
from lbryschema.error import InvalidAddress
|
||||||
|
|
||||||
|
|
||||||
|
alphabet = b'123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||||
|
|
||||||
|
|
||||||
|
if six.PY2:
|
||||||
|
iseq, bseq, buffer = (
|
||||||
|
lambda s: map(ord, s),
|
||||||
|
lambda s: ''.join(map(chr, s)),
|
||||||
|
lambda s: s,
|
||||||
|
)
|
||||||
|
elif six.PY3:
|
||||||
|
iseq, bseq, buffer = (
|
||||||
|
lambda s: s,
|
||||||
|
bytes,
|
||||||
|
lambda s: s.buffer,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def scrub_input(v):
|
||||||
|
if isinstance(v, str) and not isinstance(v, bytes):
|
||||||
|
v = v.encode('ascii')
|
||||||
|
return v
|
||||||
|
|
||||||
|
|
||||||
|
def b58encode_int(i, default_one=True):
|
||||||
|
'''Encode an integer using Base58'''
|
||||||
|
if not i and default_one:
|
||||||
|
return alphabet[0:1]
|
||||||
|
string = b""
|
||||||
|
while i:
|
||||||
|
i, idx = divmod(i, 58)
|
||||||
|
string = alphabet[idx:idx+1] + string
|
||||||
|
return string
|
||||||
|
|
||||||
|
|
||||||
|
def b58encode(v):
|
||||||
|
'''Encode a string using Base58'''
|
||||||
|
|
||||||
|
v = scrub_input(v)
|
||||||
|
|
||||||
|
nPad = len(v)
|
||||||
|
v = v.lstrip(b'\0')
|
||||||
|
nPad -= len(v)
|
||||||
|
|
||||||
|
p, acc = 1, 0
|
||||||
|
for c in iseq(reversed(v)):
|
||||||
|
acc += p * c
|
||||||
|
p = p << 8
|
||||||
|
|
||||||
|
result = b58encode_int(acc, default_one=False)
|
||||||
|
|
||||||
|
return alphabet[0:1] * nPad + result
|
||||||
|
|
||||||
|
|
||||||
|
def b58decode_int(v):
|
||||||
|
'''Decode a Base58 encoded string as an integer'''
|
||||||
|
|
||||||
|
v = scrub_input(v)
|
||||||
|
|
||||||
|
decimal = 0
|
||||||
|
for char in v:
|
||||||
|
decimal = decimal * 58 + alphabet.index(char)
|
||||||
|
return decimal
|
||||||
|
|
||||||
|
|
||||||
|
def b58decode(v):
|
||||||
|
'''Decode a Base58 encoded string'''
|
||||||
|
|
||||||
|
v = scrub_input(v)
|
||||||
|
|
||||||
|
origlen = len(v)
|
||||||
|
v = v.lstrip(alphabet[0:1])
|
||||||
|
newlen = len(v)
|
||||||
|
|
||||||
|
acc = b58decode_int(v)
|
||||||
|
|
||||||
|
result = []
|
||||||
|
while acc > 0:
|
||||||
|
acc, mod = divmod(acc, 256)
|
||||||
|
result.append(mod)
|
||||||
|
|
||||||
|
return (b'\0' * (origlen - newlen) + bseq(reversed(result)))
|
||||||
|
|
||||||
|
|
||||||
|
def validate_b58_checksum(addr_bytes):
|
||||||
|
addr_without_checksum = addr_bytes[:-ADDRESS_CHECKSUM_LENGTH]
|
||||||
|
addr_checksum = addr_bytes[-ADDRESS_CHECKSUM_LENGTH:]
|
||||||
|
if double_sha256(addr_without_checksum)[:ADDRESS_CHECKSUM_LENGTH] != addr_checksum:
|
||||||
|
raise InvalidAddress("Invalid address checksum")
|
||||||
|
|
||||||
|
|
||||||
|
def b58decode_strip_checksum(v):
|
||||||
|
addr_bytes = b58decode(v)
|
||||||
|
validate_b58_checksum(addr_bytes)
|
||||||
|
return addr_bytes[:-ADDRESS_CHECKSUM_LENGTH]
|
||||||
|
|
||||||
|
|
||||||
|
def b58encode_with_checksum(addr_bytes):
|
||||||
|
addr_checksum = double_sha256(addr_bytes)[:ADDRESS_CHECKSUM_LENGTH]
|
||||||
|
return b58encode(addr_bytes + addr_checksum)
|
193
lbrynet/schema/claim.py
Normal file
193
lbrynet/schema/claim.py
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
import json
|
||||||
|
import binascii
|
||||||
|
from google.protobuf import json_format # pylint: disable=no-name-in-module
|
||||||
|
from google.protobuf.message import DecodeError as DecodeError_pb # pylint: disable=no-name-in-module,import-error
|
||||||
|
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from lbryschema.schema.claim import Claim
|
||||||
|
from lbryschema.proto import claim_pb2
|
||||||
|
from lbryschema.validator import get_validator
|
||||||
|
from lbryschema.signer import get_signer
|
||||||
|
from lbryschema.schema import NIST256p, CURVE_NAMES, CLAIM_TYPE_NAMES
|
||||||
|
from lbryschema.encoding import decode_fields, decode_b64_fields, encode_fields
|
||||||
|
from lbryschema.error import DecodeError
|
||||||
|
from lbryschema.fee import Fee
|
||||||
|
|
||||||
|
|
||||||
|
class ClaimDict(OrderedDict):
|
||||||
|
def __init__(self, claim_dict=None):
|
||||||
|
if isinstance(claim_dict, claim_pb2.Claim):
|
||||||
|
raise Exception("To initialize %s with a Claim protobuf use %s.load_protobuf" %
|
||||||
|
(self.__class__.__name__, self.__class__.__name__))
|
||||||
|
OrderedDict.__init__(self, claim_dict or [])
|
||||||
|
|
||||||
|
@property
|
||||||
|
def protobuf_dict(self):
|
||||||
|
"""Claim dictionary using base64 to represent bytes"""
|
||||||
|
|
||||||
|
return json.loads(json_format.MessageToJson(self.protobuf, True))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def protobuf(self):
|
||||||
|
"""Claim message object"""
|
||||||
|
|
||||||
|
return Claim.load(self)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serialized(self):
|
||||||
|
"""Serialized Claim protobuf"""
|
||||||
|
|
||||||
|
return self.protobuf.SerializeToString()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serialized_no_signature(self):
|
||||||
|
"""Serialized Claim protobuf without publisherSignature field"""
|
||||||
|
claim = self.protobuf
|
||||||
|
claim.ClearField("publisherSignature")
|
||||||
|
return ClaimDict.load_protobuf(claim).serialized
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_signature(self):
|
||||||
|
claim = self.protobuf
|
||||||
|
if claim.HasField("publisherSignature"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_certificate(self):
|
||||||
|
claim = self.protobuf
|
||||||
|
return CLAIM_TYPE_NAMES[claim.claimType] == "certificate"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_stream(self):
|
||||||
|
claim = self.protobuf
|
||||||
|
return CLAIM_TYPE_NAMES[claim.claimType] == "stream"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_hash(self):
|
||||||
|
claim = self.protobuf
|
||||||
|
if not CLAIM_TYPE_NAMES[claim.claimType] == "stream":
|
||||||
|
return None
|
||||||
|
return binascii.hexlify(claim.stream.source.source)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def has_fee(self):
|
||||||
|
claim = self.protobuf
|
||||||
|
if not CLAIM_TYPE_NAMES[claim.claimType] == "stream":
|
||||||
|
return None
|
||||||
|
if claim.stream.metadata.HasField("fee"):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source_fee(self):
|
||||||
|
claim = self.protobuf
|
||||||
|
if not CLAIM_TYPE_NAMES[claim.claimType] == "stream":
|
||||||
|
return None
|
||||||
|
if claim.stream.metadata.HasField("fee"):
|
||||||
|
return Fee.load_protobuf(claim.stream.metadata.fee)
|
||||||
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def certificate_id(self):
|
||||||
|
if not self.has_signature:
|
||||||
|
return None
|
||||||
|
return binascii.hexlify(self.protobuf.publisherSignature.certificateId)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def signature(self):
|
||||||
|
if not self.has_signature:
|
||||||
|
return None
|
||||||
|
return binascii.hexlify(self.protobuf.publisherSignature.signature)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def protobuf_len(self):
|
||||||
|
"""Length of serialized string"""
|
||||||
|
|
||||||
|
return self.protobuf.ByteSize()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def json_len(self):
|
||||||
|
"""Length of json encoded string"""
|
||||||
|
|
||||||
|
return len(json.dumps(self.claim_dict))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def claim_dict(self):
|
||||||
|
"""Claim dictionary with bytes represented as hex and base58"""
|
||||||
|
|
||||||
|
return dict(encode_fields(self))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_protobuf_dict(cls, protobuf_dict):
|
||||||
|
"""
|
||||||
|
Load a ClaimDict from a dictionary with base64 encoded bytes
|
||||||
|
(as returned by the protobuf json formatter)
|
||||||
|
"""
|
||||||
|
|
||||||
|
return cls(decode_b64_fields(protobuf_dict))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_protobuf(cls, protobuf_claim):
|
||||||
|
"""Load ClaimDict from a protobuf Claim message"""
|
||||||
|
return cls.load_protobuf_dict(json.loads(json_format.MessageToJson(protobuf_claim, True)))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_dict(cls, claim_dict):
|
||||||
|
"""Load ClaimDict from a dictionary with hex and base58 encoded bytes"""
|
||||||
|
try:
|
||||||
|
return cls.load_protobuf(cls(decode_fields(claim_dict)).protobuf)
|
||||||
|
except json_format.ParseError as err:
|
||||||
|
raise DecodeError(str(err))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def deserialize(cls, serialized):
|
||||||
|
"""Load a ClaimDict from a serialized protobuf string"""
|
||||||
|
|
||||||
|
temp_claim = claim_pb2.Claim()
|
||||||
|
try:
|
||||||
|
temp_claim.ParseFromString(serialized)
|
||||||
|
except DecodeError_pb:
|
||||||
|
raise DecodeError(DecodeError_pb)
|
||||||
|
return cls.load_protobuf(temp_claim)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate_certificate(cls, private_key, curve=NIST256p):
|
||||||
|
signer = get_signer(curve).load_pem(private_key)
|
||||||
|
return cls.load_protobuf(signer.certificate)
|
||||||
|
|
||||||
|
def sign(self, private_key, claim_address, cert_claim_id, curve=NIST256p):
|
||||||
|
signer = get_signer(curve).load_pem(private_key)
|
||||||
|
signed = signer.sign_stream_claim(self, claim_address, cert_claim_id)
|
||||||
|
return ClaimDict.load_protobuf(signed)
|
||||||
|
|
||||||
|
def validate_signature(self, claim_address, certificate):
|
||||||
|
if isinstance(certificate, ClaimDict):
|
||||||
|
certificate = certificate.protobuf
|
||||||
|
curve = CURVE_NAMES[certificate.certificate.keyType]
|
||||||
|
validator = get_validator(curve).load_from_certificate(certificate, self.certificate_id)
|
||||||
|
return validator.validate_claim_signature(self, claim_address)
|
||||||
|
|
||||||
|
def validate_private_key(self, private_key, certificate_id):
|
||||||
|
certificate = self.protobuf
|
||||||
|
if CLAIM_TYPE_NAMES[certificate.claimType] != "certificate":
|
||||||
|
return
|
||||||
|
curve = CURVE_NAMES[certificate.certificate.keyType]
|
||||||
|
validator = get_validator(curve).load_from_certificate(certificate, certificate_id)
|
||||||
|
signing_key = validator.signing_key_from_pem(private_key)
|
||||||
|
return validator.validate_private_key(signing_key)
|
||||||
|
|
||||||
|
def get_validator(self, certificate_id):
|
||||||
|
"""
|
||||||
|
Get a lbryschema.validator.Validator object for a certificate claim
|
||||||
|
|
||||||
|
:param certificate_id: claim id of this certificate claim
|
||||||
|
:return: None or lbryschema.validator.Validator object
|
||||||
|
"""
|
||||||
|
|
||||||
|
claim = self.protobuf
|
||||||
|
if CLAIM_TYPE_NAMES[claim.claimType] != "certificate":
|
||||||
|
return
|
||||||
|
curve = CURVE_NAMES[claim.certificate.keyType]
|
||||||
|
return get_validator(curve).load_from_certificate(claim, certificate_id)
|
63
lbrynet/schema/decode.py
Normal file
63
lbrynet/schema/decode.py
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
import json
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
from lbryschema.error import DecodeError, InvalidAddress
|
||||||
|
from lbryschema.legacy.migrate import migrate as schema_migrator
|
||||||
|
from lbryschema.claim import ClaimDict
|
||||||
|
|
||||||
|
from google.protobuf import json_format # pylint: disable=no-name-in-module
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_json_claim_value(decoded_json):
|
||||||
|
try:
|
||||||
|
if 'fee' in decoded_json:
|
||||||
|
old_fee = decoded_json['fee']
|
||||||
|
if not old_fee[list(old_fee.keys())[0]]['amount']:
|
||||||
|
del decoded_json['fee']
|
||||||
|
return migrate_json_claim_value(decoded_json)
|
||||||
|
except (TypeError, AttributeError, InvalidAddress):
|
||||||
|
raise DecodeError("Failed to decode claim")
|
||||||
|
try:
|
||||||
|
pb_migrated = schema_migrator(decoded_json)
|
||||||
|
return pb_migrated
|
||||||
|
except json_format.ParseError as parse_error:
|
||||||
|
raise DecodeError("Failed to parse protobuf: %s" % parse_error)
|
||||||
|
except Exception as err:
|
||||||
|
raise DecodeError("Failed to migrate claim: %s" % err)
|
||||||
|
|
||||||
|
|
||||||
|
def smart_decode(claim_value):
|
||||||
|
"""
|
||||||
|
Decode a claim value
|
||||||
|
|
||||||
|
Try decoding claim protobuf, if this fails try decoding json and migrating it.
|
||||||
|
If unable to decode or migrate, raise DecodeError
|
||||||
|
"""
|
||||||
|
|
||||||
|
# if already decoded, return
|
||||||
|
if isinstance(claim_value, ClaimDict):
|
||||||
|
return claim_value
|
||||||
|
elif isinstance(claim_value, dict):
|
||||||
|
return ClaimDict.load_dict(claim_value)
|
||||||
|
|
||||||
|
try:
|
||||||
|
claim_value = binascii.unhexlify(claim_value)
|
||||||
|
except (TypeError, ValueError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if claim_value[0] in ['{', ord('{')]:
|
||||||
|
try:
|
||||||
|
if six.PY3 and isinstance(claim_value, six.binary_type):
|
||||||
|
claim_value = claim_value.decode()
|
||||||
|
decoded_json = json.loads(claim_value)
|
||||||
|
return migrate_json_claim_value(decoded_json)
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
if six.PY3 and isinstance(claim_value, six.text_type):
|
||||||
|
claim_value = claim_value.encode()
|
||||||
|
return ClaimDict.deserialize(claim_value)
|
||||||
|
except (DecodeError, InvalidAddress, KeyError, TypeError):
|
||||||
|
raise DecodeError(claim_value)
|
78
lbrynet/schema/encoding.py
Normal file
78
lbrynet/schema/encoding.py
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
import base64, binascii
|
||||||
|
from copy import deepcopy
|
||||||
|
from lbryschema.address import decode_address, encode_address
|
||||||
|
from lbryschema.schema import CLAIM_TYPES, CLAIM_TYPE, STREAM_TYPE, CERTIFICATE_TYPE
|
||||||
|
from lbryschema.schema import SIGNATURE
|
||||||
|
from lbryschema.error import DecodeError, InvalidAddress
|
||||||
|
|
||||||
|
|
||||||
|
def encode_fields(claim_dictionary):
|
||||||
|
"""Encode bytes to hex and b58 for return by ClaimDict"""
|
||||||
|
claim_dictionary = deepcopy(claim_dictionary)
|
||||||
|
claim_type = CLAIM_TYPES[claim_dictionary[CLAIM_TYPE]]
|
||||||
|
claim_value = claim_dictionary[claim_type]
|
||||||
|
if claim_type == CLAIM_TYPES[STREAM_TYPE]:
|
||||||
|
claim_value['source']['source'] = binascii.hexlify(claim_value['source']['source']).decode()
|
||||||
|
if 'fee' in claim_value['metadata']:
|
||||||
|
try:
|
||||||
|
address = encode_address(claim_value['metadata']['fee']['address'])
|
||||||
|
except InvalidAddress as err:
|
||||||
|
raise DecodeError("Invalid fee address: %s" % err)
|
||||||
|
claim_value['metadata']['fee']['address'] = address
|
||||||
|
elif claim_type == CLAIM_TYPES[CERTIFICATE_TYPE]:
|
||||||
|
public_key = claim_value["publicKey"]
|
||||||
|
claim_value["publicKey"] = binascii.hexlify(public_key).decode()
|
||||||
|
if SIGNATURE in claim_dictionary:
|
||||||
|
encoded_sig = binascii.hexlify(claim_dictionary[SIGNATURE]['signature']).decode()
|
||||||
|
encoded_cert_id = binascii.hexlify(claim_dictionary[SIGNATURE]['certificateId']).decode()
|
||||||
|
claim_dictionary[SIGNATURE]['signature'] = encoded_sig
|
||||||
|
claim_dictionary[SIGNATURE]['certificateId'] = encoded_cert_id
|
||||||
|
claim_dictionary[claim_type] = claim_value
|
||||||
|
return claim_dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def decode_fields(claim_dictionary):
|
||||||
|
"""Decode hex and b58 encoded bytes in dictionaries given to ClaimDict"""
|
||||||
|
claim_dictionary = deepcopy(claim_dictionary)
|
||||||
|
claim_type = CLAIM_TYPES[claim_dictionary[CLAIM_TYPE]]
|
||||||
|
claim_value = claim_dictionary[claim_type]
|
||||||
|
if claim_type == CLAIM_TYPES[STREAM_TYPE]:
|
||||||
|
claim_value['source']['source'] = binascii.unhexlify(claim_value['source']['source'])
|
||||||
|
if 'fee' in claim_value['metadata']:
|
||||||
|
try:
|
||||||
|
address = decode_address(claim_value['metadata']['fee']['address'])
|
||||||
|
except InvalidAddress as err:
|
||||||
|
raise DecodeError("Invalid fee address: %s" % err)
|
||||||
|
claim_value['metadata']['fee']['address'] = address
|
||||||
|
elif claim_type == CLAIM_TYPES[CERTIFICATE_TYPE]:
|
||||||
|
public_key = binascii.unhexlify(claim_value["publicKey"])
|
||||||
|
claim_value["publicKey"] = public_key
|
||||||
|
if SIGNATURE in claim_dictionary:
|
||||||
|
decoded_sig = binascii.unhexlify(claim_dictionary[SIGNATURE]['signature'])
|
||||||
|
decoded_cert_id = binascii.unhexlify(claim_dictionary[SIGNATURE]['certificateId'])
|
||||||
|
claim_dictionary[SIGNATURE]['signature'] = decoded_sig
|
||||||
|
claim_dictionary[SIGNATURE]['certificateId'] = decoded_cert_id
|
||||||
|
claim_dictionary[claim_type] = claim_value
|
||||||
|
return claim_dictionary
|
||||||
|
|
||||||
|
|
||||||
|
def decode_b64_fields(claim_dictionary):
|
||||||
|
"""Decode b64 encoded bytes in protobuf generated dictionary to be given to ClaimDict"""
|
||||||
|
claim_dictionary = deepcopy(claim_dictionary)
|
||||||
|
claim_type = CLAIM_TYPES[claim_dictionary[CLAIM_TYPE]]
|
||||||
|
claim_value = claim_dictionary[claim_type]
|
||||||
|
if claim_type == CLAIM_TYPES[STREAM_TYPE]:
|
||||||
|
claim_value['source']['source'] = base64.b64decode(claim_value['source']['source'])
|
||||||
|
if 'fee' in claim_value['metadata']:
|
||||||
|
address = base64.b64decode(claim_value['metadata']['fee']['address'])
|
||||||
|
claim_value['metadata']['fee']['address'] = address
|
||||||
|
elif claim_type == CLAIM_TYPES[CERTIFICATE_TYPE]:
|
||||||
|
public_key = base64.b64decode(claim_value["publicKey"])
|
||||||
|
claim_value["publicKey"] = public_key
|
||||||
|
if SIGNATURE in claim_dictionary:
|
||||||
|
encoded_sig = base64.b64decode(claim_dictionary[SIGNATURE]['signature'])
|
||||||
|
encoded_cert_id = base64.b64decode(claim_dictionary[SIGNATURE]['certificateId'])
|
||||||
|
claim_dictionary[SIGNATURE]['signature'] = encoded_sig
|
||||||
|
claim_dictionary[SIGNATURE]['certificateId'] = encoded_cert_id
|
||||||
|
claim_dictionary[claim_type] = claim_value
|
||||||
|
return claim_dictionary
|
22
lbrynet/schema/error.py
Normal file
22
lbrynet/schema/error.py
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
class UnknownSourceType(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidSourceHashLength(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class DecodeError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class URIParseError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class CertificateError(Exception):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
class InvalidAddress(Exception):
|
||||||
|
pass
|
79
lbrynet/schema/fee.py
Normal file
79
lbrynet/schema/fee.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
from collections import OrderedDict
|
||||||
|
|
||||||
|
from lbryschema.address import encode_address, decode_address
|
||||||
|
from lbryschema.schema import CURRENCY_NAMES, CURRENCY_MAP
|
||||||
|
from lbryschema.schema.fee import Fee as FeeHelper
|
||||||
|
from lbryschema.proto import fee_pb2
|
||||||
|
|
||||||
|
|
||||||
|
def migrate(fee):
|
||||||
|
if len(list(fee.keys())) == 3 and 'currency' in fee and 'amount' in fee and 'address' in fee:
|
||||||
|
return FeeHelper.load({
|
||||||
|
"version": "_0_0_1",
|
||||||
|
"currency": fee['currency'],
|
||||||
|
"amount": fee['amount'],
|
||||||
|
"address": decode_address(fee['address'])
|
||||||
|
})
|
||||||
|
if len(list(fee.keys())) > 1:
|
||||||
|
raise Exception("Invalid fee")
|
||||||
|
|
||||||
|
currency = list(fee.keys())[0]
|
||||||
|
amount = fee[currency]['amount']
|
||||||
|
address = fee[currency]['address']
|
||||||
|
|
||||||
|
return FeeHelper.load({
|
||||||
|
"version": "_0_0_1",
|
||||||
|
"currency": currency,
|
||||||
|
"amount": amount,
|
||||||
|
"address": decode_address(address)
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
class Fee(OrderedDict):
|
||||||
|
def __init__(self, fee):
|
||||||
|
if (len(fee) == 4 and "version" in fee and "currency" in fee
|
||||||
|
and "amount" in fee and "address" in fee):
|
||||||
|
OrderedDict.__init__(self, fee)
|
||||||
|
else:
|
||||||
|
OrderedDict.__init__(self, Fee.load_protobuf(migrate(fee)))
|
||||||
|
|
||||||
|
@property
|
||||||
|
def currency(self):
|
||||||
|
return self['currency']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def address(self):
|
||||||
|
return self['address']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def amount(self):
|
||||||
|
return self['amount']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def version(self):
|
||||||
|
return self['version']
|
||||||
|
|
||||||
|
@property
|
||||||
|
def protobuf(self):
|
||||||
|
pb = {
|
||||||
|
"version": self.version,
|
||||||
|
"currency": CURRENCY_MAP[self.currency],
|
||||||
|
"address": decode_address(self.address),
|
||||||
|
"amount": self.amount
|
||||||
|
}
|
||||||
|
return FeeHelper.load(pb)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_protobuf(cls, pb):
|
||||||
|
return cls({
|
||||||
|
"version": pb.version,
|
||||||
|
"currency": CURRENCY_NAMES[pb.currency],
|
||||||
|
"address": encode_address(pb.address),
|
||||||
|
"amount": pb.amount
|
||||||
|
})
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def deserialize(cls, serialized):
|
||||||
|
pb = fee_pb2.Fee()
|
||||||
|
pb.ParseFromString(serialized)
|
||||||
|
return cls.load_protobuf(pb)
|
24
lbrynet/schema/hashing.py
Normal file
24
lbrynet/schema/hashing.py
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
import six
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
|
||||||
|
def sha256(x):
|
||||||
|
if isinstance(x, six.text_type):
|
||||||
|
x = x.encode('utf-8')
|
||||||
|
return hashlib.sha256(x).digest()
|
||||||
|
|
||||||
|
|
||||||
|
def double_sha256(x):
|
||||||
|
return sha256(sha256(x))
|
||||||
|
|
||||||
|
|
||||||
|
def ripemd160(x):
|
||||||
|
if isinstance(x, six.text_type):
|
||||||
|
x = x.encode('utf-8')
|
||||||
|
md = hashlib.new('ripemd160')
|
||||||
|
md.update(x)
|
||||||
|
return md.digest()
|
||||||
|
|
||||||
|
|
||||||
|
def hash160(x):
|
||||||
|
return ripemd160(sha256(x))
|
59
lbrynet/schema/legacy/StructuredDict.py
Normal file
59
lbrynet/schema/legacy/StructuredDict.py
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
import jsonschema
|
||||||
|
|
||||||
|
|
||||||
|
class StructuredDict(dict):
|
||||||
|
"""
|
||||||
|
A dictionary that enforces a structure specified by a schema, and supports
|
||||||
|
migration between different versions of the schema.
|
||||||
|
"""
|
||||||
|
|
||||||
|
# To be specified in sub-classes, an array in the format
|
||||||
|
# [(version, schema, migration), ...]
|
||||||
|
_versions = []
|
||||||
|
|
||||||
|
# Used internally to allow schema lookups by version number
|
||||||
|
_schemas = {}
|
||||||
|
|
||||||
|
version = None
|
||||||
|
|
||||||
|
def __init__(self, value, starting_version, migrate=True, target_version=None):
|
||||||
|
dict.__init__(self, value)
|
||||||
|
|
||||||
|
self.version = starting_version
|
||||||
|
self._schemas = dict([(version, schema) for (version, schema, _) in self._versions])
|
||||||
|
|
||||||
|
self.validate(starting_version)
|
||||||
|
|
||||||
|
if migrate:
|
||||||
|
self.migrate(target_version)
|
||||||
|
|
||||||
|
def _upgrade_version_range(self, start_version, end_version):
|
||||||
|
after_starting_version = False
|
||||||
|
for version, schema, migration in self._versions:
|
||||||
|
if not after_starting_version:
|
||||||
|
if version == self.version:
|
||||||
|
after_starting_version = True
|
||||||
|
continue
|
||||||
|
|
||||||
|
yield version, schema, migration
|
||||||
|
|
||||||
|
if end_version and version == end_version:
|
||||||
|
break
|
||||||
|
|
||||||
|
def validate(self, version):
|
||||||
|
jsonschema.validate(self, self._schemas[version])
|
||||||
|
|
||||||
|
def migrate(self, target_version=None):
|
||||||
|
if target_version:
|
||||||
|
assert self._versions.index(target_version) > self._versions.index(self.version), \
|
||||||
|
"Current version is above target version"
|
||||||
|
|
||||||
|
for version, schema, migration in self._upgrade_version_range(self.version, target_version):
|
||||||
|
migration(self)
|
||||||
|
try:
|
||||||
|
self.validate(version)
|
||||||
|
except jsonschema.ValidationError as e:
|
||||||
|
raise jsonschema.ValidationError(
|
||||||
|
"Could not migrate to version %s due to validation error: %s" %
|
||||||
|
(version, e.message))
|
||||||
|
self.version = version
|
0
lbrynet/schema/legacy/__init__.py
Normal file
0
lbrynet/schema/legacy/__init__.py
Normal file
276
lbrynet/schema/legacy/metadata_schemas.py
Normal file
276
lbrynet/schema/legacy/metadata_schemas.py
Normal file
|
@ -0,0 +1,276 @@
|
||||||
|
VER_001 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY metadata schema 0.0.1',
|
||||||
|
'definitions': {
|
||||||
|
'fee_info': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'ver': {
|
||||||
|
'type': 'string',
|
||||||
|
'default': '0.0.1'
|
||||||
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'author': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'content-type': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'lbry_sd_hash': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'btih': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
},
|
||||||
|
'thumbnail': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'preview': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'fee': {
|
||||||
|
'properties': {
|
||||||
|
'LBC': {'$ref': '#/definitions/fee_info'},
|
||||||
|
'BTC': {'$ref': '#/definitions/fee_info'},
|
||||||
|
'USD': {'$ref': '#/definitions/fee_info'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'contact': {
|
||||||
|
'type': 'number'
|
||||||
|
},
|
||||||
|
'pubkey': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
},
|
||||||
|
'required': [
|
||||||
|
'title', 'description', 'author', 'language', 'license', 'content-type', 'sources'],
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VER_002 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY metadata schema 0.0.2',
|
||||||
|
'definitions': {
|
||||||
|
'fee_info': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'ver': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['0.0.2'],
|
||||||
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'author': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'content-type': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'lbry_sd_hash': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'btih': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
},
|
||||||
|
'thumbnail': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'preview': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'fee': {
|
||||||
|
'properties': {
|
||||||
|
'LBC': {'$ref': '#/definitions/fee_info'},
|
||||||
|
'BTC': {'$ref': '#/definitions/fee_info'},
|
||||||
|
'USD': {'$ref': '#/definitions/fee_info'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'contact': {
|
||||||
|
'type': 'number'
|
||||||
|
},
|
||||||
|
'pubkey': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license_url': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'nsfw': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': False
|
||||||
|
},
|
||||||
|
|
||||||
|
},
|
||||||
|
'required': [
|
||||||
|
'ver', 'title', 'description', 'author', 'language', 'license',
|
||||||
|
'content-type', 'sources', 'nsfw'
|
||||||
|
],
|
||||||
|
'additionalProperties': False
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
VER_003 = {
|
||||||
|
'$schema': 'http://json-schema.org/draft-04/schema#',
|
||||||
|
'title': 'LBRY metadata schema 0.0.3',
|
||||||
|
'definitions': {
|
||||||
|
'fee_info': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'amount': {
|
||||||
|
'type': 'number',
|
||||||
|
'minimum': 0,
|
||||||
|
'exclusiveMinimum': True,
|
||||||
|
},
|
||||||
|
'address': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'type': 'object',
|
||||||
|
|
||||||
|
'properties': {
|
||||||
|
'ver': {
|
||||||
|
'type': 'string',
|
||||||
|
'enum': ['0.0.3'],
|
||||||
|
},
|
||||||
|
'title': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'description': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'author': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'language': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'content_type': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'sources': {
|
||||||
|
'type': 'object',
|
||||||
|
'properties': {
|
||||||
|
'lbry_sd_hash': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'btih': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'url': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'additionalProperties': False
|
||||||
|
},
|
||||||
|
'thumbnail': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'preview': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'fee': {
|
||||||
|
'properties': {
|
||||||
|
'LBC': {'$ref': '#/definitions/fee_info'},
|
||||||
|
'BTC': {'$ref': '#/definitions/fee_info'},
|
||||||
|
'USD': {'$ref': '#/definitions/fee_info'}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'contact': {
|
||||||
|
'type': 'number'
|
||||||
|
},
|
||||||
|
'pubkey': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'license_url': {
|
||||||
|
'type': 'string'
|
||||||
|
},
|
||||||
|
'nsfw': {
|
||||||
|
'type': 'boolean',
|
||||||
|
'default': False
|
||||||
|
},
|
||||||
|
'sig': {
|
||||||
|
'type': 'string'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'required': [
|
||||||
|
'ver', 'title', 'description', 'author', 'language', 'license',
|
||||||
|
'content_type', 'sources', 'nsfw'
|
||||||
|
],
|
||||||
|
'additionalProperties': False,
|
||||||
|
'dependencies': {
|
||||||
|
'pubkey': ['sig'],
|
||||||
|
'sig': ['pubkey']
|
||||||
|
}
|
||||||
|
}
|
79
lbrynet/schema/legacy/migrate.py
Normal file
79
lbrynet/schema/legacy/migrate.py
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
"""
|
||||||
|
migrate claim json schema (0.0.1-3) to protobuf (0.1.0)
|
||||||
|
"""
|
||||||
|
|
||||||
|
from lbryschema.legacy import metadata_schemas
|
||||||
|
from lbryschema.claim import ClaimDict
|
||||||
|
from .StructuredDict import StructuredDict
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_001_to_002(metadata):
|
||||||
|
metadata['ver'] = '0.0.2'
|
||||||
|
metadata['nsfw'] = False
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_002_to_003(metadata):
|
||||||
|
metadata['ver'] = '0.0.3'
|
||||||
|
if 'content-type' in metadata:
|
||||||
|
metadata['content_type'] = metadata['content-type']
|
||||||
|
del metadata['content-type']
|
||||||
|
|
||||||
|
|
||||||
|
class LegacyMetadata(StructuredDict):
|
||||||
|
current_version = '0.0.3'
|
||||||
|
|
||||||
|
_versions = [
|
||||||
|
('0.0.1', metadata_schemas.VER_001, None),
|
||||||
|
('0.0.2', metadata_schemas.VER_002, migrate_001_to_002),
|
||||||
|
('0.0.3', metadata_schemas.VER_003, migrate_002_to_003)
|
||||||
|
]
|
||||||
|
|
||||||
|
def __init__(self, metadata, migrate=True, target_version=None):
|
||||||
|
if not isinstance(metadata, dict):
|
||||||
|
raise TypeError("{} is not a dictionary".format(metadata))
|
||||||
|
starting_version = metadata.get('ver', '0.0.1')
|
||||||
|
|
||||||
|
StructuredDict.__init__(self, metadata, starting_version, migrate, target_version)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate_003_to_010(value):
|
||||||
|
migrated_to_003 = LegacyMetadata(value)
|
||||||
|
metadata = {
|
||||||
|
"version": "_0_1_0"
|
||||||
|
}
|
||||||
|
for k in ["author", "description", "language", "license", "nsfw", "thumbnail", "title",
|
||||||
|
"preview"]:
|
||||||
|
if k in migrated_to_003:
|
||||||
|
metadata.update({k: migrated_to_003[k]})
|
||||||
|
|
||||||
|
if 'license_url' in migrated_to_003:
|
||||||
|
metadata['licenseUrl'] = migrated_to_003['license_url']
|
||||||
|
|
||||||
|
if "fee" in migrated_to_003:
|
||||||
|
fee = migrated_to_003["fee"]
|
||||||
|
currency = list(fee.keys())[0]
|
||||||
|
amount = fee[currency]['amount']
|
||||||
|
address = fee[currency]['address']
|
||||||
|
metadata.update(dict(fee={"currency": currency, "version": "_0_0_1",
|
||||||
|
"amount": amount, "address": address}))
|
||||||
|
source = {
|
||||||
|
"source": migrated_to_003['sources']['lbry_sd_hash'],
|
||||||
|
"contentType": migrated_to_003['content_type'],
|
||||||
|
"sourceType": "lbry_sd_hash",
|
||||||
|
"version": "_0_0_1"
|
||||||
|
}
|
||||||
|
|
||||||
|
migrated = {
|
||||||
|
"version": "_0_0_1",
|
||||||
|
"claimType": "streamType",
|
||||||
|
"stream": {
|
||||||
|
"version": "_0_0_1",
|
||||||
|
"metadata": metadata,
|
||||||
|
"source": source
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ClaimDict.load_dict(migrated)
|
||||||
|
|
||||||
|
|
||||||
|
def migrate(value):
|
||||||
|
return migrate_003_to_010(value)
|
0
lbrynet/schema/proto/__init__.py
Normal file
0
lbrynet/schema/proto/__init__.py
Normal file
18
lbrynet/schema/proto/certificate.proto
Normal file
18
lbrynet/schema/proto/certificate.proto
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
enum KeyType {
|
||||||
|
UNKNOWN_PUBLIC_KEY_TYPE = 0;
|
||||||
|
NIST256p = 1;
|
||||||
|
NIST384p = 2;
|
||||||
|
SECP256k1 = 3;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Certificate {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
required KeyType keyType = 2;
|
||||||
|
required bytes publicKey = 4;
|
||||||
|
}
|
144
lbrynet/schema/proto/certificate_pb2.py
Normal file
144
lbrynet/schema/proto/certificate_pb2.py
Normal file
|
@ -0,0 +1,144 @@
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: lbryschema/proto/certificate.proto
|
||||||
|
|
||||||
|
import sys
|
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||||
|
from google.protobuf.internal import enum_type_wrapper
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf import descriptor_pb2
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
|
name='lbryschema/proto/certificate.proto',
|
||||||
|
package='',
|
||||||
|
serialized_pb=_b('\n\"lbryschema/proto/certificate.proto\"\x8e\x01\n\x0b\x43\x65rtificate\x12%\n\x07version\x18\x01 \x02(\x0e\x32\x14.Certificate.Version\x12\x19\n\x07keyType\x18\x02 \x02(\x0e\x32\x08.KeyType\x12\x11\n\tpublicKey\x18\x04 \x02(\x0c\"*\n\x07Version\x12\x13\n\x0fUNKNOWN_VERSION\x10\x00\x12\n\n\x06_0_0_1\x10\x01*Q\n\x07KeyType\x12\x1b\n\x17UNKNOWN_PUBLIC_KEY_TYPE\x10\x00\x12\x0c\n\x08NIST256p\x10\x01\x12\x0c\n\x08NIST384p\x10\x02\x12\r\n\tSECP256k1\x10\x03')
|
||||||
|
)
|
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
_KEYTYPE = _descriptor.EnumDescriptor(
|
||||||
|
name='KeyType',
|
||||||
|
full_name='KeyType',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_PUBLIC_KEY_TYPE', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='NIST256p', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='NIST384p', index=2, number=2,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='SECP256k1', index=3, number=3,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=183,
|
||||||
|
serialized_end=264,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_KEYTYPE)
|
||||||
|
|
||||||
|
KeyType = enum_type_wrapper.EnumTypeWrapper(_KEYTYPE)
|
||||||
|
UNKNOWN_PUBLIC_KEY_TYPE = 0
|
||||||
|
NIST256p = 1
|
||||||
|
NIST384p = 2
|
||||||
|
SECP256k1 = 3
|
||||||
|
|
||||||
|
|
||||||
|
_CERTIFICATE_VERSION = _descriptor.EnumDescriptor(
|
||||||
|
name='Version',
|
||||||
|
full_name='Certificate.Version',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_VERSION', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='_0_0_1', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=139,
|
||||||
|
serialized_end=181,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_CERTIFICATE_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
_CERTIFICATE = _descriptor.Descriptor(
|
||||||
|
name='Certificate',
|
||||||
|
full_name='Certificate',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='version', full_name='Certificate.version', index=0,
|
||||||
|
number=1, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='keyType', full_name='Certificate.keyType', index=1,
|
||||||
|
number=2, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='publicKey', full_name='Certificate.publicKey', index=2,
|
||||||
|
number=4, type=12, cpp_type=9, label=2,
|
||||||
|
has_default_value=False, default_value=_b(""),
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
_CERTIFICATE_VERSION,
|
||||||
|
],
|
||||||
|
options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=39,
|
||||||
|
serialized_end=181,
|
||||||
|
)
|
||||||
|
|
||||||
|
_CERTIFICATE.fields_by_name['version'].enum_type = _CERTIFICATE_VERSION
|
||||||
|
_CERTIFICATE.fields_by_name['keyType'].enum_type = _KEYTYPE
|
||||||
|
_CERTIFICATE_VERSION.containing_type = _CERTIFICATE
|
||||||
|
DESCRIPTOR.message_types_by_name['Certificate'] = _CERTIFICATE
|
||||||
|
DESCRIPTOR.enum_types_by_name['KeyType'] = _KEYTYPE
|
||||||
|
|
||||||
|
Certificate = _reflection.GeneratedProtocolMessageType('Certificate', (_message.Message,), dict(
|
||||||
|
DESCRIPTOR = _CERTIFICATE,
|
||||||
|
__module__ = 'lbryschema.proto.certificate_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:Certificate)
|
||||||
|
))
|
||||||
|
_sym_db.RegisterMessage(Certificate)
|
||||||
|
|
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
22
lbrynet/schema/proto/claim.proto
Normal file
22
lbrynet/schema/proto/claim.proto
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
import "lbryschema/proto/stream.proto";
|
||||||
|
import "lbryschema/proto/certificate.proto";
|
||||||
|
import "lbryschema/proto/signature.proto";
|
||||||
|
|
||||||
|
message Claim {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
enum ClaimType {
|
||||||
|
UNKNOWN_CLAIM_TYPE = 0;
|
||||||
|
streamType = 1;
|
||||||
|
certificateType = 2;
|
||||||
|
}
|
||||||
|
required ClaimType claimType = 2;
|
||||||
|
optional Stream stream = 3;
|
||||||
|
optional Certificate certificate = 4;
|
||||||
|
optional Signature publisherSignature = 5;
|
||||||
|
}
|
156
lbrynet/schema/proto/claim_pb2.py
Normal file
156
lbrynet/schema/proto/claim_pb2.py
Normal file
|
@ -0,0 +1,156 @@
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: lbryschema/proto/claim.proto
|
||||||
|
|
||||||
|
import sys
|
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf import descriptor_pb2
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
import lbryschema.proto.stream_pb2
|
||||||
|
import lbryschema.proto.certificate_pb2
|
||||||
|
import lbryschema.proto.signature_pb2
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
|
name='lbryschema/proto/claim.proto',
|
||||||
|
package='',
|
||||||
|
serialized_pb=_b('\n\x1clbryschema/proto/claim.proto\x1a\x1dlbryschema/proto/stream.proto\x1a\"lbryschema/proto/certificate.proto\x1a lbryschema/proto/signature.proto\"\xa7\x02\n\x05\x43laim\x12\x1f\n\x07version\x18\x01 \x02(\x0e\x32\x0e.Claim.Version\x12#\n\tclaimType\x18\x02 \x02(\x0e\x32\x10.Claim.ClaimType\x12\x17\n\x06stream\x18\x03 \x01(\x0b\x32\x07.Stream\x12!\n\x0b\x63\x65rtificate\x18\x04 \x01(\x0b\x32\x0c.Certificate\x12&\n\x12publisherSignature\x18\x05 \x01(\x0b\x32\n.Signature\"*\n\x07Version\x12\x13\n\x0fUNKNOWN_VERSION\x10\x00\x12\n\n\x06_0_0_1\x10\x01\"H\n\tClaimType\x12\x16\n\x12UNKNOWN_CLAIM_TYPE\x10\x00\x12\x0e\n\nstreamType\x10\x01\x12\x13\n\x0f\x63\x65rtificateType\x10\x02')
|
||||||
|
,
|
||||||
|
dependencies=[lbryschema.proto.stream_pb2.DESCRIPTOR,lbryschema.proto.certificate_pb2.DESCRIPTOR,lbryschema.proto.signature_pb2.DESCRIPTOR,])
|
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_CLAIM_VERSION = _descriptor.EnumDescriptor(
|
||||||
|
name='Version',
|
||||||
|
full_name='Claim.Version',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_VERSION', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='_0_0_1', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=313,
|
||||||
|
serialized_end=355,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_CLAIM_VERSION)
|
||||||
|
|
||||||
|
_CLAIM_CLAIMTYPE = _descriptor.EnumDescriptor(
|
||||||
|
name='ClaimType',
|
||||||
|
full_name='Claim.ClaimType',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_CLAIM_TYPE', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='streamType', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='certificateType', index=2, number=2,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=357,
|
||||||
|
serialized_end=429,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_CLAIM_CLAIMTYPE)
|
||||||
|
|
||||||
|
|
||||||
|
_CLAIM = _descriptor.Descriptor(
|
||||||
|
name='Claim',
|
||||||
|
full_name='Claim',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='version', full_name='Claim.version', index=0,
|
||||||
|
number=1, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='claimType', full_name='Claim.claimType', index=1,
|
||||||
|
number=2, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='stream', full_name='Claim.stream', index=2,
|
||||||
|
number=3, type=11, cpp_type=10, label=1,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='certificate', full_name='Claim.certificate', index=3,
|
||||||
|
number=4, type=11, cpp_type=10, label=1,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='publisherSignature', full_name='Claim.publisherSignature', index=4,
|
||||||
|
number=5, type=11, cpp_type=10, label=1,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
_CLAIM_VERSION,
|
||||||
|
_CLAIM_CLAIMTYPE,
|
||||||
|
],
|
||||||
|
options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=134,
|
||||||
|
serialized_end=429,
|
||||||
|
)
|
||||||
|
|
||||||
|
_CLAIM.fields_by_name['version'].enum_type = _CLAIM_VERSION
|
||||||
|
_CLAIM.fields_by_name['claimType'].enum_type = _CLAIM_CLAIMTYPE
|
||||||
|
_CLAIM.fields_by_name['stream'].message_type = lbryschema.proto.stream_pb2._STREAM
|
||||||
|
_CLAIM.fields_by_name['certificate'].message_type = lbryschema.proto.certificate_pb2._CERTIFICATE
|
||||||
|
_CLAIM.fields_by_name['publisherSignature'].message_type = lbryschema.proto.signature_pb2._SIGNATURE
|
||||||
|
_CLAIM_VERSION.containing_type = _CLAIM
|
||||||
|
_CLAIM_CLAIMTYPE.containing_type = _CLAIM
|
||||||
|
DESCRIPTOR.message_types_by_name['Claim'] = _CLAIM
|
||||||
|
|
||||||
|
Claim = _reflection.GeneratedProtocolMessageType('Claim', (_message.Message,), dict(
|
||||||
|
DESCRIPTOR = _CLAIM,
|
||||||
|
__module__ = 'lbryschema.proto.claim_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:Claim)
|
||||||
|
))
|
||||||
|
_sym_db.RegisterMessage(Claim)
|
||||||
|
|
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
18
lbrynet/schema/proto/fee.proto
Normal file
18
lbrynet/schema/proto/fee.proto
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
message Fee {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
}
|
||||||
|
enum Currency {
|
||||||
|
UNKNOWN_CURRENCY = 0;
|
||||||
|
LBC = 1;
|
||||||
|
BTC = 2;
|
||||||
|
USD = 3;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
required Currency currency = 2;
|
||||||
|
required bytes address = 3;
|
||||||
|
required float amount = 4;
|
||||||
|
}
|
146
lbrynet/schema/proto/fee_pb2.py
Normal file
146
lbrynet/schema/proto/fee_pb2.py
Normal file
|
@ -0,0 +1,146 @@
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: lbryschema/proto/fee.proto
|
||||||
|
|
||||||
|
import sys
|
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf import descriptor_pb2
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
|
name='lbryschema/proto/fee.proto',
|
||||||
|
package='',
|
||||||
|
serialized_pb=_b('\n\x1albryschema/proto/fee.proto\"\xcf\x01\n\x03\x46\x65\x65\x12\x1d\n\x07version\x18\x01 \x02(\x0e\x32\x0c.Fee.Version\x12\x1f\n\x08\x63urrency\x18\x02 \x02(\x0e\x32\r.Fee.Currency\x12\x0f\n\x07\x61\x64\x64ress\x18\x03 \x02(\x0c\x12\x0e\n\x06\x61mount\x18\x04 \x02(\x02\"*\n\x07Version\x12\x13\n\x0fUNKNOWN_VERSION\x10\x00\x12\n\n\x06_0_0_1\x10\x01\";\n\x08\x43urrency\x12\x14\n\x10UNKNOWN_CURRENCY\x10\x00\x12\x07\n\x03LBC\x10\x01\x12\x07\n\x03\x42TC\x10\x02\x12\x07\n\x03USD\x10\x03')
|
||||||
|
)
|
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_FEE_VERSION = _descriptor.EnumDescriptor(
|
||||||
|
name='Version',
|
||||||
|
full_name='Fee.Version',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_VERSION', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='_0_0_1', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=135,
|
||||||
|
serialized_end=177,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_FEE_VERSION)
|
||||||
|
|
||||||
|
_FEE_CURRENCY = _descriptor.EnumDescriptor(
|
||||||
|
name='Currency',
|
||||||
|
full_name='Fee.Currency',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_CURRENCY', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='LBC', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='BTC', index=2, number=2,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='USD', index=3, number=3,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=179,
|
||||||
|
serialized_end=238,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_FEE_CURRENCY)
|
||||||
|
|
||||||
|
|
||||||
|
_FEE = _descriptor.Descriptor(
|
||||||
|
name='Fee',
|
||||||
|
full_name='Fee',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='version', full_name='Fee.version', index=0,
|
||||||
|
number=1, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='currency', full_name='Fee.currency', index=1,
|
||||||
|
number=2, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='address', full_name='Fee.address', index=2,
|
||||||
|
number=3, type=12, cpp_type=9, label=2,
|
||||||
|
has_default_value=False, default_value=_b(""),
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='amount', full_name='Fee.amount', index=3,
|
||||||
|
number=4, type=2, cpp_type=6, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
_FEE_VERSION,
|
||||||
|
_FEE_CURRENCY,
|
||||||
|
],
|
||||||
|
options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=31,
|
||||||
|
serialized_end=238,
|
||||||
|
)
|
||||||
|
|
||||||
|
_FEE.fields_by_name['version'].enum_type = _FEE_VERSION
|
||||||
|
_FEE.fields_by_name['currency'].enum_type = _FEE_CURRENCY
|
||||||
|
_FEE_VERSION.containing_type = _FEE
|
||||||
|
_FEE_CURRENCY.containing_type = _FEE
|
||||||
|
DESCRIPTOR.message_types_by_name['Fee'] = _FEE
|
||||||
|
|
||||||
|
Fee = _reflection.GeneratedProtocolMessageType('Fee', (_message.Message,), dict(
|
||||||
|
DESCRIPTOR = _FEE,
|
||||||
|
__module__ = 'lbryschema.proto.fee_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:Fee)
|
||||||
|
))
|
||||||
|
_sym_db.RegisterMessage(Fee)
|
||||||
|
|
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
212
lbrynet/schema/proto/metadata.proto
Normal file
212
lbrynet/schema/proto/metadata.proto
Normal file
|
@ -0,0 +1,212 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
import "lbryschema/proto/fee.proto";
|
||||||
|
|
||||||
|
message Metadata {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
_0_0_2 = 2;
|
||||||
|
_0_0_3 = 3;
|
||||||
|
_0_1_0 = 4;
|
||||||
|
}
|
||||||
|
enum Language {
|
||||||
|
UNKNOWN_LANGUAGE = 0;
|
||||||
|
en = 1;
|
||||||
|
aa = 2;
|
||||||
|
ab = 3;
|
||||||
|
ae = 4;
|
||||||
|
af = 5;
|
||||||
|
ak = 6;
|
||||||
|
am = 7;
|
||||||
|
an = 8;
|
||||||
|
ar = 9;
|
||||||
|
as = 10;
|
||||||
|
av = 11;
|
||||||
|
ay = 12;
|
||||||
|
az = 13;
|
||||||
|
ba = 14;
|
||||||
|
be = 15;
|
||||||
|
bg = 16;
|
||||||
|
bh = 17;
|
||||||
|
bi = 18;
|
||||||
|
bm = 19;
|
||||||
|
bn = 20;
|
||||||
|
bo = 21;
|
||||||
|
br = 22;
|
||||||
|
bs = 23;
|
||||||
|
ca = 24;
|
||||||
|
ce = 25;
|
||||||
|
ch = 26;
|
||||||
|
co = 27;
|
||||||
|
cr = 28;
|
||||||
|
cs = 29;
|
||||||
|
cu = 30;
|
||||||
|
cv = 31;
|
||||||
|
cy = 32;
|
||||||
|
da = 33;
|
||||||
|
de = 34;
|
||||||
|
dv = 35;
|
||||||
|
dz = 36;
|
||||||
|
ee = 37;
|
||||||
|
el = 38;
|
||||||
|
eo = 39;
|
||||||
|
es = 40;
|
||||||
|
et = 41;
|
||||||
|
eu = 42;
|
||||||
|
fa = 43;
|
||||||
|
ff = 44;
|
||||||
|
fi = 45;
|
||||||
|
fj = 46;
|
||||||
|
fo = 47;
|
||||||
|
fr = 48;
|
||||||
|
fy = 49;
|
||||||
|
ga = 50;
|
||||||
|
gd = 51;
|
||||||
|
gl = 52;
|
||||||
|
gn = 53;
|
||||||
|
gu = 54;
|
||||||
|
gv = 55;
|
||||||
|
ha = 56;
|
||||||
|
he = 57;
|
||||||
|
hi = 58;
|
||||||
|
ho = 59;
|
||||||
|
hr = 60;
|
||||||
|
ht = 61;
|
||||||
|
hu = 62;
|
||||||
|
hy = 63;
|
||||||
|
hz = 64;
|
||||||
|
ia = 65;
|
||||||
|
id = 66;
|
||||||
|
ie = 67;
|
||||||
|
ig = 68;
|
||||||
|
ii = 69;
|
||||||
|
ik = 70;
|
||||||
|
io = 71;
|
||||||
|
is = 72;
|
||||||
|
it = 73;
|
||||||
|
iu = 74;
|
||||||
|
ja = 75;
|
||||||
|
jv = 76;
|
||||||
|
ka = 77;
|
||||||
|
kg = 78;
|
||||||
|
ki = 79;
|
||||||
|
kj = 80;
|
||||||
|
kk = 81;
|
||||||
|
kl = 82;
|
||||||
|
km = 83;
|
||||||
|
kn = 84;
|
||||||
|
ko = 85;
|
||||||
|
kr = 86;
|
||||||
|
ks = 87;
|
||||||
|
ku = 88;
|
||||||
|
kv = 89;
|
||||||
|
kw = 90;
|
||||||
|
ky = 91;
|
||||||
|
la = 92;
|
||||||
|
lb = 93;
|
||||||
|
lg = 94;
|
||||||
|
li = 95;
|
||||||
|
ln = 96;
|
||||||
|
lo = 97;
|
||||||
|
lt = 98;
|
||||||
|
lu = 99;
|
||||||
|
lv = 100;
|
||||||
|
mg = 101;
|
||||||
|
mh = 102;
|
||||||
|
mi = 103;
|
||||||
|
mk = 104;
|
||||||
|
ml = 105;
|
||||||
|
mn = 106;
|
||||||
|
mr = 107;
|
||||||
|
ms = 108;
|
||||||
|
mt = 109;
|
||||||
|
my = 110;
|
||||||
|
na = 111;
|
||||||
|
nb = 112;
|
||||||
|
nd = 113;
|
||||||
|
ne = 114;
|
||||||
|
ng = 115;
|
||||||
|
nl = 116;
|
||||||
|
nn = 117;
|
||||||
|
no = 118;
|
||||||
|
nr = 119;
|
||||||
|
nv = 120;
|
||||||
|
ny = 121;
|
||||||
|
oc = 122;
|
||||||
|
oj = 123;
|
||||||
|
om = 124;
|
||||||
|
or = 125;
|
||||||
|
os = 126;
|
||||||
|
pa = 127;
|
||||||
|
pi = 128;
|
||||||
|
pl = 129;
|
||||||
|
ps = 130;
|
||||||
|
pt = 131;
|
||||||
|
qu = 132;
|
||||||
|
rm = 133;
|
||||||
|
rn = 134;
|
||||||
|
ro = 135;
|
||||||
|
ru = 136;
|
||||||
|
rw = 137;
|
||||||
|
sa = 138;
|
||||||
|
sc = 139;
|
||||||
|
sd = 140;
|
||||||
|
se = 141;
|
||||||
|
sg = 142;
|
||||||
|
si = 143;
|
||||||
|
sk = 144;
|
||||||
|
sl = 145;
|
||||||
|
sm = 146;
|
||||||
|
sn = 147;
|
||||||
|
so = 148;
|
||||||
|
sq = 149;
|
||||||
|
sr = 150;
|
||||||
|
ss = 151;
|
||||||
|
st = 152;
|
||||||
|
su = 153;
|
||||||
|
sv = 154;
|
||||||
|
sw = 155;
|
||||||
|
ta = 156;
|
||||||
|
te = 157;
|
||||||
|
tg = 158;
|
||||||
|
th = 159;
|
||||||
|
ti = 160;
|
||||||
|
tk = 161;
|
||||||
|
tl = 162;
|
||||||
|
tn = 163;
|
||||||
|
to = 164;
|
||||||
|
tr = 165;
|
||||||
|
ts = 166;
|
||||||
|
tt = 167;
|
||||||
|
tw = 168;
|
||||||
|
ty = 169;
|
||||||
|
ug = 170;
|
||||||
|
uk = 171;
|
||||||
|
ur = 172;
|
||||||
|
uz = 173;
|
||||||
|
ve = 174;
|
||||||
|
vi = 175;
|
||||||
|
vo = 176;
|
||||||
|
wa = 177;
|
||||||
|
wo = 178;
|
||||||
|
xh = 179;
|
||||||
|
yi = 180;
|
||||||
|
yo = 181;
|
||||||
|
za = 182;
|
||||||
|
zh = 183;
|
||||||
|
zu = 184;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
required Language language = 2;
|
||||||
|
required string title = 3;
|
||||||
|
required string description = 4;
|
||||||
|
required string author = 5;
|
||||||
|
required string license = 6;
|
||||||
|
required bool nsfw = 7;
|
||||||
|
|
||||||
|
optional Fee fee = 8;
|
||||||
|
optional string thumbnail = 9;
|
||||||
|
optional string preview = 10;
|
||||||
|
optional string licenseUrl = 11;
|
||||||
|
}
|
934
lbrynet/schema/proto/metadata_pb2.py
Normal file
934
lbrynet/schema/proto/metadata_pb2.py
Normal file
File diff suppressed because one or more lines are too long
14
lbrynet/schema/proto/signature.proto
Normal file
14
lbrynet/schema/proto/signature.proto
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
import "lbryschema/proto/certificate.proto";
|
||||||
|
|
||||||
|
message Signature {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
required KeyType signatureType = 2;
|
||||||
|
required bytes signature = 3;
|
||||||
|
required bytes certificateId = 4;
|
||||||
|
}
|
116
lbrynet/schema/proto/signature_pb2.py
Normal file
116
lbrynet/schema/proto/signature_pb2.py
Normal file
|
@ -0,0 +1,116 @@
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: lbryschema/proto/signature.proto
|
||||||
|
|
||||||
|
import sys
|
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf import descriptor_pb2
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
import lbryschema.proto.certificate_pb2
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
|
name='lbryschema/proto/signature.proto',
|
||||||
|
package='',
|
||||||
|
serialized_pb=_b('\n lbryschema/proto/signature.proto\x1a\"lbryschema/proto/certificate.proto\"\xa7\x01\n\tSignature\x12#\n\x07version\x18\x01 \x02(\x0e\x32\x12.Signature.Version\x12\x1f\n\rsignatureType\x18\x02 \x02(\x0e\x32\x08.KeyType\x12\x11\n\tsignature\x18\x03 \x02(\x0c\x12\x15\n\rcertificateId\x18\x04 \x02(\x0c\"*\n\x07Version\x12\x13\n\x0fUNKNOWN_VERSION\x10\x00\x12\n\n\x06_0_0_1\x10\x01')
|
||||||
|
,
|
||||||
|
dependencies=[lbryschema.proto.certificate_pb2.DESCRIPTOR,])
|
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_SIGNATURE_VERSION = _descriptor.EnumDescriptor(
|
||||||
|
name='Version',
|
||||||
|
full_name='Signature.Version',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_VERSION', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='_0_0_1', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=198,
|
||||||
|
serialized_end=240,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_SIGNATURE_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
_SIGNATURE = _descriptor.Descriptor(
|
||||||
|
name='Signature',
|
||||||
|
full_name='Signature',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='version', full_name='Signature.version', index=0,
|
||||||
|
number=1, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='signatureType', full_name='Signature.signatureType', index=1,
|
||||||
|
number=2, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='signature', full_name='Signature.signature', index=2,
|
||||||
|
number=3, type=12, cpp_type=9, label=2,
|
||||||
|
has_default_value=False, default_value=_b(""),
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='certificateId', full_name='Signature.certificateId', index=3,
|
||||||
|
number=4, type=12, cpp_type=9, label=2,
|
||||||
|
has_default_value=False, default_value=_b(""),
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
_SIGNATURE_VERSION,
|
||||||
|
],
|
||||||
|
options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=73,
|
||||||
|
serialized_end=240,
|
||||||
|
)
|
||||||
|
|
||||||
|
_SIGNATURE.fields_by_name['version'].enum_type = _SIGNATURE_VERSION
|
||||||
|
_SIGNATURE.fields_by_name['signatureType'].enum_type = lbryschema.proto.certificate_pb2._KEYTYPE
|
||||||
|
_SIGNATURE_VERSION.containing_type = _SIGNATURE
|
||||||
|
DESCRIPTOR.message_types_by_name['Signature'] = _SIGNATURE
|
||||||
|
|
||||||
|
Signature = _reflection.GeneratedProtocolMessageType('Signature', (_message.Message,), dict(
|
||||||
|
DESCRIPTOR = _SIGNATURE,
|
||||||
|
__module__ = 'lbryschema.proto.signature_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:Signature)
|
||||||
|
))
|
||||||
|
_sym_db.RegisterMessage(Signature)
|
||||||
|
|
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
16
lbrynet/schema/proto/source.proto
Normal file
16
lbrynet/schema/proto/source.proto
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
message Source {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
enum SourceTypes {
|
||||||
|
UNKNOWN_SOURCE_TYPE = 0;
|
||||||
|
lbry_sd_hash = 1;
|
||||||
|
}
|
||||||
|
required SourceTypes sourceType = 2;
|
||||||
|
required bytes source = 3;
|
||||||
|
required string contentType = 4;
|
||||||
|
}
|
138
lbrynet/schema/proto/source_pb2.py
Normal file
138
lbrynet/schema/proto/source_pb2.py
Normal file
|
@ -0,0 +1,138 @@
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: lbryschema/proto/source.proto
|
||||||
|
|
||||||
|
import sys
|
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf import descriptor_pb2
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
|
name='lbryschema/proto/source.proto',
|
||||||
|
package='',
|
||||||
|
serialized_pb=_b('\n\x1dlbryschema/proto/source.proto\"\xde\x01\n\x06Source\x12 \n\x07version\x18\x01 \x02(\x0e\x32\x0f.Source.Version\x12\'\n\nsourceType\x18\x02 \x02(\x0e\x32\x13.Source.SourceTypes\x12\x0e\n\x06source\x18\x03 \x02(\x0c\x12\x13\n\x0b\x63ontentType\x18\x04 \x02(\t\"*\n\x07Version\x12\x13\n\x0fUNKNOWN_VERSION\x10\x00\x12\n\n\x06_0_0_1\x10\x01\"8\n\x0bSourceTypes\x12\x17\n\x13UNKNOWN_SOURCE_TYPE\x10\x00\x12\x10\n\x0clbry_sd_hash\x10\x01')
|
||||||
|
)
|
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_SOURCE_VERSION = _descriptor.EnumDescriptor(
|
||||||
|
name='Version',
|
||||||
|
full_name='Source.Version',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_VERSION', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='_0_0_1', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=156,
|
||||||
|
serialized_end=198,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_SOURCE_VERSION)
|
||||||
|
|
||||||
|
_SOURCE_SOURCETYPES = _descriptor.EnumDescriptor(
|
||||||
|
name='SourceTypes',
|
||||||
|
full_name='Source.SourceTypes',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_SOURCE_TYPE', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='lbry_sd_hash', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=200,
|
||||||
|
serialized_end=256,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_SOURCE_SOURCETYPES)
|
||||||
|
|
||||||
|
|
||||||
|
_SOURCE = _descriptor.Descriptor(
|
||||||
|
name='Source',
|
||||||
|
full_name='Source',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='version', full_name='Source.version', index=0,
|
||||||
|
number=1, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='sourceType', full_name='Source.sourceType', index=1,
|
||||||
|
number=2, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='source', full_name='Source.source', index=2,
|
||||||
|
number=3, type=12, cpp_type=9, label=2,
|
||||||
|
has_default_value=False, default_value=_b(""),
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='contentType', full_name='Source.contentType', index=3,
|
||||||
|
number=4, type=9, cpp_type=9, label=2,
|
||||||
|
has_default_value=False, default_value=_b("").decode('utf-8'),
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
_SOURCE_VERSION,
|
||||||
|
_SOURCE_SOURCETYPES,
|
||||||
|
],
|
||||||
|
options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=34,
|
||||||
|
serialized_end=256,
|
||||||
|
)
|
||||||
|
|
||||||
|
_SOURCE.fields_by_name['version'].enum_type = _SOURCE_VERSION
|
||||||
|
_SOURCE.fields_by_name['sourceType'].enum_type = _SOURCE_SOURCETYPES
|
||||||
|
_SOURCE_VERSION.containing_type = _SOURCE
|
||||||
|
_SOURCE_SOURCETYPES.containing_type = _SOURCE
|
||||||
|
DESCRIPTOR.message_types_by_name['Source'] = _SOURCE
|
||||||
|
|
||||||
|
Source = _reflection.GeneratedProtocolMessageType('Source', (_message.Message,), dict(
|
||||||
|
DESCRIPTOR = _SOURCE,
|
||||||
|
__module__ = 'lbryschema.proto.source_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:Source)
|
||||||
|
))
|
||||||
|
_sym_db.RegisterMessage(Source)
|
||||||
|
|
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
15
lbrynet/schema/proto/stream.proto
Normal file
15
lbrynet/schema/proto/stream.proto
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
syntax = "proto2";
|
||||||
|
|
||||||
|
import "lbryschema/proto/metadata.proto";
|
||||||
|
import "lbryschema/proto/source.proto";
|
||||||
|
|
||||||
|
|
||||||
|
message Stream {
|
||||||
|
enum Version {
|
||||||
|
UNKNOWN_VERSION = 0;
|
||||||
|
_0_0_1 = 1;
|
||||||
|
}
|
||||||
|
required Version version = 1;
|
||||||
|
required Metadata metadata = 2;
|
||||||
|
required Source source = 3;
|
||||||
|
}
|
111
lbrynet/schema/proto/stream_pb2.py
Normal file
111
lbrynet/schema/proto/stream_pb2.py
Normal file
|
@ -0,0 +1,111 @@
|
||||||
|
# Generated by the protocol buffer compiler. DO NOT EDIT!
|
||||||
|
# source: lbryschema/proto/stream.proto
|
||||||
|
|
||||||
|
import sys
|
||||||
|
_b=sys.version_info[0]<3 and (lambda x:x) or (lambda x:x.encode('latin1'))
|
||||||
|
from google.protobuf import descriptor as _descriptor
|
||||||
|
from google.protobuf import message as _message
|
||||||
|
from google.protobuf import reflection as _reflection
|
||||||
|
from google.protobuf import symbol_database as _symbol_database
|
||||||
|
from google.protobuf import descriptor_pb2
|
||||||
|
# @@protoc_insertion_point(imports)
|
||||||
|
|
||||||
|
_sym_db = _symbol_database.Default()
|
||||||
|
|
||||||
|
|
||||||
|
import lbryschema.proto.metadata_pb2
|
||||||
|
import lbryschema.proto.source_pb2
|
||||||
|
|
||||||
|
|
||||||
|
DESCRIPTOR = _descriptor.FileDescriptor(
|
||||||
|
name='lbryschema/proto/stream.proto',
|
||||||
|
package='',
|
||||||
|
serialized_pb=_b('\n\x1dlbryschema/proto/stream.proto\x1a\x1flbryschema/proto/metadata.proto\x1a\x1dlbryschema/proto/source.proto\"\x8c\x01\n\x06Stream\x12 \n\x07version\x18\x01 \x02(\x0e\x32\x0f.Stream.Version\x12\x1b\n\x08metadata\x18\x02 \x02(\x0b\x32\t.Metadata\x12\x17\n\x06source\x18\x03 \x02(\x0b\x32\x07.Source\"*\n\x07Version\x12\x13\n\x0fUNKNOWN_VERSION\x10\x00\x12\n\n\x06_0_0_1\x10\x01')
|
||||||
|
,
|
||||||
|
dependencies=[lbryschema.proto.metadata_pb2.DESCRIPTOR,lbryschema.proto.source_pb2.DESCRIPTOR,])
|
||||||
|
_sym_db.RegisterFileDescriptor(DESCRIPTOR)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
_STREAM_VERSION = _descriptor.EnumDescriptor(
|
||||||
|
name='Version',
|
||||||
|
full_name='Stream.Version',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
values=[
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='UNKNOWN_VERSION', index=0, number=0,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
_descriptor.EnumValueDescriptor(
|
||||||
|
name='_0_0_1', index=1, number=1,
|
||||||
|
options=None,
|
||||||
|
type=None),
|
||||||
|
],
|
||||||
|
containing_type=None,
|
||||||
|
options=None,
|
||||||
|
serialized_start=196,
|
||||||
|
serialized_end=238,
|
||||||
|
)
|
||||||
|
_sym_db.RegisterEnumDescriptor(_STREAM_VERSION)
|
||||||
|
|
||||||
|
|
||||||
|
_STREAM = _descriptor.Descriptor(
|
||||||
|
name='Stream',
|
||||||
|
full_name='Stream',
|
||||||
|
filename=None,
|
||||||
|
file=DESCRIPTOR,
|
||||||
|
containing_type=None,
|
||||||
|
fields=[
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='version', full_name='Stream.version', index=0,
|
||||||
|
number=1, type=14, cpp_type=8, label=2,
|
||||||
|
has_default_value=False, default_value=0,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='metadata', full_name='Stream.metadata', index=1,
|
||||||
|
number=2, type=11, cpp_type=10, label=2,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
_descriptor.FieldDescriptor(
|
||||||
|
name='source', full_name='Stream.source', index=2,
|
||||||
|
number=3, type=11, cpp_type=10, label=2,
|
||||||
|
has_default_value=False, default_value=None,
|
||||||
|
message_type=None, enum_type=None, containing_type=None,
|
||||||
|
is_extension=False, extension_scope=None,
|
||||||
|
options=None),
|
||||||
|
],
|
||||||
|
extensions=[
|
||||||
|
],
|
||||||
|
nested_types=[],
|
||||||
|
enum_types=[
|
||||||
|
_STREAM_VERSION,
|
||||||
|
],
|
||||||
|
options=None,
|
||||||
|
is_extendable=False,
|
||||||
|
extension_ranges=[],
|
||||||
|
oneofs=[
|
||||||
|
],
|
||||||
|
serialized_start=98,
|
||||||
|
serialized_end=238,
|
||||||
|
)
|
||||||
|
|
||||||
|
_STREAM.fields_by_name['version'].enum_type = _STREAM_VERSION
|
||||||
|
_STREAM.fields_by_name['metadata'].message_type = lbryschema.proto.metadata_pb2._METADATA
|
||||||
|
_STREAM.fields_by_name['source'].message_type = lbryschema.proto.source_pb2._SOURCE
|
||||||
|
_STREAM_VERSION.containing_type = _STREAM
|
||||||
|
DESCRIPTOR.message_types_by_name['Stream'] = _STREAM
|
||||||
|
|
||||||
|
Stream = _reflection.GeneratedProtocolMessageType('Stream', (_message.Message,), dict(
|
||||||
|
DESCRIPTOR = _STREAM,
|
||||||
|
__module__ = 'lbryschema.proto.stream_pb2'
|
||||||
|
# @@protoc_insertion_point(class_scope:Stream)
|
||||||
|
))
|
||||||
|
_sym_db.RegisterMessage(Stream)
|
||||||
|
|
||||||
|
|
||||||
|
# @@protoc_insertion_point(module_scope)
|
102
lbrynet/schema/schema/__init__.py
Normal file
102
lbrynet/schema/schema/__init__.py
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
V_0_0_1 = "_0_0_1"
|
||||||
|
V_0_0_2 = "_0_0_2"
|
||||||
|
V_0_0_3 = "_0_0_3"
|
||||||
|
V_0_1_0 = "_0_1_0"
|
||||||
|
|
||||||
|
|
||||||
|
VERSION_MAP = {
|
||||||
|
V_0_0_1: 1,
|
||||||
|
V_0_0_2: 2,
|
||||||
|
V_0_0_3: 3,
|
||||||
|
V_0_1_0: 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
VERSION_NAMES = {
|
||||||
|
1: V_0_0_1,
|
||||||
|
2: V_0_0_2,
|
||||||
|
3: V_0_0_3,
|
||||||
|
4: V_0_1_0
|
||||||
|
}
|
||||||
|
|
||||||
|
LBC = "LBC"
|
||||||
|
BTC = "BTC"
|
||||||
|
USD = "USD"
|
||||||
|
|
||||||
|
CURRENCY_MAP = {
|
||||||
|
LBC: 1,
|
||||||
|
BTC: 2,
|
||||||
|
USD: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
CURRENCY_NAMES = {
|
||||||
|
1: LBC,
|
||||||
|
2: BTC,
|
||||||
|
3: USD
|
||||||
|
}
|
||||||
|
|
||||||
|
ADDRESS_LENGTH = 25
|
||||||
|
ADDRESS_CHECKSUM_LENGTH = 4
|
||||||
|
|
||||||
|
VERSION = "version"
|
||||||
|
STREAM_TYPE = "streamType"
|
||||||
|
CERTIFICATE_TYPE = "certificateType"
|
||||||
|
CLAIM_TYPE = "claimType"
|
||||||
|
SIGNATURE = "publisherSignature"
|
||||||
|
|
||||||
|
CLAIM_TYPES = {
|
||||||
|
STREAM_TYPE: "stream",
|
||||||
|
CERTIFICATE_TYPE: "certificate"
|
||||||
|
}
|
||||||
|
|
||||||
|
CLAIM_TYPE_NAMES = {
|
||||||
|
1: "stream",
|
||||||
|
2: "certificate"
|
||||||
|
}
|
||||||
|
|
||||||
|
LBRY_SD_HASH = "lbry_sd_hash"
|
||||||
|
LBRY_SD_HASH_LENGTH = 48
|
||||||
|
|
||||||
|
SOURCE_TYPES = {
|
||||||
|
LBRY_SD_HASH: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
NIST256p = "NIST256p"
|
||||||
|
NIST384p = "NIST384p"
|
||||||
|
SECP256k1 = "SECP256k1"
|
||||||
|
|
||||||
|
ECDSA_CURVES = {
|
||||||
|
NIST256p: 1,
|
||||||
|
NIST384p: 2,
|
||||||
|
SECP256k1: 3
|
||||||
|
}
|
||||||
|
|
||||||
|
CURVE_NAMES = {
|
||||||
|
1: NIST256p,
|
||||||
|
2: NIST384p,
|
||||||
|
3: SECP256k1
|
||||||
|
}
|
||||||
|
|
||||||
|
SHA256 = "sha256"
|
||||||
|
SHA384 = "sha384"
|
||||||
|
|
||||||
|
|
||||||
|
B58_CHARS = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz'
|
||||||
|
assert len(B58_CHARS) == 58
|
||||||
|
|
||||||
|
PUBKEY_ADDRESS = 0
|
||||||
|
SCRIPT_ADDRESS = 5
|
||||||
|
|
||||||
|
ADDRESS_PREFIXES = {
|
||||||
|
"lbrycrd_main": {
|
||||||
|
PUBKEY_ADDRESS: 85,
|
||||||
|
SCRIPT_ADDRESS: 122
|
||||||
|
},
|
||||||
|
"lbrycrd_regtest": {
|
||||||
|
PUBKEY_ADDRESS: 111,
|
||||||
|
SCRIPT_ADDRESS: 196
|
||||||
|
},
|
||||||
|
"lbrycrd_testnet": {
|
||||||
|
PUBKEY_ADDRESS: 111,
|
||||||
|
SCRIPT_ADDRESS: 196
|
||||||
|
},
|
||||||
|
}
|
54
lbrynet/schema/schema/certificate.py
Normal file
54
lbrynet/schema/schema/certificate.py
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from lbryschema.proto import certificate_pb2 as cert_pb
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
from lbryschema.schema import VERSION_MAP, V_0_0_1, ECDSA_CURVES, CURVE_NAMES
|
||||||
|
from lbryschema.validator import get_key_type_from_dem
|
||||||
|
|
||||||
|
|
||||||
|
class _ECDSAKeyHelper(object):
|
||||||
|
def __init__(self, key):
|
||||||
|
self._key = key
|
||||||
|
|
||||||
|
@property
|
||||||
|
def der(self):
|
||||||
|
return self._key.to_der()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def curve_name(self):
|
||||||
|
return self._key.curve.name
|
||||||
|
|
||||||
|
|
||||||
|
class Certificate(Schema):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_key = deepcopy(message)
|
||||||
|
_message_pb = cert_pb.Certificate()
|
||||||
|
if isinstance(_key, dict):
|
||||||
|
_message_pb.publicKey = _key.pop("publicKey")
|
||||||
|
_message_pb.version = VERSION_MAP[_key.pop("version")]
|
||||||
|
_message_pb.keyType = ECDSA_CURVES[_key.pop("keyType")]
|
||||||
|
else:
|
||||||
|
_message_pb.version = _key.version
|
||||||
|
_message_pb.keyType = _key.keyType
|
||||||
|
_message_pb.publicKey = _key.publicKey
|
||||||
|
if _message_pb.keyType not in CURVE_NAMES:
|
||||||
|
raise Exception("Unknown curve")
|
||||||
|
if get_key_type_from_dem(_message_pb.publicKey) != _message_pb.keyType:
|
||||||
|
raise Exception("Curve mismatch")
|
||||||
|
return cls._load(_key, _message_pb)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_from_key_obj(cls, key, key_type):
|
||||||
|
if key_type in ECDSA_CURVES:
|
||||||
|
_key = _ECDSAKeyHelper(key)
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown key type: %s" % str(type(key)))
|
||||||
|
if key_type != _key.curve_name:
|
||||||
|
raise Exception("Curve mismatch")
|
||||||
|
msg = {
|
||||||
|
"version": V_0_0_1,
|
||||||
|
"keyType": key_type,
|
||||||
|
"publicKey": _key.der,
|
||||||
|
}
|
||||||
|
return cls.load(msg)
|
51
lbrynet/schema/schema/claim.py
Normal file
51
lbrynet/schema/schema/claim.py
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from lbryschema.proto import claim_pb2 as claim_pb
|
||||||
|
from lbryschema.schema import VERSION_MAP
|
||||||
|
from lbryschema.schema.signature import Signature
|
||||||
|
from lbryschema.schema.certificate import Certificate
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
from lbryschema.schema.stream import Stream
|
||||||
|
|
||||||
|
|
||||||
|
class Claim(Schema):
|
||||||
|
CLAIM_TYPE_STREAM = 1
|
||||||
|
CLAIM_TYPE_CERT = 2
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_claim = deepcopy(message)
|
||||||
|
_message_pb = claim_pb.Claim()
|
||||||
|
_message_pb.version = VERSION_MAP[_claim.pop("version")]
|
||||||
|
|
||||||
|
if "certificate" in _claim:
|
||||||
|
_cert = _claim.pop("certificate")
|
||||||
|
if isinstance(_cert, dict):
|
||||||
|
cert = Certificate.load(_cert)
|
||||||
|
else:
|
||||||
|
cert = _cert
|
||||||
|
claim_type = Claim.CLAIM_TYPE_CERT
|
||||||
|
_message_pb.certificate.MergeFrom(cert)
|
||||||
|
|
||||||
|
elif "stream" in _claim:
|
||||||
|
_stream = _claim.pop("stream")
|
||||||
|
if isinstance(_stream, dict):
|
||||||
|
stream = Stream.load(_stream)
|
||||||
|
else:
|
||||||
|
stream = _stream
|
||||||
|
claim_type = Claim.CLAIM_TYPE_STREAM
|
||||||
|
_message_pb.stream.MergeFrom(stream)
|
||||||
|
else:
|
||||||
|
raise AttributeError
|
||||||
|
|
||||||
|
_message_pb.claimType = claim_type
|
||||||
|
|
||||||
|
if "publisherSignature" in _claim:
|
||||||
|
_publisherSignature = _claim.pop("publisherSignature")
|
||||||
|
if isinstance(_publisherSignature, dict):
|
||||||
|
publisherSignature = Signature.load(_publisherSignature)
|
||||||
|
else:
|
||||||
|
publisherSignature = _publisherSignature
|
||||||
|
_message_pb.publisherSignature.MergeFrom(publisherSignature)
|
||||||
|
|
||||||
|
return cls._load(_claim, _message_pb)
|
17
lbrynet/schema/schema/fee.py
Normal file
17
lbrynet/schema/schema/fee.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
from lbryschema.proto import fee_pb2 as fee_pb
|
||||||
|
from lbryschema.schema import VERSION_MAP, CURRENCY_MAP
|
||||||
|
|
||||||
|
|
||||||
|
class Fee(Schema):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_fee = deepcopy(message)
|
||||||
|
currency = CURRENCY_MAP[_fee.pop('currency')]
|
||||||
|
_message_pb = fee_pb.Fee()
|
||||||
|
_message_pb.version = VERSION_MAP[_fee.pop("version")]
|
||||||
|
_message_pb.currency = currency
|
||||||
|
_message_pb.address = _fee.pop('address')
|
||||||
|
return cls._load(_fee, _message_pb)
|
17
lbrynet/schema/schema/metadata.py
Normal file
17
lbrynet/schema/schema/metadata.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
from lbryschema.proto import metadata_pb2 as metadata_pb
|
||||||
|
from lbryschema.schema.fee import Fee
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
from lbryschema.schema import VERSION_MAP
|
||||||
|
|
||||||
|
|
||||||
|
class Metadata(Schema):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_metadata = deepcopy(message)
|
||||||
|
_message_pb = metadata_pb.Metadata()
|
||||||
|
_message_pb.version = VERSION_MAP[_metadata.pop("version")]
|
||||||
|
if 'fee' in _metadata:
|
||||||
|
fee_pb = Fee.load(_metadata.pop('fee'))
|
||||||
|
_message_pb.fee.CopyFrom(fee_pb)
|
||||||
|
return cls._load(_metadata, _message_pb)
|
15
lbrynet/schema/schema/schema.py
Normal file
15
lbrynet/schema/schema/schema.py
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
import json
|
||||||
|
import google.protobuf.json_format as json_pb # pylint: disable=no-name-in-module
|
||||||
|
from google.protobuf.message import Message # pylint: disable=no-name-in-module,import-error
|
||||||
|
|
||||||
|
|
||||||
|
class Schema(Message):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
raise NotImplementedError
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _load(cls, data, message):
|
||||||
|
if isinstance(data, dict):
|
||||||
|
data = json.dumps(data)
|
||||||
|
return json_pb.Parse(data, message)
|
17
lbrynet/schema/schema/signature.py
Normal file
17
lbrynet/schema/schema/signature.py
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from lbryschema.proto import signature_pb2 as signature_pb
|
||||||
|
from lbryschema.schema import VERSION_MAP, ECDSA_CURVES
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
|
||||||
|
|
||||||
|
class Signature(Schema):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_signature = deepcopy(message)
|
||||||
|
_message_pb = signature_pb.Signature()
|
||||||
|
_message_pb.version = VERSION_MAP[_signature.pop("version")]
|
||||||
|
_message_pb.signatureType = ECDSA_CURVES[_signature.pop("signatureType")]
|
||||||
|
_message_pb.certificateId = _signature.pop("certificateId")
|
||||||
|
_message_pb.signature = _signature.pop("signature")
|
||||||
|
return cls._load(_signature, _message_pb)
|
19
lbrynet/schema/schema/source.py
Normal file
19
lbrynet/schema/schema/source.py
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
from lbryschema.proto import source_pb2 as source_pb
|
||||||
|
from lbryschema.schema import SOURCE_TYPES, LBRY_SD_HASH_LENGTH, VERSION_MAP
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
from lbryschema.error import InvalidSourceHashLength
|
||||||
|
|
||||||
|
|
||||||
|
class Source(Schema):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_source = deepcopy(message)
|
||||||
|
sd_hash = _source.pop('source')
|
||||||
|
assert len(sd_hash) == LBRY_SD_HASH_LENGTH, InvalidSourceHashLength(len(sd_hash))
|
||||||
|
_message_pb = source_pb.Source()
|
||||||
|
_message_pb.version = VERSION_MAP[_source.pop("version")]
|
||||||
|
_message_pb.sourceType = SOURCE_TYPES[_source.pop('sourceType')]
|
||||||
|
_message_pb.source = sd_hash
|
||||||
|
_message_pb.contentType = _source.pop('contentType')
|
||||||
|
return cls._load(_source, _message_pb)
|
20
lbrynet/schema/schema/stream.py
Normal file
20
lbrynet/schema/schema/stream.py
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
from copy import deepcopy
|
||||||
|
|
||||||
|
from lbryschema.schema.source import Source
|
||||||
|
from lbryschema.proto import stream_pb2 as stream_pb
|
||||||
|
from lbryschema.schema import VERSION_MAP
|
||||||
|
from lbryschema.schema.metadata import Metadata
|
||||||
|
from lbryschema.schema.schema import Schema
|
||||||
|
|
||||||
|
|
||||||
|
class Stream(Schema):
|
||||||
|
@classmethod
|
||||||
|
def load(cls, message):
|
||||||
|
_claim = deepcopy(message)
|
||||||
|
source = Source.load(_claim.pop('source'))
|
||||||
|
metadata = Metadata.load(_claim.pop('metadata'))
|
||||||
|
_message_pb = stream_pb.Stream()
|
||||||
|
_message_pb.version = VERSION_MAP[_claim.pop("version")]
|
||||||
|
_message_pb.source.CopyFrom(source)
|
||||||
|
_message_pb.metadata.CopyFrom(metadata)
|
||||||
|
return cls._load(_claim, _message_pb)
|
41
lbrynet/schema/signature/flags.py
Normal file
41
lbrynet/schema/signature/flags.py
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
class SignatureSerializationFlag:
|
||||||
|
UNSIGNED = 0
|
||||||
|
'''
|
||||||
|
Format:
|
||||||
|
<FLAG><CLAIM BINARY>
|
||||||
|
or (legacy)
|
||||||
|
<CLAIM BINARY>
|
||||||
|
'''
|
||||||
|
ECDSA_LEGACY = 1
|
||||||
|
'''
|
||||||
|
Old claim format, which carried the signature inside the protobuf. Requires serializing back the claim with
|
||||||
|
signature stripped out for validation. This process requires knowledge on how a claim is serialized, thus requires
|
||||||
|
old fixed protobuf schema to work.
|
||||||
|
|
||||||
|
Format:
|
||||||
|
<CLAIM PROTOBUF SERIALIZED>
|
||||||
|
Curves: NIST256p, NIST384p, SECP256k1
|
||||||
|
Signature content: `r` and `s` in each half of the 64 or 96 bytes (depends on curve)
|
||||||
|
Signed payload:
|
||||||
|
1. Claim transaction output address (raw, decoded using base58)
|
||||||
|
2. Stripped out claim protobuf serialization (without the signature)
|
||||||
|
3. Certificate claim id (binary, not in network byte order)
|
||||||
|
'''
|
||||||
|
ECDSA_SECP256K1 = 2
|
||||||
|
'''
|
||||||
|
Format:
|
||||||
|
<FLAG><CERTIFICATE ID><SIGNATURE><BINARY PAYLOAD>
|
||||||
|
Curve: SECP256K1
|
||||||
|
Signature content: 64 bytes total, each half represents `r` and `s`
|
||||||
|
Signed payload:
|
||||||
|
1. raw claim name as bytes
|
||||||
|
2. Claim transaction output address (raw, decoded using base58)
|
||||||
|
3. Binary payload, independent of serialization (everything after the signature last byte)
|
||||||
|
4. Certificate claim id, not in network byte order.
|
||||||
|
|
||||||
|
A certificate can be signed as well, but this serialization model is unaware of content type or protobuf format.
|
||||||
|
'''
|
||||||
|
@classmethod
|
||||||
|
def is_flag_valid(cls, flag):
|
||||||
|
# todo: use python 3 enum when fully ported, but not worth now as its an extra dependency for py2
|
||||||
|
return 0 <= flag <= 2
|
11
lbrynet/schema/signature/serializer.py
Normal file
11
lbrynet/schema/signature/serializer.py
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
import struct
|
||||||
|
from collections import namedtuple
|
||||||
|
from .flags import SignatureSerializationFlag
|
||||||
|
|
||||||
|
|
||||||
|
class Signature(namedtuple("Signature", "flags signature certificate_id")):
|
||||||
|
def deserialize(cls, payload):
|
||||||
|
flag = struct.unpack("<b", payload[0])[0]
|
||||||
|
if not SignatureSerializationFlag.is_flag_valid(flag):
|
||||||
|
return Signature(SignatureSerializationFlag.ECDSA_LEGACY, )
|
||||||
|
certificate
|
102
lbrynet/schema/signer.py
Normal file
102
lbrynet/schema/signer.py
Normal file
|
@ -0,0 +1,102 @@
|
||||||
|
import ecdsa
|
||||||
|
import hashlib
|
||||||
|
import binascii
|
||||||
|
from lbryschema.address import decode_address
|
||||||
|
from lbryschema.encoding import decode_b64_fields
|
||||||
|
from lbryschema.schema.certificate import Certificate
|
||||||
|
from lbryschema.schema.claim import Claim
|
||||||
|
from lbryschema.validator import validate_claim_id
|
||||||
|
from lbryschema.schema import V_0_0_1, CLAIM_TYPE, CLAIM_TYPES, CERTIFICATE_TYPE, VERSION
|
||||||
|
from lbryschema.schema import NIST256p, NIST384p, SECP256k1, SHA256, SHA384
|
||||||
|
|
||||||
|
|
||||||
|
class NIST_ECDSASigner(object):
|
||||||
|
CURVE = None
|
||||||
|
CURVE_NAME = None
|
||||||
|
HASHFUNC = hashlib.sha256
|
||||||
|
HASHFUNC_NAME = SHA256
|
||||||
|
|
||||||
|
def __init__(self, private_key):
|
||||||
|
self._private_key = private_key
|
||||||
|
|
||||||
|
@property
|
||||||
|
def private_key(self):
|
||||||
|
return self._private_key
|
||||||
|
|
||||||
|
@property
|
||||||
|
def public_key(self):
|
||||||
|
return self.private_key.get_verifying_key()
|
||||||
|
|
||||||
|
@property
|
||||||
|
def certificate(self):
|
||||||
|
certificate_claim = {
|
||||||
|
VERSION: V_0_0_1,
|
||||||
|
CLAIM_TYPE: CERTIFICATE_TYPE,
|
||||||
|
CLAIM_TYPES[CERTIFICATE_TYPE]: Certificate.load_from_key_obj(self.public_key,
|
||||||
|
self.CURVE_NAME)
|
||||||
|
}
|
||||||
|
return Claim.load(certificate_claim)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_pem(cls, pem_string):
|
||||||
|
return cls(ecdsa.SigningKey.from_pem(pem_string, hashfunc=cls.HASHFUNC_NAME))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def generate(cls):
|
||||||
|
return cls(ecdsa.SigningKey.generate(curve=cls.CURVE, hashfunc=cls.HASHFUNC_NAME))
|
||||||
|
|
||||||
|
def sign_stream_claim(self, claim, claim_address, cert_claim_id):
|
||||||
|
validate_claim_id(cert_claim_id)
|
||||||
|
decoded_addr = decode_address(claim_address)
|
||||||
|
|
||||||
|
to_sign = bytearray()
|
||||||
|
to_sign.extend(decoded_addr)
|
||||||
|
to_sign.extend(claim.serialized_no_signature)
|
||||||
|
to_sign.extend(binascii.unhexlify(cert_claim_id))
|
||||||
|
|
||||||
|
digest = self.HASHFUNC(to_sign).digest()
|
||||||
|
|
||||||
|
if not isinstance(self.private_key, ecdsa.SigningKey):
|
||||||
|
raise Exception("Not given a signing key")
|
||||||
|
sig_dict = {
|
||||||
|
"version": V_0_0_1,
|
||||||
|
"signatureType": self.CURVE_NAME,
|
||||||
|
"signature": self.private_key.sign_digest_deterministic(digest, hashfunc=self.HASHFUNC),
|
||||||
|
"certificateId": binascii.unhexlify(cert_claim_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = {
|
||||||
|
"version": V_0_0_1,
|
||||||
|
"stream": decode_b64_fields(claim.protobuf_dict)['stream'],
|
||||||
|
"publisherSignature": sig_dict
|
||||||
|
}
|
||||||
|
|
||||||
|
return Claim.load(msg)
|
||||||
|
|
||||||
|
|
||||||
|
class NIST256pSigner(NIST_ECDSASigner):
|
||||||
|
CURVE = ecdsa.NIST256p
|
||||||
|
CURVE_NAME = NIST256p
|
||||||
|
|
||||||
|
|
||||||
|
class NIST384pSigner(NIST_ECDSASigner):
|
||||||
|
CURVE = ecdsa.NIST384p
|
||||||
|
CURVE_NAME = NIST384p
|
||||||
|
HASHFUNC = hashlib.sha384
|
||||||
|
HASHFUNC_NAME = SHA384
|
||||||
|
|
||||||
|
|
||||||
|
class SECP256k1Signer(NIST_ECDSASigner):
|
||||||
|
CURVE = ecdsa.SECP256k1
|
||||||
|
CURVE_NAME = SECP256k1
|
||||||
|
|
||||||
|
|
||||||
|
def get_signer(curve):
|
||||||
|
if curve == NIST256p:
|
||||||
|
return NIST256pSigner
|
||||||
|
elif curve == NIST384p:
|
||||||
|
return NIST384pSigner
|
||||||
|
elif curve == SECP256k1:
|
||||||
|
return SECP256k1Signer
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown curve: %s" % str(curve))
|
171
lbrynet/schema/uri.py
Normal file
171
lbrynet/schema/uri.py
Normal file
|
@ -0,0 +1,171 @@
|
||||||
|
import re
|
||||||
|
from lbryschema.error import URIParseError
|
||||||
|
|
||||||
|
PROTOCOL = 'lbry://'
|
||||||
|
CHANNEL_CHAR = '@'
|
||||||
|
CLAIM_ID_CHAR = '#'
|
||||||
|
CLAIM_SEQUENCE_CHAR = ':'
|
||||||
|
BID_POSITION_CHAR = '$'
|
||||||
|
PATH_CHAR = '/'
|
||||||
|
QUERY_CHAR = '?'
|
||||||
|
|
||||||
|
CLAIM_ID_MAX_LENGTH = 40
|
||||||
|
CHANNEL_NAME_MIN_LENGTH = 1
|
||||||
|
|
||||||
|
|
||||||
|
class URI(object):
|
||||||
|
__slots__ = ['name', 'claim_sequence', 'bid_position', 'claim_id', 'path']
|
||||||
|
|
||||||
|
def __init__(self, name, claim_sequence=None, bid_position=None, claim_id=None, path=None):
|
||||||
|
if len([v for v in [claim_sequence, bid_position, claim_id] if v is not None]) > 1:
|
||||||
|
raise ValueError(
|
||||||
|
"Only one of these may be present at a time: claim_sequence, bid_position, claim_id"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.name = name
|
||||||
|
self.claim_sequence = claim_sequence
|
||||||
|
self.bid_position = bid_position
|
||||||
|
self.claim_id = claim_id
|
||||||
|
self.path = path
|
||||||
|
|
||||||
|
if self.path is not None and not self.is_channel:
|
||||||
|
raise ValueError("Content claims cannot have paths")
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.to_uri_string()
|
||||||
|
|
||||||
|
def __eq__(self, other):
|
||||||
|
for prop in self.__slots__:
|
||||||
|
if not hasattr(other, prop) or getattr(self, prop) != getattr(other, prop):
|
||||||
|
return False
|
||||||
|
return self.__class__ == other.__class__
|
||||||
|
|
||||||
|
@property
|
||||||
|
def is_channel(self):
|
||||||
|
return self.name.startswith(CHANNEL_CHAR)
|
||||||
|
|
||||||
|
def to_uri_string(self):
|
||||||
|
uri_string = PROTOCOL + "%s" % self.name
|
||||||
|
|
||||||
|
if self.claim_sequence is not None:
|
||||||
|
uri_string += CLAIM_SEQUENCE_CHAR + "%i" % self.claim_sequence
|
||||||
|
elif self.bid_position is not None:
|
||||||
|
uri_string += BID_POSITION_CHAR + "%i" % self.bid_position
|
||||||
|
elif self.claim_id is not None:
|
||||||
|
uri_string += CLAIM_ID_CHAR + "%s" % self.claim_id
|
||||||
|
|
||||||
|
if self.path is not None:
|
||||||
|
uri_string += PATH_CHAR + "%s" % self.path
|
||||||
|
|
||||||
|
return uri_string
|
||||||
|
|
||||||
|
def to_dict(self):
|
||||||
|
return {
|
||||||
|
"name": self.name,
|
||||||
|
'claim_sequence': self.claim_sequence,
|
||||||
|
'bid_position': self.bid_position,
|
||||||
|
'claim_id': self.claim_id,
|
||||||
|
'path': self.path,
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_uri_string(cls, uri_string):
|
||||||
|
"""
|
||||||
|
Parses LBRY uri into its components
|
||||||
|
|
||||||
|
:param uri_string: format - lbry://name:n$rank#id/path
|
||||||
|
optional modifiers:
|
||||||
|
claim_sequence (int): the nth claim to the name
|
||||||
|
bid_position (int): the bid queue position of the claim for the name
|
||||||
|
claim_id (str): the claim id for the claim
|
||||||
|
path (str): claim within a channel
|
||||||
|
:return: URI
|
||||||
|
"""
|
||||||
|
match = re.match(get_schema_regex(), uri_string)
|
||||||
|
|
||||||
|
if match is None:
|
||||||
|
raise URIParseError('Invalid URI')
|
||||||
|
|
||||||
|
if match.group('content_name') and match.group('path'):
|
||||||
|
raise URIParseError('Only channels may have paths')
|
||||||
|
|
||||||
|
return cls(
|
||||||
|
name=match.group("content_or_channel_name"),
|
||||||
|
claim_sequence=int(match.group("claim_sequence")) if match.group(
|
||||||
|
"claim_sequence") is not None else None,
|
||||||
|
bid_position=int(match.group("bid_position")) if match.group(
|
||||||
|
"bid_position") is not None else None,
|
||||||
|
claim_id=match.group("claim_id"),
|
||||||
|
path=match.group("path")
|
||||||
|
)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_dict(cls, uri_dict):
|
||||||
|
"""
|
||||||
|
Creates URI from dict
|
||||||
|
|
||||||
|
:return: URI
|
||||||
|
"""
|
||||||
|
return cls(**uri_dict)
|
||||||
|
|
||||||
|
|
||||||
|
def get_schema_regex():
|
||||||
|
def _named(name, regex):
|
||||||
|
return "(?P<" + name + ">" + regex + ")"
|
||||||
|
|
||||||
|
def _group(regex):
|
||||||
|
return "(?:" + regex + ")"
|
||||||
|
|
||||||
|
# TODO: regex should include the fact that content names cannot have paths
|
||||||
|
# right now this is only enforced in code, not in the regex
|
||||||
|
|
||||||
|
# Escape constants
|
||||||
|
claim_id_char = re.escape(CLAIM_ID_CHAR)
|
||||||
|
claim_sequence_char = re.escape(CLAIM_SEQUENCE_CHAR)
|
||||||
|
bid_position_char = re.escape(BID_POSITION_CHAR)
|
||||||
|
channel_char = re.escape(CHANNEL_CHAR)
|
||||||
|
path_char = re.escape(PATH_CHAR)
|
||||||
|
protocol = _named("protocol", re.escape(PROTOCOL))
|
||||||
|
|
||||||
|
# Define basic building blocks
|
||||||
|
valid_name_char = "[a-zA-Z0-9\-]" # these characters are the only valid name characters
|
||||||
|
name_content = valid_name_char + '+'
|
||||||
|
name_min_channel_length = valid_name_char + '{' + str(CHANNEL_NAME_MIN_LENGTH) + ',}'
|
||||||
|
|
||||||
|
positive_number = "[1-9][0-9]*"
|
||||||
|
number = '\-?' + positive_number
|
||||||
|
|
||||||
|
# Define URI components
|
||||||
|
content_name = _named("content_name", name_content)
|
||||||
|
channel_name = _named("channel_name", channel_char + name_min_channel_length)
|
||||||
|
content_or_channel_name = _named("content_or_channel_name", content_name + "|" + channel_name)
|
||||||
|
|
||||||
|
claim_id_piece = _named("claim_id", "[0-9a-f]{1," + str(CLAIM_ID_MAX_LENGTH) + "}")
|
||||||
|
claim_id = _group(claim_id_char + claim_id_piece)
|
||||||
|
|
||||||
|
bid_position_piece = _named("bid_position", number)
|
||||||
|
bid_position = _group(bid_position_char + bid_position_piece)
|
||||||
|
|
||||||
|
claim_sequence_piece = _named("claim_sequence", number)
|
||||||
|
claim_sequence = _group(claim_sequence_char + claim_sequence_piece)
|
||||||
|
|
||||||
|
modifier = _named("modifier", claim_id + "|" + bid_position + "|" + claim_sequence)
|
||||||
|
|
||||||
|
path_piece = _named("path", name_content)
|
||||||
|
path = _group(path_char + path_piece)
|
||||||
|
|
||||||
|
# Combine components
|
||||||
|
uri = _named("uri", (
|
||||||
|
'^' +
|
||||||
|
protocol + '?' +
|
||||||
|
content_or_channel_name +
|
||||||
|
modifier + '?' +
|
||||||
|
path + '?' +
|
||||||
|
'$'
|
||||||
|
))
|
||||||
|
|
||||||
|
return uri
|
||||||
|
|
||||||
|
|
||||||
|
def parse_lbry_uri(lbry_uri):
|
||||||
|
return URI.from_uri_string(lbry_uri)
|
136
lbrynet/schema/validator.py
Normal file
136
lbrynet/schema/validator.py
Normal file
|
@ -0,0 +1,136 @@
|
||||||
|
from string import hexdigits
|
||||||
|
import six
|
||||||
|
import ecdsa
|
||||||
|
import hashlib
|
||||||
|
import binascii
|
||||||
|
|
||||||
|
from cryptography.hazmat.primitives import serialization
|
||||||
|
from cryptography.hazmat.backends import default_backend
|
||||||
|
from cryptography.hazmat.primitives.serialization import load_der_public_key
|
||||||
|
from cryptography.hazmat.primitives import hashes
|
||||||
|
from cryptography.hazmat.primitives.asymmetric import ec
|
||||||
|
from cryptography.hazmat.primitives.asymmetric.utils import Prehashed
|
||||||
|
from cryptography.exceptions import InvalidSignature
|
||||||
|
from ecdsa.util import sigencode_der
|
||||||
|
|
||||||
|
from lbryschema.address import decode_address
|
||||||
|
from lbryschema.schema import NIST256p, NIST384p, SECP256k1, ECDSA_CURVES, CURVE_NAMES
|
||||||
|
|
||||||
|
|
||||||
|
def validate_claim_id(claim_id):
|
||||||
|
if not len(claim_id) == 40:
|
||||||
|
raise Exception("Incorrect claimid length: %i" % len(claim_id))
|
||||||
|
if isinstance(claim_id, six.binary_type):
|
||||||
|
claim_id = claim_id.decode('utf-8')
|
||||||
|
if set(claim_id).difference(hexdigits):
|
||||||
|
raise Exception("Claim id is not hex encoded")
|
||||||
|
|
||||||
|
|
||||||
|
class Validator(object):
|
||||||
|
CURVE_NAME = None
|
||||||
|
HASHFUNC = hashlib.sha256
|
||||||
|
|
||||||
|
def __init__(self, public_key, certificate_claim_id):
|
||||||
|
validate_claim_id(certificate_claim_id)
|
||||||
|
if CURVE_NAMES.get(get_key_type_from_dem(public_key)) != self.CURVE_NAME:
|
||||||
|
raise Exception("Curve mismatch")
|
||||||
|
self._public_key = public_key
|
||||||
|
self._certificate_claim_id = certificate_claim_id
|
||||||
|
|
||||||
|
@property
|
||||||
|
def public_key(self):
|
||||||
|
return self._public_key
|
||||||
|
|
||||||
|
@property
|
||||||
|
def certificate_claim_id(self):
|
||||||
|
return self._certificate_claim_id
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def signing_key_from_pem(cls, pem):
|
||||||
|
return ecdsa.SigningKey.from_pem(pem, hashfunc=cls.HASHFUNC)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def signing_key_from_der(cls, der):
|
||||||
|
return ecdsa.SigningKey.from_der(der, hashfunc=cls.HASHFUNC)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def load_from_certificate(cls, certificate_claim, certificate_claim_id):
|
||||||
|
certificate = certificate_claim.certificate
|
||||||
|
return cls(certificate.publicKey, certificate_claim_id)
|
||||||
|
|
||||||
|
def validate_signature(self, digest, signature):
|
||||||
|
public_key = load_der_public_key(self.public_key, default_backend())
|
||||||
|
if len(signature) == 64:
|
||||||
|
hash = hashes.SHA256()
|
||||||
|
elif len(signature) == 96:
|
||||||
|
hash = hashes.SHA384()
|
||||||
|
signature = binascii.hexlify(signature)
|
||||||
|
r = int(signature[:int(len(signature)/2)], 16)
|
||||||
|
s = int(signature[int(len(signature)/2):], 16)
|
||||||
|
encoded_sig = sigencode_der(r, s, len(signature)*4)
|
||||||
|
try:
|
||||||
|
public_key.verify(encoded_sig, digest, ec.ECDSA(Prehashed(hash)))
|
||||||
|
return True
|
||||||
|
except InvalidSignature:
|
||||||
|
# TODO Fixme. This is what is expected today on the outer calls. This should be implementation independent
|
||||||
|
# but requires changing everything calling that
|
||||||
|
from ecdsa import BadSignatureError
|
||||||
|
raise BadSignatureError
|
||||||
|
|
||||||
|
def validate_claim_signature(self, claim, claim_address):
|
||||||
|
decoded_address = decode_address(claim_address)
|
||||||
|
|
||||||
|
# extract and serialize the stream from the claim, then check the signature
|
||||||
|
signature = binascii.unhexlify(claim.signature)
|
||||||
|
|
||||||
|
if signature is None:
|
||||||
|
raise Exception("No signature to validate")
|
||||||
|
|
||||||
|
to_sign = bytearray()
|
||||||
|
to_sign.extend(decoded_address)
|
||||||
|
to_sign.extend(claim.serialized_no_signature)
|
||||||
|
to_sign.extend(binascii.unhexlify(self.certificate_claim_id))
|
||||||
|
|
||||||
|
return self.validate_signature(self.HASHFUNC(to_sign).digest(), signature)
|
||||||
|
|
||||||
|
def validate_private_key(self, private_key):
|
||||||
|
if not isinstance(private_key, ecdsa.SigningKey):
|
||||||
|
raise TypeError("Not given a signing key, given a %s" % str(type(private_key)))
|
||||||
|
return private_key.get_verifying_key().to_der() == self.public_key
|
||||||
|
|
||||||
|
|
||||||
|
class NIST256pValidator(Validator):
|
||||||
|
CURVE_NAME = NIST256p
|
||||||
|
HASHFUNC = hashlib.sha256
|
||||||
|
|
||||||
|
|
||||||
|
class NIST384pValidator(Validator):
|
||||||
|
CURVE_NAME = NIST384p
|
||||||
|
HASHFUNC = hashlib.sha384
|
||||||
|
|
||||||
|
|
||||||
|
class SECP256k1Validator(Validator):
|
||||||
|
CURVE_NAME = SECP256k1
|
||||||
|
HASHFUNC = hashlib.sha256
|
||||||
|
|
||||||
|
|
||||||
|
def get_validator(curve):
|
||||||
|
if curve == NIST256p:
|
||||||
|
return NIST256pValidator
|
||||||
|
elif curve == NIST384p:
|
||||||
|
return NIST384pValidator
|
||||||
|
elif curve == SECP256k1:
|
||||||
|
return SECP256k1Validator
|
||||||
|
else:
|
||||||
|
raise Exception("Unknown curve: %s" % str(curve))
|
||||||
|
|
||||||
|
|
||||||
|
def get_key_type_from_dem(pubkey_dem):
|
||||||
|
name = serialization.load_der_public_key(pubkey_dem, default_backend()).curve.name
|
||||||
|
if name == 'secp256k1':
|
||||||
|
return ECDSA_CURVES[SECP256k1]
|
||||||
|
elif name == 'secp256r1':
|
||||||
|
return ECDSA_CURVES[NIST256p]
|
||||||
|
elif name == 'secp384r1':
|
||||||
|
return ECDSA_CURVES[NIST384p]
|
||||||
|
raise Exception("unexpected curve: %s" % name)
|
Loading…
Add table
Add a link
Reference in a new issue