Skip to content
Merged

ruff #45

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .git-blame-ignore-revs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
db5ce2efda477bdf9042832e41fa4eb3ce530266
3 changes: 1 addition & 2 deletions .github/workflows/python_client_checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,7 @@ jobs:
name: Call Ledger Python linters
uses: LedgerHQ/ledger-app-workflows/.github/workflows/reusable_python_checks.yml@v1
with:
run_linter: pylint
run_type_check: true
src_directory: application_client
setup_directory: tests
req_directory: tests
req_directory: tests
134 changes: 67 additions & 67 deletions tests/application_client/aptos_command_sender.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,119 +10,119 @@

CLA: int = 0x5B


class P1(IntEnum):
# Parameter 1 for first APDU number.
P1_START = 0x00
# Parameter 1 for maximum APDU number.
P1_MAX = 0x03
P1_MAX = 0x03
# Parameter 1 for screen confirmation for GET_PUBLIC_KEY.
P1_CONFIRM = 0x01


class P2(IntEnum):
# Parameter 2 for last APDU to receive.
P2_LAST = 0x00
# Parameter 2 for more APDU to receive.
P2_MORE = 0x80


class InsType(IntEnum):
GET_VERSION = 0x03
GET_APP_NAME = 0x04
GET_VERSION = 0x03
GET_APP_NAME = 0x04
GET_PUBLIC_KEY = 0x05
SIGN_TX = 0x06
SIGN_TX = 0x06


class Errors(IntEnum):
SW_DENY = 0x6985
SW_WRONG_P1P2 = 0x6A86
SW_WRONG_DATA_LENGTH = 0x6A87
SW_INS_NOT_SUPPORTED = 0x6D00
SW_CLA_NOT_SUPPORTED = 0x6E00
SW_WRONG_RESPONSE_LENGTH = 0xB000
SW_DENY = 0x6985
SW_WRONG_P1P2 = 0x6A86
SW_WRONG_DATA_LENGTH = 0x6A87
SW_INS_NOT_SUPPORTED = 0x6D00
SW_CLA_NOT_SUPPORTED = 0x6E00
SW_WRONG_RESPONSE_LENGTH = 0xB000
SW_DISPLAY_BIP32_PATH_FAIL = 0xB001
SW_DISPLAY_ADDRESS_FAIL = 0xB002
SW_DISPLAY_AMOUNT_FAIL = 0xB003
SW_WRONG_TX_LENGTH = 0xB004
SW_TX_PARSING_FAIL = 0xB005
SW_GET_PUB_KEY_FAIL = 0xB006
SW_BAD_STATE = 0xB007
SW_SIGNATURE_FAIL = 0xB008
SW_DISPLAY_GAS_FEE_FAIL = 0xB009
SW_SWAP_CHECKING_FAIL = 0xB00A
SW_DISPLAY_ADDRESS_FAIL = 0xB002
SW_DISPLAY_AMOUNT_FAIL = 0xB003
SW_WRONG_TX_LENGTH = 0xB004
SW_TX_PARSING_FAIL = 0xB005
SW_GET_PUB_KEY_FAIL = 0xB006
SW_BAD_STATE = 0xB007
SW_SIGNATURE_FAIL = 0xB008
SW_DISPLAY_GAS_FEE_FAIL = 0xB009
SW_SWAP_CHECKING_FAIL = 0xB00A


def split_message(message: bytes, max_size: int) -> List[bytes]:
return [message[x:x + max_size] for x in range(0, len(message), max_size)]
return [message[x : x + max_size] for x in range(0, len(message), max_size)]


class AptosCommandSender:
def __init__(self, backend: BackendInterface) -> None:
self.backend = backend


def get_app_and_version(self) -> RAPDU:
return self.backend.exchange(cla=0xB0, # specific CLA for BOLOS
ins=0x01, # specific INS for get_app_and_version
p1=P1.P1_START,
p2=P2.P2_LAST,
data=b"")

return self.backend.exchange(
cla=0xB0, # specific CLA for BOLOS
ins=0x01, # specific INS for get_app_and_version
p1=P1.P1_START,
p2=P2.P2_LAST,
data=b"",
)

def get_version(self) -> RAPDU:
return self.backend.exchange(cla=CLA,
ins=InsType.GET_VERSION,
p1=P1.P1_START,
p2=P2.P2_LAST,
data=b"")

return self.backend.exchange(
cla=CLA, ins=InsType.GET_VERSION, p1=P1.P1_START, p2=P2.P2_LAST, data=b""
)

def get_app_name(self) -> RAPDU:
return self.backend.exchange(cla=CLA,
ins=InsType.GET_APP_NAME,
p1=P1.P1_START,
p2=P2.P2_LAST,
data=b"")

