From 45bf6c3bf3097f1e06572ec530f7740b4f3d1a6d Mon Sep 17 00:00:00 2001 From: Cristian Vicas Date: Tue, 31 Aug 2021 14:54:04 +0300 Subject: [PATCH] Drop comment_* apis. Refactored dangling functions. Added unit test. --- lbry/extras/daemon/comment_client.py | 41 ------------------- lbry/extras/daemon/daemon.py | 8 +++- lbry/wallet/transaction.py | 6 +++ .../blockchain/test_claim_commands.py | 25 +++++++++-- tests/unit/wallet/test_schema_signing.py | 21 +++++++++- 5 files changed, 53 insertions(+), 48 deletions(-) delete mode 100644 lbry/extras/daemon/comment_client.py diff --git a/lbry/extras/daemon/comment_client.py b/lbry/extras/daemon/comment_client.py deleted file mode 100644 index ec4a76192..000000000 --- a/lbry/extras/daemon/comment_client.py +++ /dev/null @@ -1,41 +0,0 @@ -import logging -import time -import hashlib -import binascii - -import ecdsa -from lbry.crypto.hash import sha256 -from lbry.wallet.transaction import Output - -log = logging.getLogger(__name__) - - -def get_encoded_signature(signature): - signature = signature.encode() if isinstance(signature, str) else signature - 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) - - -def verify(channel, data, signature, channel_hash=None): - pieces = [ - signature['signing_ts'].encode(), - channel_hash or channel.claim_hash, - data - ] - return Output.is_signature_valid( - get_encoded_signature(signature['signature']), - sha256(b''.join(pieces)), - channel.claim.channel.public_key_bytes - ) - - -def sign(channel, data): - timestamp = str(int(time.time())) - pieces = [timestamp.encode(), channel.claim_hash, data] - digest = sha256(b''.join(pieces)) - signature = channel.private_key.sign_digest_deterministic(digest, hashfunc=hashlib.sha256) - return { - 'signature': binascii.hexlify(signature).decode(), - 'signing_ts': timestamp - } diff --git a/lbry/extras/daemon/daemon.py b/lbry/extras/daemon/daemon.py index 2ea85c84b..427c2a4c5 100644 --- a/lbry/extras/daemon/daemon.py +++ b/lbry/extras/daemon/daemon.py @@ -46,7 +46,6 @@ from lbry.extras.daemon.components import EXCHANGE_RATE_MANAGER_COMPONENT, UPNP_ from lbry.extras.daemon.componentmanager import RequiredCondition from lbry.extras.daemon.componentmanager import ComponentManager from lbry.extras.daemon.json_response_encoder import JSONResponseEncoder -from lbry.extras.daemon import comment_client from lbry.extras.daemon.undecorated import undecorated from lbry.extras.daemon.security import ensure_request_allowed from lbry.file_analysis import VideoFileAnalyzer @@ -2837,7 +2836,12 @@ class Daemon(metaclass=JSONRPCServerType): signing_channel = await self.get_channel_or_error( wallet, channel_account_id, channel_id, channel_name, for_signing=True ) - return comment_client.sign(signing_channel, unhexlify(hexdata)) + timestamp = str(int(time.time())) + signature = signing_channel.sign_data(unhexlify(hexdata), timestamp) + return { + 'signature': signature, + 'signing_ts': timestamp + } @requires(WALLET_COMPONENT) async def jsonrpc_channel_abandon( diff --git a/lbry/wallet/transaction.py b/lbry/wallet/transaction.py index 01948ceea..fd8ad1961 100644 --- a/lbry/wallet/transaction.py +++ b/lbry/wallet/transaction.py @@ -459,6 +459,12 @@ class Output(InputOutput): self.signable.signature = channel.private_key.sign_digest_deterministic(digest, hashfunc=hashlib.sha256) self.script.generate() + def sign_data(self, data:bytes, timestamp:str) -> str: + pieces = [timestamp.encode(), self.claim_hash, data] + digest = sha256(b''.join(pieces)) + signature = self.private_key.sign_digest_deterministic(digest, hashfunc=hashlib.sha256) + return hexlify(signature).decode() + def clear_signature(self): self.channel = None self.signable.clear_signature() diff --git a/tests/integration/blockchain/test_claim_commands.py b/tests/integration/blockchain/test_claim_commands.py index 6474cc5cb..2836f7671 100644 --- a/tests/integration/blockchain/test_claim_commands.py +++ b/tests/integration/blockchain/test_claim_commands.py @@ -5,19 +5,38 @@ import asyncio from binascii import unhexlify from unittest import skip from urllib.request import urlopen +import ecdsa from lbry.error import InsufficientFundsError -from lbry.extras.daemon.comment_client import verify from lbry.extras.daemon.daemon import DEFAULT_PAGE_SIZE from lbry.testcase import CommandTestCase from lbry.wallet.orchstr8.node import SPVNode -from lbry.wallet.transaction import Transaction +from lbry.wallet.transaction import Transaction, Output from lbry.wallet.util import satoshis_to_coins as lbc - +from lbry.crypto.hash import sha256 log = logging.getLogger(__name__) +def get_encoded_signature(signature): + signature = signature.encode() if isinstance(signature, str) else signature + 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) + + +def verify(channel, data, signature, channel_hash=None): + pieces = [ + signature['signing_ts'].encode(), + channel_hash or channel.claim_hash, + data + ] + return Output.is_signature_valid( + get_encoded_signature(signature['signature']), + sha256(b''.join(pieces)), + channel.claim.channel.public_key_bytes + ) + class ClaimTestCase(CommandTestCase): diff --git a/tests/unit/wallet/test_schema_signing.py b/tests/unit/wallet/test_schema_signing.py index 08b61ce9d..7545bb8b6 100644 --- a/tests/unit/wallet/test_schema_signing.py +++ b/tests/unit/wallet/test_schema_signing.py @@ -2,10 +2,9 @@ from binascii import unhexlify from lbry.testcase import AsyncioTestCase from lbry.wallet.constants import CENT, NULL_HASH32 - from lbry.wallet import Ledger, Database, Headers, Transaction, Input, Output from lbry.schema.claim import Claim - +from lbry.crypto.hash import sha256 def get_output(amount=CENT, pubkey_hash=NULL_HASH32): return Transaction() \ @@ -114,3 +113,21 @@ class TestValidatingOldSignatures(AsyncioTestCase): }) self.assertTrue(stream.is_signed_by(channel, ledger)) + + +class TestValidateSignContent(AsyncioTestCase): + + async def test_sign_some_content(self): + some_content = "MEANINGLESS CONTENT AEE3353320".encode() + timestamp_str = "1630564175" + channel = await get_channel() + stream = get_stream() + signature = channel.sign_data(some_content, timestamp_str) + stream.signable.signature = unhexlify(signature.encode()) + encoded_signature = stream.get_encoded_signature() + pieces = [timestamp_str.encode(), channel.claim_hash, some_content] + self.assertTrue(Output.is_signature_valid( + encoded_signature, + sha256(b''.join(pieces)), + channel.claim.channel.public_key_bytes + ))