python/trezorctl: send raw bytes to device (fixes #116)

pull/919/head
matejcik 4 years ago
parent 9a330f3475
commit 2112da7ab5

@ -16,7 +16,7 @@
import click import click
from .. import debuglink from .. import debuglink, mapping, messages, protobuf
from ..messages import DebugLinkShowTextStyle as S from ..messages import DebugLinkShowTextStyle as S
@ -71,3 +71,48 @@ def show_text(connect, icon, color, header, body):
return debuglink.show_text( return debuglink.show_text(
connect(), header, body_text, icon=icon, icon_color=color connect(), header, body_text, icon=icon, icon_color=color
) )
@cli.command()
@click.argument("message_name_or_type")
@click.argument("hex_data")
@click.pass_obj
def send_bytes(connect, message_name_or_type, hex_data):
"""Send raw bytes to Trezor.
Message type and message data must be specified separately, due to how message
chunking works on the transport level. Message length is calculated and sent
automatically, and it is currently impossible to explicitly specify invalid length.
MESSAGE_NAME_OR_TYPE can either be a number, or a name from the MessageType enum,
in which case the value of that enum is used.
"""
if message_name_or_type.isdigit():
message_type = int(message_name_or_type)
else:
message_type = getattr(messages.MessageType, message_name_or_type)
if not isinstance(message_type, int):
raise click.ClickException("Invalid message type.")
try:
message_data = bytes.fromhex(hex_data)
except Exception as e:
raise click.ClickException("Invalid hex data.") from e
transport = connect(return_transport=True)
transport.begin_session()
transport.write(message_type, message_data)
response_type, response_data = transport.read()
transport.end_session()
click.echo("Response type: {}".format(response_type))
click.echo("Response data: {}".format(response_data.hex()))
try:
msg = mapping.decode(response_type, response_data)
click.echo("Parsed message:")
click.echo(protobuf.format_message(msg))
except Exception as e:
click.echo("Could not parse response: {}".format(e))

@ -157,19 +157,21 @@ def cli(ctx, path, verbose, is_json, passphrase_on_host, session_id):
except ValueError: except ValueError:
raise click.ClickException("Not a valid session id: {}".format(session_id)) raise click.ClickException("Not a valid session id: {}".format(session_id))
def get_device(): def get_device(return_transport=False):
try: try:
device = get_transport(path, prefix_search=False) transport = get_transport(path, prefix_search=False)
except Exception: except Exception:
try: try:
device = get_transport(path, prefix_search=True) transport = get_transport(path, prefix_search=True)
except Exception: except Exception:
click.echo("Failed to find a Trezor device.") click.echo("Failed to find a Trezor device.")
if path is not None: if path is not None:
click.echo("Using path: {}".format(path)) click.echo("Using path: {}".format(path))
sys.exit(1) sys.exit(1)
if return_transport:
return transport
return TrezorClient( return TrezorClient(
transport=device, transport=transport,
ui=ui.ClickUI(passphrase_on_host=passphrase_on_host), ui=ui.ClickUI(passphrase_on_host=passphrase_on_host),
session_id=session_id, session_id=session_id,
) )

Loading…
Cancel
Save