2019-04-07 20:37:04 +02:00
|
|
|
import logging
|
2019-06-13 02:20:30 +02:00
|
|
|
import time
|
|
|
|
import hashlib
|
|
|
|
import binascii
|
2019-05-24 18:12:27 +02:00
|
|
|
|
2019-06-13 02:20:30 +02:00
|
|
|
import ecdsa
|
2019-12-31 20:52:57 +01:00
|
|
|
from lbry import utils
|
|
|
|
from lbry.crypto.hash import sha256
|
2019-06-21 02:55:47 +02:00
|
|
|
from lbry.wallet.transaction import Output
|
2019-04-07 20:37:04 +02:00
|
|
|
|
|
|
|
log = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
2019-06-13 02:20:30 +02:00
|
|
|
def get_encoded_signature(signature):
|
2020-01-03 07:39:34 +01:00
|
|
|
signature = signature.encode() if isinstance(signature, str) else signature
|
2019-06-13 02:20:30 +02:00
|
|
|
r = int(signature[:int(len(signature) / 2)], 16)
|
|
|
|
s = int(signature[int(len(signature) / 2):], 16)
|
|
|
|
return ecdsa.util.sigencode_der(r, s, len(signature) * 4)
|
|
|
|
|
|
|
|
|
2019-07-25 03:18:21 +02:00
|
|
|
def cid2hash(claim_id: str) -> bytes:
|
|
|
|
return binascii.unhexlify(claim_id.encode())[::-1]
|
|
|
|
|
|
|
|
|
2020-10-08 21:48:37 +02:00
|
|
|
def is_comment_signed_by_channel(comment: dict, channel: Output, sign_comment_id=False):
|
2020-01-03 07:39:34 +01:00
|
|
|
if isinstance(channel, Output):
|
2019-07-02 17:58:24 +02:00
|
|
|
try:
|
2020-10-08 21:48:37 +02:00
|
|
|
signing_field = comment['comment_id'] if sign_comment_id else comment['comment']
|
2020-12-24 07:06:57 +01:00
|
|
|
return verify(channel, signing_field.encode(), comment, cid2hash(comment['channel_id']))
|
2019-07-02 17:58:24 +02:00
|
|
|
except KeyError:
|
|
|
|
pass
|
2019-06-13 02:20:30 +02:00
|
|
|
return False
|
|
|
|
|
|
|
|
|
2020-12-24 07:06:57 +01:00
|
|
|
def verify(channel, data, signature, channel_hash=None):
|
2020-12-24 06:55:47 +01:00
|
|
|
pieces = [
|
|
|
|
signature['signing_ts'].encode(),
|
2020-12-24 07:06:57 +01:00
|
|
|
channel_hash or channel.claim_hash,
|
2020-12-24 06:55:47 +01:00
|
|
|
data
|
|
|
|
]
|
|
|
|
return Output.is_signature_valid(
|
|
|
|
get_encoded_signature(signature['signature']),
|
|
|
|
sha256(b''.join(pieces)),
|
|
|
|
channel.claim.channel.public_key_bytes
|
|
|
|
)
|
|
|
|
|
|
|
|
|
2020-10-08 21:48:37 +02:00
|
|
|
def sign_comment(comment: dict, channel: Output, sign_comment_id=False):
|
|
|
|
signing_field = comment['comment_id'] if sign_comment_id else comment['comment']
|
2020-12-24 06:55:47 +01:00
|
|
|
comment.update(sign(channel, signing_field.encode()))
|
|
|
|
|
|
|
|
|
|
|
|
def sign(channel, data):
|
|
|
|
timestamp = str(int(time.time()))
|
|
|
|
pieces = [timestamp.encode(), channel.claim_hash, data]
|
2019-06-13 02:20:30 +02:00
|
|
|
digest = sha256(b''.join(pieces))
|
|
|
|
signature = channel.private_key.sign_digest_deterministic(digest, hashfunc=hashlib.sha256)
|
2020-12-24 06:55:47 +01:00
|
|
|
return {
|
2019-07-19 06:29:21 +02:00
|
|
|
'signature': binascii.hexlify(signature).decode(),
|
2019-07-25 03:18:21 +02:00
|
|
|
'signing_ts': timestamp
|
2020-12-24 06:55:47 +01:00
|
|
|
}
|
|
|
|
|
2019-04-07 20:37:04 +02:00
|
|
|
|
2020-09-23 22:43:28 +02:00
|
|
|
def sign_reaction(reaction: dict, channel: Output):
|
|
|
|
signing_field = reaction['channel_name']
|
2020-12-24 06:55:47 +01:00
|
|
|
reaction.update(sign(channel, signing_field.encode()))
|
|
|
|
|
2019-04-07 20:37:04 +02:00
|
|
|
|
2019-07-19 06:29:21 +02:00
|
|
|
async def jsonrpc_post(url: str, method: str, params: dict = None, **kwargs) -> any:
|
2019-07-24 21:51:14 +02:00
|
|
|
params = params or {}
|
2019-07-19 06:29:21 +02:00
|
|
|
params.update(kwargs)
|
2020-09-23 22:43:28 +02:00
|
|
|
json_body = {'jsonrpc': '2.0', 'id': 1, 'method': method, 'params': params}
|
2019-08-26 18:06:18 +02:00
|
|
|
async with utils.aiohttp_request('POST', url, json=json_body) as response:
|
2019-05-24 18:12:27 +02:00
|
|
|
try:
|
|
|
|
result = await response.json()
|
|
|
|
return result['result'] if 'result' in result else result
|
2019-07-03 00:38:43 +02:00
|
|
|
except Exception as cte:
|
2019-07-19 06:29:21 +02:00
|
|
|
log.exception('Unable to decode response from server: %s', cte)
|
2019-05-24 18:12:27 +02:00
|
|
|
return await response.text()
|