return self.backend.exchange(
cla=CLA, ins=InsType.GET_APP_NAME, p1=P1.P1_START, p2=P2.P2_LAST, data=b""
)

def get_public_key(self, path: str) -> RAPDU:
return self.backend.exchange(cla=CLA,
ins=InsType.GET_PUBLIC_KEY,
p1=P1.P1_START,
p2=P2.P2_LAST,
data=pack_derivation_path(path))

return self.backend.exchange(
cla=CLA,
ins=InsType.GET_PUBLIC_KEY,
p1=P1.P1_START,
p2=P2.P2_LAST,
data=pack_derivation_path(path),
)

@contextmanager
def get_public_key_with_confirmation(self, path: str) -> Generator[None, None, None]:
with self.backend.exchange_async(cla=CLA,
ins=InsType.GET_PUBLIC_KEY,
p1=P1.P1_CONFIRM,
p2=P2.P2_LAST,
data=pack_derivation_path(path)) as response:
def get_public_key_with_confirmation(
self, path: str
) -> Generator[None, None, None]:
with self.backend.exchange_async(
cla=CLA,
ins=InsType.GET_PUBLIC_KEY,
p1=P1.P1_CONFIRM,
p2=P2.P2_LAST,
data=pack_derivation_path(path),
) as response:
yield response


@contextmanager
def sign_tx(self, path: str, transaction: bytes) -> Generator[None, None, None]:
self.backend.exchange(cla=CLA,
ins=InsType.SIGN_TX,
p1=P1.P1_START,
p2=P2.P2_MORE,
data=pack_derivation_path(path))
self.backend.exchange(
cla=CLA,
ins=InsType.SIGN_TX,
p1=P1.P1_START,
p2=P2.P2_MORE,
data=pack_derivation_path(path),
)
messages = split_message(transaction, MAX_APDU_LEN)
idx: int = P1.P1_START + 1

for msg in messages[:-1]:
self.backend.exchange(cla=CLA,
ins=InsType.SIGN_TX,
p1=idx,
p2=P2.P2_MORE,
data=msg)
self.backend.exchange(
cla=CLA, ins=InsType.SIGN_TX, p1=idx, p2=P2.P2_MORE, data=msg
)
idx += 1

with self.backend.exchange_async(cla=CLA,
ins=InsType.SIGN_TX,
p1=idx,
p2=P2.P2_LAST,
data=messages[-1]) as response:
with self.backend.exchange_async(
cla=CLA, ins=InsType.SIGN_TX, p1=idx, p2=P2.P2_LAST, data=messages[-1]
) as response:
yield response

def get_async_response(self) -> Optional[RAPDU]:
Expand Down
15 changes: 11 additions & 4 deletions tests/application_client/aptos_response_unpacker.py
Original file line number Diff line number Diff line change
@@ -1,20 +1,24 @@
from typing import Tuple
from struct import unpack


# remainder, data_len, data
def pop_sized_buf_from_buffer(buffer:bytes, size:int) -> Tuple[bytes, bytes]:
def pop_sized_buf_from_buffer(buffer: bytes, size: int) -> Tuple[bytes, bytes]:
return buffer[size:], buffer[0:size]


# remainder, data_len, data
def pop_size_prefixed_buf_from_buf(buffer:bytes) -> Tuple[bytes, int, bytes]:
def pop_size_prefixed_buf_from_buf(buffer: bytes) -> Tuple[bytes, int, bytes]:
data_len = buffer[0]
return buffer[1+data_len:], data_len, buffer[1:data_len+1]
return buffer[1 + data_len :], data_len, buffer[1 : data_len + 1]


# Unpack from response:
# response = app_name (var)
def unpack_get_app_name_response(response: bytes) -> str:
return response.decode("ascii")


# Unpack from response:
# response = MAJOR (1)
# MINOR (1)
Expand All @@ -24,6 +28,7 @@ def unpack_get_version_response(response: bytes) -> Tuple[int, int, int]:
major, minor, patch = unpack("BBB", response)
return (major, minor, patch)


# Unpack from response:
# response = format_id (1)
# app_name_raw_len (1)
Expand All @@ -42,6 +47,7 @@ def unpack_get_app_and_version_response(response: bytes) -> Tuple[str, str]:

return app_name_raw.decode("ascii"), version_raw.decode("ascii")


