forked from LBRYCommunity/lbry-sdk
move lbryschema/lbryschema into lbrynet/schema
This commit is contained in:
parent
d12b6cddb3
commit
2dcebe48b7
42 changed files with 3892 additions and 0 deletions
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…
Reference in a new issue