diff --git a/src/aleph/sdk/chains/common.py b/src/aleph/sdk/chains/common.py index 140f5c2d..8113bd3a 100644 --- a/src/aleph/sdk/chains/common.py +++ b/src/aleph/sdk/chains/common.py @@ -62,7 +62,6 @@ def _setup_sender(self, message: Dict) -> Dict: else: raise ValueError("Message sender does not match the account's public key.") - @abstractmethod async def sign_message(self, message: Dict) -> Dict: """ Returns a signed message from an Aleph message. @@ -72,19 +71,19 @@ async def sign_message(self, message: Dict) -> Dict: Dict: Signed message """ message = self._setup_sender(message) - sig = await self.sign_raw(get_verification_buffer(message)) - message["signature"] = sig.hex() + message["signature"] = await self.sign_raw(get_verification_buffer(message)) return message - - async def sign_raw(self, buffer: bytes) -> bytes: + + @abstractmethod + async def sign_raw(self, buffer: bytes) -> str: """ Returns a signed message from a raw buffer. Args: buffer: Buffer to sign Returns: - bytes: Signed buffer + str: Signature in preferred format """ - + raise NotImplementedError @abstractmethod def get_address(self) -> str: diff --git a/src/aleph/sdk/chains/cosmos.py b/src/aleph/sdk/chains/cosmos.py index c1e29d5b..7fadd133 100644 --- a/src/aleph/sdk/chains/cosmos.py +++ b/src/aleph/sdk/chains/cosmos.py @@ -51,20 +51,11 @@ def __init__(self, private_key=None, hrp=DEFAULT_HRP): async def sign_message(self, message): message = self._setup_sender(message) - verif = get_verification_string(message) - - privkey = ecdsa.SigningKey.from_string(self.private_key, curve=ecdsa.SECP256k1) - signature_compact = privkey.sign_deterministic( - verif.encode("utf-8"), - hashfunc=hashlib.sha256, - sigencode=ecdsa.util.sigencode_string_canonize, - ) - signature_base64_str = base64.b64encode(signature_compact).decode("utf-8") base64_pubkey = base64.b64encode(self.get_public_key().encode()).decode("utf-8") sig = { - "signature": signature_base64_str, + "signature": self.sign_raw(verif.encode("utf-8")), "pub_key": {"type": "tendermint/PubKeySecp256k1", "value": base64_pubkey}, "account_number": str(0), "sequence": str(0), @@ -72,6 +63,15 @@ async def sign_message(self, message): message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> str: + privkey = ecdsa.SigningKey.from_string(self.private_key, curve=ecdsa.SECP256k1) + signature_compact = privkey.sign_deterministic( + buffer, + hashfunc=hashlib.sha256, + sigencode=ecdsa.util.sigencode_string_canonize, + ) + return base64.b64encode(signature_compact).decode("utf-8") + def get_address(self) -> str: return privkey_to_address(self.private_key) diff --git a/src/aleph/sdk/chains/ethereum.py b/src/aleph/sdk/chains/ethereum.py index a6e516f6..40ee2003 100644 --- a/src/aleph/sdk/chains/ethereum.py +++ b/src/aleph/sdk/chains/ethereum.py @@ -1,5 +1,5 @@ from pathlib import Path -from typing import Dict, Optional, Union +from typing import Optional, Union from eth_account import Account from eth_account.messages import encode_defunct @@ -11,7 +11,6 @@ BaseAccount, get_fallback_private_key, get_public_key, - get_verification_buffer, ) @@ -23,12 +22,12 @@ class ETHAccount(BaseAccount): def __init__(self, private_key: bytes): self.private_key = private_key self._account = Account.from_key(self.private_key) - - async def sign_raw(self, buffer: bytes) -> bytes: + + async def sign_raw(self, buffer: bytes) -> str: """Sign a raw buffer.""" msghash = encode_defunct(text=buffer.decode("utf-8")) sig = self._account.sign_message(msghash) - return sig["signature"] + return sig["signature"].hex() def get_address(self) -> str: return self._account.address diff --git a/src/aleph/sdk/chains/nuls1.py b/src/aleph/sdk/chains/nuls1.py index c5629fb7..12ffaa37 100644 --- a/src/aleph/sdk/chains/nuls1.py +++ b/src/aleph/sdk/chains/nuls1.py @@ -315,6 +315,10 @@ async def sign_message(self, message): message["signature"] = sig.serialize().hex() return message + async def sign_raw(self, buffer: bytes) -> str: + sig = NulsSignature.sign_data(self.private_key, buffer) + return sig.serialize().hex() + def get_address(self): return address_from_hash( public_key_to_hash(self.get_public_key(), chain_id=self.chain_id) diff --git a/src/aleph/sdk/chains/nuls2.py b/src/aleph/sdk/chains/nuls2.py index ec1a367d..7618a02a 100644 --- a/src/aleph/sdk/chains/nuls2.py +++ b/src/aleph/sdk/chains/nuls2.py @@ -12,7 +12,6 @@ BaseAccount, get_fallback_private_key, get_public_key, - get_verification_buffer, ) @@ -37,16 +36,9 @@ def __init__(self, private_key=None, chain_id=1, prefix=None): else: self.prefix = prefix - async def sign_message(self, message): - # sig = NulsSignature.sign_message(self.private_key, - # get_verification_buffer(message)) - message = self._setup_sender(message) - - sig = sign_recoverable_message( - self.private_key, get_verification_buffer(message) - ) - message["signature"] = base64.b64encode(sig).decode() - return message + async def sign_raw(self, buffer: bytes) -> str: + sig = sign_recoverable_message(self.private_key, buffer) + return base64.b64encode(sig).decode() def get_address(self): return address_from_hash( diff --git a/src/aleph/sdk/chains/remote.py b/src/aleph/sdk/chains/remote.py index 8b27e615..250fcc62 100644 --- a/src/aleph/sdk/chains/remote.py +++ b/src/aleph/sdk/chains/remote.py @@ -77,6 +77,9 @@ async def sign_message(self, message: Dict) -> Dict: response.raise_for_status() return await response.json() + async def sign_raw(self, buffer: bytes) -> str: + raise NotImplementedError() + def get_address(self) -> str: return self._address diff --git a/src/aleph/sdk/chains/sol.py b/src/aleph/sdk/chains/sol.py index cc5a2cfa..96e4b2bf 100644 --- a/src/aleph/sdk/chains/sol.py +++ b/src/aleph/sdk/chains/sol.py @@ -32,15 +32,15 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_address(), - "signature": encode(self.sign_raw(verif)), + "signature": self.sign_raw(verif), } message["signature"] = json.dumps(sig) return message - async def sign_raw(self, buffer: bytes) -> bytes: + async def sign_raw(self, buffer: bytes) -> str: """Sign a raw buffer.""" sig = self._signing_key.sign(buffer) - return sig.signature + return encode(sig.signature) def get_address(self) -> str: return encode(self._signing_key.verify_key) diff --git a/src/aleph/sdk/chains/substrate.py b/src/aleph/sdk/chains/substrate.py index cc73a8b0..0f49c70e 100644 --- a/src/aleph/sdk/chains/substrate.py +++ b/src/aleph/sdk/chains/substrate.py @@ -25,6 +25,10 @@ async def sign_message(self, message): message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> str: + sig = self._account.sign(buffer) + return sig.hex() + def get_address(self): return self._account.ss58_address diff --git a/src/aleph/sdk/chains/tezos.py b/src/aleph/sdk/chains/tezos.py index af870c35..d31e2f8c 100644 --- a/src/aleph/sdk/chains/tezos.py +++ b/src/aleph/sdk/chains/tezos.py @@ -27,12 +27,15 @@ async def sign_message(self, message: Dict) -> Dict: verif = get_verification_buffer(message) sig = { "publicKey": self.get_public_key(), - "signature": self._account.sign(verif), + "signature": self.sign_raw(verif), } message["signature"] = json.dumps(sig) return message + async def sign_raw(self, buffer: bytes) -> str: + return self._account.sign(buffer) + def get_address(self) -> str: return self._account.public_key_hash() diff --git a/src/aleph/sdk/client.py b/src/aleph/sdk/client.py index 430ace1f..d48fded9 100644 --- a/src/aleph/sdk/client.py +++ b/src/aleph/sdk/client.py @@ -6,6 +6,7 @@ import threading import time from datetime import datetime +from io import BytesIO from pathlib import Path from typing import ( Any, @@ -23,7 +24,6 @@ TypeVar, Union, ) -from io import BytesIO import aiohttp from aleph_message.models import ( @@ -45,17 +45,18 @@ ) from aleph_message.models.execution.base import Encoding from aleph_message.status import MessageStatus -from pydantic import ValidationError, BaseModel +from pydantic import ValidationError from aleph.sdk.types import Account, GenericMessage, StorageEnum -from aleph.sdk.utils import copy_async_readable_to_buffer, Writable, AsyncReadable +from aleph.sdk.utils import Writable, copy_async_readable_to_buffer + from .conf import settings from .exceptions import ( BroadcastError, + FileTooLarge, InvalidMessageError, MessageNotFoundError, MultipleMessagesError, - FileTooLarge, ) from .models import MessagesResponse from .utils import check_unix_socket_valid, get_message_type_value @@ -237,12 +238,24 @@ def download_file_ipfs(self, file_hash: str) -> bytes: self.async_session.download_file_ipfs, file_hash=file_hash, ) - def download_file_to_buffer(self, file_hash: str, output_buffer: Writable[bytes]) -> bytes: - return self._wrap(self.async_session.download_file_to_buffer, file_hash=file_hash, output_buffer=output_buffer) - def download_file_ipfs_to_buffer(self, file_hash: str, output_buffer: Writable[bytes]) -> bytes: - return self._wrap(self.async_session.download_file_ipfs_to_buffer, file_hash=file_hash, output_buffer=output_buffer) + def download_file_to_buffer( + self, file_hash: str, output_buffer: Writable[bytes] + ) -> bytes: + return self._wrap( + self.async_session.download_file_to_buffer, + file_hash=file_hash, + output_buffer=output_buffer, + ) + def download_file_ipfs_to_buffer( + self, file_hash: str, output_buffer: Writable[bytes] + ) -> bytes: + return self._wrap( + self.async_session.download_file_ipfs_to_buffer, + file_hash=file_hash, + output_buffer=output_buffer, + ) def watch_messages( self, diff --git a/src/aleph/sdk/utils.py b/src/aleph/sdk/utils.py index 91c45c26..be56cc2c 100644 --- a/src/aleph/sdk/utils.py +++ b/src/aleph/sdk/utils.py @@ -4,7 +4,7 @@ from enum import Enum from pathlib import Path from shutil import make_archive -from typing import Tuple, Type, Union +from typing import Protocol, Tuple, Type, TypeVar, Union from zipfile import BadZipFile, ZipFile from aleph_message.models import MessageType @@ -13,13 +13,6 @@ from aleph.sdk.conf import settings from aleph.sdk.types import GenericMessage -from typing import ( - Tuple, - Type, - TypeVar, - Protocol, -) - logger = logging.getLogger(__name__) try: @@ -54,7 +47,7 @@ def create_archive(path: Path) -> Tuple[Path, Encoding]: return archive_path, Encoding.zip elif os.path.isfile(path): if path.suffix == ".squashfs" or ( - magic and magic.from_file(path).startswith("Squashfs filesystem") + magic and magic.from_file(path).startswith("Squashfs filesystem") ): return path, Encoding.squashfs else: @@ -101,7 +94,7 @@ def write(self, buffer: U) -> int: async def copy_async_readable_to_buffer( - readable: AsyncReadable[T], buffer: Writable[T], chunk_size: int + readable: AsyncReadable[T], buffer: Writable[T], chunk_size: int ): while True: chunk = await readable.read(chunk_size) diff --git a/tests/unit/test_download.py b/tests/unit/test_download.py index 219ccde5..df14cce9 100644 --- a/tests/unit/test_download.py +++ b/tests/unit/test_download.py @@ -1,4 +1,5 @@ import pytest + from aleph.sdk import AlephClient from aleph.sdk.conf import settings as sdk_settings