# Unpack from response:
# response = pub_key_len (1)
# pub_key (var)
Expand All @@ -57,6 +63,7 @@ def unpack_get_public_key_response(response: bytes) -> Tuple[int, bytes, int, by

return pub_key_len, pub_key, chain_code_len, chain_code


# Unpack from response:
# response = der_sig_len (1)
# der_sig (var)
Expand All @@ -67,4 +74,4 @@ def unpack_sign_tx_response(response: bytes) -> Tuple[int, bytes, int]:

assert len(response) == 0

return sig_len, sig, int.from_bytes(v, byteorder='big')
return sig_len, sig, int.from_bytes(v, byteorder="big")
21 changes: 10 additions & 11 deletions tests/application_client/aptos_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,28 @@
from typing import Optional, Literal


UINT64_MAX: int = 2**64-1
UINT32_MAX: int = 2**32-1
UINT16_MAX: int = 2**16-1
UINT64_MAX: int = 2**64 - 1
UINT32_MAX: int = 2**32 - 1
UINT16_MAX: int = 2**16 - 1


def write_varint(n: int) -> bytes:
if n < 0xFC:
return n.to_bytes(1, byteorder="little")

if n <= UINT16_MAX:
return b"\xFD" + n.to_bytes(2, byteorder="little")
return b"\xfd" + n.to_bytes(2, byteorder="little")

if n <= UINT32_MAX:
return b"\xFE" + n.to_bytes(4, byteorder="little")
return b"\xfe" + n.to_bytes(4, byteorder="little")

if n <= UINT64_MAX:
return b"\xFF" + n.to_bytes(8, byteorder="little")
return b"\xff" + n.to_bytes(8, byteorder="little")

raise ValueError(f"Can't write to varint: '{n}'!")


def read_varint(buf: BytesIO,
prefix: Optional[bytes] = None) -> int:
def read_varint(buf: BytesIO, prefix: Optional[bytes] = None) -> int:
b: bytes = prefix if prefix else buf.read(1)

if not b:
Expand All @@ -49,9 +48,9 @@ def read(buf: BytesIO, size: int) -> bytes:
return b


def read_uint(buf: BytesIO,
bit_len: int,
byteorder: Literal['big', 'little'] = 'little') -> int:
def read_uint(
buf: BytesIO, bit_len: int, byteorder: Literal["big", "little"] = "little"
) -> int:
size: int = bit_len // 8
b: bytes = buf.read(size)

Expand Down
14 changes: 1 addition & 13 deletions tests/application_client/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,18 +1,6 @@
[tool:pytest]
addopts = --strict-markers

[pylint]
disable = C0114, # missing-module-docstring
C0115, # missing-class-docstring
C0116, # missing-function-docstring
C0103, # invalid-name
R0801, # duplicate-code
R0913, # too-many-arguments
R0917 # too-many-positional-arguments

max-line-length=120
extension-pkg-whitelist=hid

[pycodestyle]
max-line-length = 100

Expand All @@ -23,4 +11,4 @@ ignore_missing_imports = True
ignore_missing_imports = True

[mypy-ledgered.*]
ignore_missing_imports = True
ignore_missing_imports = True
4 changes: 1 addition & 3 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
from ragger.conftest import configuration

###########################
### CONFIGURATION START ###
###########################
Expand All @@ -12,4 +10,4 @@
#########################

# Pull all features from the base ragger conftest using the overridden configuration
pytest_plugins = ("ragger.conftest.base_conftest", )
pytest_plugins = ("ragger.conftest.base_conftest",)
10 changes: 0 additions & 10 deletions tests/setup.cfg
Original file line number Diff line number Diff line change
@@ -1,16 +1,6 @@
[tool:pytest]
addopts = --strict-markers

[pylint]
disable = C0114, # missing-module-docstring
C0115, # missing-class-docstring
C0116, # missing-function-docstring
C0103, # invalid-name
R0801, # duplicate-code
R0913 # too-many-arguments
max-line-length=100
extension-pkg-whitelist=hid

[pycodestyle]
max-line-length = 100

Expand Down
12 changes: 8 additions & 4 deletions tests/test_app_mainmenu.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def test_app_mainmenu(firmware, navigator, test_name):
instructions = [
NavInsID.RIGHT_CLICK,
NavInsID.RIGHT_CLICK,
NavInsID.RIGHT_CLICK
NavInsID.RIGHT_CLICK,
]
else:
num_info_pages = 2 if firmware.device == "flex" else 1
Expand All @@ -21,7 +21,11 @@ def test_app_mainmenu(firmware, navigator, test_name):
NavIns(NavInsID.TOUCH, (200, 113)),
*([NavInsID.USE_CASE_SETTINGS_NEXT] * num_info_pages),
NavInsID.USE_CASE_SETTINGS_PREVIOUS,
NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT
NavInsID.USE_CASE_SETTINGS_MULTI_PAGE_EXIT,
]
navigator.navigate_and_compare(ROOT_SCREENSHOT_PATH, test_name, instructions,
screen_change_before_first_instruction=False)
navigator.navigate_and_compare(
ROOT_SCREENSHOT_PATH,
test_name,
instructions,
screen_change_before_first_instruction=False,
)
Loading
Loading