Updated Ragger app client for domain names & sign APDUs
This commit is contained in:
@@ -2,12 +2,33 @@ from enum import IntEnum, auto
|
||||
from typing import Optional
|
||||
from ragger.backend import BackendInterface
|
||||
from ragger.utils import RAPDU
|
||||
from ragger.navigator import NavInsID, NavIns, NanoNavigator
|
||||
from .command_builder import EthereumCmdBuilder
|
||||
from .setting import SettingType, SettingImpl
|
||||
from .eip712 import EIP712FieldType
|
||||
from .response_parser import EthereumRespParser
|
||||
from .tlv import format_tlv
|
||||
import signal
|
||||
import time
|
||||
from pathlib import Path
|
||||
import keychain
|
||||
import rlp
|
||||
|
||||
|
||||
ROOT_SCREENSHOT_PATH = Path(__file__).parent.parent
|
||||
WEI_IN_ETH = 1e+18
|
||||
|
||||
|
||||
class DOMAIN_NAME_TAG(IntEnum):
|
||||
STRUCTURE_TYPE = 0x01
|
||||
STRUCTURE_VERSION = 0x02
|
||||
CHALLENGE = 0x12
|
||||
SIGNER_KEY_ID = 0x13
|
||||
SIGNER_ALGO = 0x14
|
||||
SIGNATURE = 0x15
|
||||
DOMAIN_NAME = 0x20
|
||||
COIN_TYPE = 0x21
|
||||
ADDRESS = 0x22
|
||||
|
||||
|
||||
class EthereumClient:
|
||||
@@ -23,15 +44,20 @@ class EthereumClient:
|
||||
),
|
||||
SettingType.VERBOSE_EIP712: SettingImpl(
|
||||
[ "nanox", "nanosp" ]
|
||||
),
|
||||
SettingType.VERBOSE_ENS: SettingImpl(
|
||||
[ "nanox", "nanosp" ]
|
||||
)
|
||||
}
|
||||
_click_delay = 1/4
|
||||
_eip712_filtering = False
|
||||
|
||||
def __init__(self, client: BackendInterface):
|
||||
def __init__(self, client: BackendInterface, golden_run: bool):
|
||||
self._client = client
|
||||
self._chain_id = 1
|
||||
self._cmd_builder = EthereumCmdBuilder()
|
||||
self._resp_parser = EthereumRespParser()
|
||||
self._nav = NanoNavigator(client, client.firmware, golden_run)
|
||||
signal.signal(signal.SIGALRM, self._click_signal_timeout)
|
||||
for setting in self._settings.values():
|
||||
setting.value = False
|
||||
@@ -156,3 +182,61 @@ class EthereumClient:
|
||||
with self._send(self._cmd_builder.eip712_filtering_show_field(name, sig)):
|
||||
pass
|
||||
assert self._recv().status == 0x9000
|
||||
|
||||
def send_fund(self,
|
||||
bip32_path: str,
|
||||
nonce: int,
|
||||
gas_price: int,
|
||||
gas_limit: int,
|
||||
to: bytes,
|
||||
amount: float,
|
||||
chain_id: int,
|
||||
screenshot_collection: str = None):
|
||||
data = list()
|
||||
data.append(nonce)
|
||||
data.append(gas_price)
|
||||
data.append(gas_limit)
|
||||
data.append(to)
|
||||
data.append(int(amount * WEI_IN_ETH))
|
||||
data.append(bytes())
|
||||
data.append(chain_id)
|
||||
data.append(bytes())
|
||||
data.append(bytes())
|
||||
|
||||
for chunk in self._cmd_builder.sign(bip32_path, rlp.encode(data)):
|
||||
with self._send(chunk):
|
||||
nav_ins = NavIns(NavInsID.RIGHT_CLICK)
|
||||
final_ins = [ NavIns(NavInsID.BOTH_CLICK) ]
|
||||
target_text = "and send"
|
||||
if screenshot_collection:
|
||||
self._nav.navigate_until_text_and_compare(nav_ins,
|
||||
final_ins,
|
||||
target_text,
|
||||
ROOT_SCREENSHOT_PATH,
|
||||
screenshot_collection)
|
||||
else:
|
||||
self._nav.navigate_until_text(nav_ins,
|
||||
final_ins,
|
||||
target_text)
|
||||
|
||||
def get_challenge(self) -> int:
|
||||
with self._send(self._cmd_builder.get_challenge()):
|
||||
pass
|
||||
resp = self._recv()
|
||||
return self._resp_parser.challenge(resp.data)
|
||||
|
||||
def provide_domain_name(self, challenge: int, name: str, addr: bytes):
|
||||
payload = format_tlv(DOMAIN_NAME_TAG.STRUCTURE_TYPE, 3) # TrustedDomainName
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.STRUCTURE_VERSION, 1)
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_KEY_ID, 0) # test key
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.SIGNER_ALGO, 1) # secp256k1
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.CHALLENGE, challenge)
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.COIN_TYPE, 0x3c) # ETH in slip-44
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.DOMAIN_NAME, name)
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.ADDRESS, addr)
|
||||
payload += format_tlv(DOMAIN_NAME_TAG.SIGNATURE,
|
||||
keychain.sign_data(keychain.Key.DOMAIN_NAME, payload))
|
||||
|
||||
for chunk in self._cmd_builder.provide_domain_name(payload):
|
||||
with self._send(chunk):
|
||||
pass
|
||||
|
||||
Reference in New Issue
Block a user