Ragger tests
@@ -337,12 +337,11 @@ def next_timeout(_signum: int, _frame):
|
|||||||
|
|
||||||
|
|
||||||
def enable_autonext():
|
def enable_autonext():
|
||||||
seconds = 1/4
|
|
||||||
if app_client._client.firmware.device == 'stax': # Stax Speculos is slow
|
if app_client._client.firmware.device == 'stax': # Stax Speculos is slow
|
||||||
interval = seconds * 3
|
delay = 1.5
|
||||||
else:
|
else:
|
||||||
interval = seconds
|
delay = 1/4
|
||||||
signal.setitimer(signal.ITIMER_REAL, seconds, interval)
|
signal.setitimer(signal.ITIMER_REAL, delay, delay)
|
||||||
|
|
||||||
|
|
||||||
def disable_autonext():
|
def disable_autonext():
|
||||||
|
|||||||
29
tests/ragger/eip712_input_files/address_substitution.json
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
{
|
||||||
|
"domain": {
|
||||||
|
"chainId": 1,
|
||||||
|
"name": "Token test",
|
||||||
|
"verifyingContract": "0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC",
|
||||||
|
"version": "1"
|
||||||
|
},
|
||||||
|
"message": {
|
||||||
|
"from": "0xaAaAaAaaAaAaAaaAaAAAAAAAAaaaAaAaAaaAaaAa",
|
||||||
|
"to": "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
|
||||||
|
"amount": "117",
|
||||||
|
"token": "0x6B175474E89094C44Da98b954EedeAC495271d0F"
|
||||||
|
},
|
||||||
|
"primaryType": "Transfer",
|
||||||
|
"types": {
|
||||||
|
"EIP712Domain": [
|
||||||
|
{ "name": "name", "type": "string" },
|
||||||
|
{ "name": "version", "type": "string" },
|
||||||
|
{ "name": "chainId", "type": "uint256" },
|
||||||
|
{ "name": "verifyingContract", "type": "address" }
|
||||||
|
],
|
||||||
|
"Transfer": [
|
||||||
|
{ "name": "from", "type": "address" },
|
||||||
|
{ "name": "to", "type": "address" },
|
||||||
|
{ "name": "amount", "type": "uint256" },
|
||||||
|
{ "name": "token", "type": "address" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 338 B |
|
After Width: | Height: | Size: 336 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 381 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 463 B |
|
After Width: | Height: | Size: 371 B |
|
After Width: | Height: | Size: 298 B |
|
After Width: | Height: | Size: 285 B |
|
After Width: | Height: | Size: 655 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 555 B |
|
After Width: | Height: | Size: 709 B |
|
After Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 774 B |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 381 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 414 B |
|
After Width: | Height: | Size: 338 B |
|
After Width: | Height: | Size: 336 B |
|
After Width: | Height: | Size: 324 B |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 381 B |
|
After Width: | Height: | Size: 472 B |
|
After Width: | Height: | Size: 463 B |
|
After Width: | Height: | Size: 371 B |
|
After Width: | Height: | Size: 298 B |
|
After Width: | Height: | Size: 285 B |
|
After Width: | Height: | Size: 655 B |
|
After Width: | Height: | Size: 433 B |
|
After Width: | Height: | Size: 555 B |
|
After Width: | Height: | Size: 709 B |
|
After Width: | Height: | Size: 321 B |
|
After Width: | Height: | Size: 774 B |
|
After Width: | Height: | Size: 364 B |
|
After Width: | Height: | Size: 381 B |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 6.8 KiB |
|
After Width: | Height: | Size: 6.2 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.7 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 7.5 KiB |
|
After Width: | Height: | Size: 6.4 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 5.4 KiB |
|
After Width: | Height: | Size: 9.1 KiB |
|
After Width: | Height: | Size: 7.0 KiB |
|
After Width: | Height: | Size: 7.8 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 5.5 KiB |
|
After Width: | Height: | Size: 12 KiB |
|
After Width: | Height: | Size: 9.0 KiB |
|
After Width: | Height: | Size: 5.0 KiB |
@@ -9,6 +9,8 @@ from ragger.backend import BackendInterface
|
|||||||
from ragger.firmware import Firmware
|
from ragger.firmware import Firmware
|
||||||
from ragger.navigator import Navigator, NavInsID
|
from ragger.navigator import Navigator, NavInsID
|
||||||
import json
|
import json
|
||||||
|
from typing import Optional
|
||||||
|
from constants import ROOT_SNAPSHOT_PATH
|
||||||
|
|
||||||
import ledger_app_clients.ethereum.response_parser as ResponseParser
|
import ledger_app_clients.ethereum.response_parser as ResponseParser
|
||||||
from ledger_app_clients.ethereum.client import EthAppClient
|
from ledger_app_clients.ethereum.client import EthAppClient
|
||||||
@@ -29,9 +31,13 @@ BIP32_PATH = "m/44'/60'/0'/0/0"
|
|||||||
snaps_config: Optional[SnapshotsConfig] = None
|
snaps_config: Optional[SnapshotsConfig] = None
|
||||||
|
|
||||||
|
|
||||||
|
def eip712_json_path() -> str:
|
||||||
|
return "%s/eip712_input_files" % (os.path.dirname(__file__))
|
||||||
|
|
||||||
|
|
||||||
def input_files() -> list[str]:
|
def input_files() -> list[str]:
|
||||||
files = []
|
files = []
|
||||||
for file in os.scandir("%s/eip712_input_files" % (os.path.dirname(__file__))):
|
for file in os.scandir(eip712_json_path()):
|
||||||
if fnmatch.fnmatch(file, "*-data.json"):
|
if fnmatch.fnmatch(file, "*-data.json"):
|
||||||
files.append(file.path)
|
files.append(file.path)
|
||||||
return sorted(files)
|
return sorted(files)
|
||||||
@@ -87,7 +93,52 @@ def autonext(fw: Firmware, nav: Navigator):
|
|||||||
moves = [NavInsID.RIGHT_CLICK]
|
moves = [NavInsID.RIGHT_CLICK]
|
||||||
else:
|
else:
|
||||||
moves = [NavInsID.USE_CASE_REVIEW_TAP]
|
moves = [NavInsID.USE_CASE_REVIEW_TAP]
|
||||||
nav.navigate(moves, screen_change_before_first_instruction=False, screen_change_after_last_instruction=False)
|
if snaps_config is not None:
|
||||||
|
nav.navigate_and_compare(ROOT_SNAPSHOT_PATH,
|
||||||
|
snaps_config.test_name,
|
||||||
|
moves,
|
||||||
|
screen_change_before_first_instruction=False,
|
||||||
|
screen_change_after_last_instruction=False,
|
||||||
|
snap_start_idx=snaps_config.idx)
|
||||||
|
snaps_config.idx += 1
|
||||||
|
else:
|
||||||
|
nav.navigate(moves,
|
||||||
|
screen_change_before_first_instruction=False,
|
||||||
|
screen_change_after_last_instruction=False)
|
||||||
|
|
||||||
|
|
||||||
|
def eip712_new_common(fw: Firmware,
|
||||||
|
nav: Navigator,
|
||||||
|
app_client: EthAppClient,
|
||||||
|
json_data: dict,
|
||||||
|
filters: Optional[dict],
|
||||||
|
verbose: bool):
|
||||||
|
assert InputData.process_data(app_client,
|
||||||
|
json_data,
|
||||||
|
filters,
|
||||||
|
partial(autonext, fw, nav))
|
||||||
|
with app_client.eip712_sign_new(BIP32_PATH):
|
||||||
|
moves = list()
|
||||||
|
if fw.device.startswith("nano"):
|
||||||
|
# need to skip the message hash
|
||||||
|
if not verbose and filters is None:
|
||||||
|
moves = [NavInsID.RIGHT_CLICK] * 2
|
||||||
|
moves += [NavInsID.BOTH_CLICK]
|
||||||
|
else:
|
||||||
|
time.sleep(1.5)
|
||||||
|
# need to skip the message hash
|
||||||
|
if not verbose and filters is None:
|
||||||
|
moves += [NavInsID.USE_CASE_REVIEW_TAP]
|
||||||
|
moves += [NavInsID.USE_CASE_REVIEW_CONFIRM]
|
||||||
|
if snaps_config is not None:
|
||||||
|
nav.navigate_and_compare(ROOT_SNAPSHOT_PATH,
|
||||||
|
snaps_config.test_name,
|
||||||
|
moves,
|
||||||
|
snap_start_idx=snaps_config.idx)
|
||||||
|
snaps_config.idx += 1
|
||||||
|
else:
|
||||||
|
nav.navigate(moves)
|
||||||
|
return ResponseParser.signature(app_client.response().data)
|
||||||
|
|
||||||
|
|
||||||
def test_eip712_new(firmware: Firmware,
|
def test_eip712_new(firmware: Firmware,
|
||||||
@@ -124,26 +175,69 @@ def test_eip712_new(firmware: Firmware,
|
|||||||
settings_toggle(firmware, navigator, [SettingID.VERBOSE_EIP712])
|
settings_toggle(firmware, navigator, [SettingID.VERBOSE_EIP712])
|
||||||
|
|
||||||
with open(input_file) as file:
|
with open(input_file) as file:
|
||||||
assert InputData.process_data(app_client,
|
v, r, s = eip712_new_common(firmware,
|
||||||
json.load(file),
|
navigator,
|
||||||
filters,
|
app_client,
|
||||||
partial(autonext, firmware, navigator))
|
json.load(file),
|
||||||
with app_client.eip712_sign_new(BIP32_PATH):
|
filters,
|
||||||
# tight on timing, needed by the CI otherwise might fail sometimes
|
verbose)
|
||||||
time.sleep(0.5)
|
|
||||||
|
|
||||||
moves = list()
|
assert v == bytes.fromhex(config["signature"]["v"])
|
||||||
if firmware.device.startswith("nano"):
|
assert r == bytes.fromhex(config["signature"]["r"])
|
||||||
if not verbose and not filtering: # need to skip the message hash
|
assert s == bytes.fromhex(config["signature"]["s"])
|
||||||
moves = [NavInsID.RIGHT_CLICK] * 2
|
|
||||||
moves += [NavInsID.BOTH_CLICK]
|
|
||||||
else:
|
|
||||||
if not verbose and not filtering: # need to skip the message hash
|
|
||||||
moves += [NavInsID.USE_CASE_REVIEW_TAP]
|
|
||||||
moves += [NavInsID.USE_CASE_REVIEW_CONFIRM]
|
|
||||||
navigator.navigate(moves)
|
|
||||||
v, r, s = ResponseParser.signature(app_client.response().data)
|
|
||||||
|
|
||||||
assert v == bytes.fromhex(config["signature"]["v"])
|
|
||||||
assert r == bytes.fromhex(config["signature"]["r"])
|
def test_eip712_address_substitution(firmware: Firmware,
|
||||||
assert s == bytes.fromhex(config["signature"]["s"])
|
backend: BackendInterface,
|
||||||
|
navigator: Navigator,
|
||||||
|
verbose: bool):
|
||||||
|
global snaps_config
|
||||||
|
|
||||||
|
app_client = EthAppClient(backend)
|
||||||
|
if firmware.device == "nanos":
|
||||||
|
pytest.skip("Not supported on LNS")
|
||||||
|
else:
|
||||||
|
test_name = "eip712_address_substitution"
|
||||||
|
if verbose:
|
||||||
|
test_name += "_verbose"
|
||||||
|
snaps_config = SnapshotsConfig(test_name)
|
||||||
|
with open("%s/address_substitution.json" % (eip712_json_path())) as file:
|
||||||
|
data = json.load(file)
|
||||||
|
|
||||||
|
with app_client.provide_token_metadata("DAI",
|
||||||
|
bytes.fromhex(data["message"]["token"][2:]),
|
||||||
|
18,
|
||||||
|
1):
|
||||||
|
pass
|
||||||
|
|
||||||
|
with app_client.get_challenge():
|
||||||
|
pass
|
||||||
|
challenge = ResponseParser.challenge(app_client.response().data)
|
||||||
|
with app_client.provide_domain_name(challenge,
|
||||||
|
"vitalik.eth",
|
||||||
|
bytes.fromhex(data["message"]["to"][2:])):
|
||||||
|
pass
|
||||||
|
|
||||||
|
if verbose:
|
||||||
|
settings_toggle(firmware, navigator, [SettingID.VERBOSE_EIP712])
|
||||||
|
filters = None
|
||||||
|
else:
|
||||||
|
filters = {
|
||||||
|
"name": "Token test",
|
||||||
|
"fields": {
|
||||||
|
"amount": "Amount",
|
||||||
|
"token": "Token",
|
||||||
|
"to": "To",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
v, r, s = eip712_new_common(firmware,
|
||||||
|
navigator,
|
||||||
|
app_client,
|
||||||
|
data,
|
||||||
|
filters,
|
||||||
|
verbose)
|
||||||
|
|
||||||
|
assert v == bytes.fromhex("1b")
|
||||||
|
assert r == bytes.fromhex("d4a0e058251cdc3845aaa5eb8409d8a189ac668db7c55a64eb3121b0db7fd8c0")
|
||||||
|
assert s == bytes.fromhex("3221800e4f45272c6fa8fafda5e94c848d1a4b90c442aa62afa8e8d6a9af0f00")
|
||||||
|
|||||||