mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 06:18:07 +00:00
python/trezorctl: implement common client and exception handling (fixes #226)
This commit is contained in:
parent
b440ca1ec5
commit
f52c087cb6
@ -114,7 +114,7 @@ def verify_message(client, coin_name, address, signature, message):
|
|||||||
coin_name=coin_name,
|
coin_name=coin_name,
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
except exceptions.TrezorFailure as e:
|
except exceptions.TrezorFailure:
|
||||||
return False
|
return False
|
||||||
return isinstance(resp, messages.Success)
|
return isinstance(resp, messages.Success)
|
||||||
|
|
||||||
|
@ -14,14 +14,72 @@
|
|||||||
# You should have received a copy of the License along with this library.
|
# You should have received a copy of the License along with this library.
|
||||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||||
|
|
||||||
|
import functools
|
||||||
|
import sys
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
|
from .. import exceptions
|
||||||
|
from ..client import TrezorClient
|
||||||
|
from ..transport import get_transport
|
||||||
|
from ..ui import ClickUI
|
||||||
|
|
||||||
|
|
||||||
class ChoiceType(click.Choice):
|
class ChoiceType(click.Choice):
|
||||||
def __init__(self, typemap):
|
def __init__(self, typemap):
|
||||||
super(ChoiceType, self).__init__(typemap.keys())
|
super().__init__(typemap.keys())
|
||||||
self.typemap = typemap
|
self.typemap = typemap
|
||||||
|
|
||||||
def convert(self, value, param, ctx):
|
def convert(self, value, param, ctx):
|
||||||
value = super(ChoiceType, self).convert(value, param, ctx)
|
value = super().convert(value, param, ctx)
|
||||||
return self.typemap[value]
|
return self.typemap[value]
|
||||||
|
|
||||||
|
|
||||||
|
class TrezorConnection:
|
||||||
|
def __init__(self, path, session_id, passphrase_on_host):
|
||||||
|
self.path = path
|
||||||
|
self.session_id = session_id
|
||||||
|
self.passphrase_on_host = passphrase_on_host
|
||||||
|
|
||||||
|
def get_transport(self):
|
||||||
|
try:
|
||||||
|
# look for transport without prefix search
|
||||||
|
return get_transport(self.path, prefix_search=False)
|
||||||
|
except Exception:
|
||||||
|
# most likely not found. try again below.
|
||||||
|
pass
|
||||||
|
|
||||||
|
# look for transport with prefix search
|
||||||
|
# if this fails, we want the exception to bubble up to the caller
|
||||||
|
return get_transport(self.path, prefix_search=True)
|
||||||
|
|
||||||
|
def get_ui(self):
|
||||||
|
return ClickUI(passphrase_on_host=self.passphrase_on_host)
|
||||||
|
|
||||||
|
def get_client(self):
|
||||||
|
transport = self.get_transport()
|
||||||
|
ui = self.get_ui()
|
||||||
|
return TrezorClient(transport, ui=ui, session_id=self.session_id)
|
||||||
|
|
||||||
|
|
||||||
|
def with_client(func):
|
||||||
|
@click.pass_obj
|
||||||
|
@functools.wraps(func)
|
||||||
|
def trezorctl_command_with_client(obj, *args, **kwargs):
|
||||||
|
try:
|
||||||
|
client = obj.get_client()
|
||||||
|
except Exception:
|
||||||
|
click.echo("Failed to find a Trezor device.")
|
||||||
|
if obj.path is not None:
|
||||||
|
click.echo("Using path: {}".format(obj.path))
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
try:
|
||||||
|
return func(client, *args, **kwargs)
|
||||||
|
except exceptions.Cancelled:
|
||||||
|
click.echo("Action was cancelled.")
|
||||||
|
sys.exit(1)
|
||||||
|
except exceptions.TrezorException as e:
|
||||||
|
raise click.ClickException(str(e)) from e
|
||||||
|
|
||||||
|
return trezorctl_command_with_client
|
||||||
|
@ -19,6 +19,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import binance, tools
|
from .. import binance, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path to key, e.g. m/44'/714'/0'/0/0"
|
PATH_HELP = "BIP-32 path to key, e.g. m/44'/714'/0'/0/0"
|
||||||
|
|
||||||
@ -31,24 +32,20 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Binance address for specified path."""
|
"""Get Binance address for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
|
|
||||||
return binance.get_address(client, address_n, show_display)
|
return binance.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_key(connect, address, show_display):
|
def get_public_key(client, address, show_display):
|
||||||
"""Get Binance public key."""
|
"""Get Binance public key."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
|
|
||||||
return binance.get_public_key(client, address_n, show_display).hex()
|
return binance.get_public_key(client, address_n, show_display).hex()
|
||||||
|
|
||||||
|
|
||||||
@ -61,10 +58,8 @@ def get_public_key(connect, address, show_display):
|
|||||||
required=True,
|
required=True,
|
||||||
help="Transaction in JSON format",
|
help="Transaction in JSON format",
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, address, file):
|
def sign_tx(client, address, file):
|
||||||
"""Sign Binance transaction"""
|
"""Sign Binance transaction"""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
|
|
||||||
return binance.sign_tx(client, address_n, json.load(file))
|
return binance.sign_tx(client, address_n, json.load(file))
|
||||||
|
@ -20,7 +20,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import btc, messages, protobuf, tools
|
from .. import btc, messages, protobuf, tools
|
||||||
from . import ChoiceType
|
from . import ChoiceType, with_client
|
||||||
|
|
||||||
INPUT_SCRIPTS = {
|
INPUT_SCRIPTS = {
|
||||||
"address": messages.InputScriptType.SPENDADDRESS,
|
"address": messages.InputScriptType.SPENDADDRESS,
|
||||||
@ -52,13 +52,13 @@ def cli():
|
|||||||
@click.option("-n", "--address", required=True, help="BIP-32 path")
|
@click.option("-n", "--address", required=True, help="BIP-32 path")
|
||||||
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address")
|
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address")
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, coin, address, script_type, show_display):
|
def get_address(client, coin, address, script_type, show_display):
|
||||||
"""Get address for specified path."""
|
"""Get address for specified path."""
|
||||||
coin = coin or DEFAULT_COIN
|
coin = coin or DEFAULT_COIN
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return btc.get_address(
|
return btc.get_address(
|
||||||
connect(), coin, address_n, show_display, script_type=script_type
|
client, coin, address_n, show_display, script_type=script_type
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -68,13 +68,13 @@ def get_address(connect, coin, address, script_type, show_display):
|
|||||||
@click.option("-e", "--curve")
|
@click.option("-e", "--curve")
|
||||||
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address")
|
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address")
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_node(connect, coin, address, curve, script_type, show_display):
|
def get_public_node(client, coin, address, curve, script_type, show_display):
|
||||||
"""Get public node of given path."""
|
"""Get public node of given path."""
|
||||||
coin = coin or DEFAULT_COIN
|
coin = coin or DEFAULT_COIN
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
result = btc.get_public_node(
|
result = btc.get_public_node(
|
||||||
connect(),
|
client,
|
||||||
address_n,
|
address_n,
|
||||||
ecdsa_curve_name=curve,
|
ecdsa_curve_name=curve,
|
||||||
show_display=show_display,
|
show_display=show_display,
|
||||||
@ -101,8 +101,8 @@ def get_public_node(connect, coin, address, curve, script_type, show_display):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-c", "--coin", "_ignore", is_flag=True, hidden=True, expose_value=False)
|
@click.option("-c", "--coin", "_ignore", is_flag=True, hidden=True, expose_value=False)
|
||||||
@click.argument("json_file", type=click.File())
|
@click.argument("json_file", type=click.File())
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, json_file):
|
def sign_tx(client, json_file):
|
||||||
"""Sign transaction.
|
"""Sign transaction.
|
||||||
|
|
||||||
Transaction data must be provided in a JSON file. See `transaction-format.md` for
|
Transaction data must be provided in a JSON file. See `transaction-format.md` for
|
||||||
@ -111,8 +111,6 @@ def sign_tx(connect, json_file):
|
|||||||
|
|
||||||
$ python3 tools/build_tx.py | trezorctl btc sign-tx -
|
$ python3 tools/build_tx.py | trezorctl btc sign-tx -
|
||||||
"""
|
"""
|
||||||
client = connect()
|
|
||||||
|
|
||||||
data = json.load(json_file)
|
data = json.load(json_file)
|
||||||
coin = data.get("coin_name", DEFAULT_COIN)
|
coin = data.get("coin_name", DEFAULT_COIN)
|
||||||
details = protobuf.dict_to_proto(messages.SignTx, data.get("details", {}))
|
details = protobuf.dict_to_proto(messages.SignTx, data.get("details", {}))
|
||||||
@ -145,12 +143,12 @@ def sign_tx(connect, json_file):
|
|||||||
@click.option("-n", "--address", required=True, help="BIP-32 path")
|
@click.option("-n", "--address", required=True, help="BIP-32 path")
|
||||||
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address")
|
@click.option("-t", "--script-type", type=ChoiceType(INPUT_SCRIPTS), default="address")
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_message(connect, coin, address, message, script_type):
|
def sign_message(client, coin, address, message, script_type):
|
||||||
"""Sign message using address of given path."""
|
"""Sign message using address of given path."""
|
||||||
coin = coin or DEFAULT_COIN
|
coin = coin or DEFAULT_COIN
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
res = btc.sign_message(connect(), coin, address_n, message, script_type)
|
res = btc.sign_message(client, coin, address_n, message, script_type)
|
||||||
return {
|
return {
|
||||||
"message": message,
|
"message": message,
|
||||||
"address": res.address,
|
"address": res.address,
|
||||||
@ -163,12 +161,12 @@ def sign_message(connect, coin, address, message, script_type):
|
|||||||
@click.argument("address")
|
@click.argument("address")
|
||||||
@click.argument("signature")
|
@click.argument("signature")
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def verify_message(connect, coin, address, signature, message):
|
def verify_message(client, coin, address, signature, message):
|
||||||
"""Verify message."""
|
"""Verify message."""
|
||||||
signature = base64.b64decode(signature)
|
signature = base64.b64decode(signature)
|
||||||
coin = coin or DEFAULT_COIN
|
coin = coin or DEFAULT_COIN
|
||||||
return btc.verify_message(connect(), coin, address, signature, message)
|
return btc.verify_message(client, coin, address, signature, message)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -19,6 +19,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import cardano, tools
|
from .. import cardano, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path to key, e.g. m/44'/1815'/0'/0/0"
|
PATH_HELP = "BIP-32 path to key, e.g. m/44'/1815'/0'/0/0"
|
||||||
|
|
||||||
@ -37,11 +38,9 @@ def cli():
|
|||||||
help="Transaction in JSON format",
|
help="Transaction in JSON format",
|
||||||
)
|
)
|
||||||
@click.option("-N", "--network", type=int, default=1)
|
@click.option("-N", "--network", type=int, default=1)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, file, network):
|
def sign_tx(client, file, network):
|
||||||
"""Sign Cardano transaction."""
|
"""Sign Cardano transaction."""
|
||||||
client = connect()
|
|
||||||
|
|
||||||
transaction = json.load(file)
|
transaction = json.load(file)
|
||||||
|
|
||||||
inputs = [cardano.create_input(input) for input in transaction["inputs"]]
|
inputs = [cardano.create_input(input) for input in transaction["inputs"]]
|
||||||
@ -59,21 +58,17 @@ def sign_tx(connect, file, network):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Cardano address."""
|
"""Get Cardano address."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
|
|
||||||
return cardano.get_address(client, address_n, show_display)
|
return cardano.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_key(connect, address):
|
def get_public_key(client, address):
|
||||||
"""Get Cardano public key."""
|
"""Get Cardano public key."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
|
|
||||||
return cardano.get_public_key(client, address_n)
|
return cardano.get_public_key(client, address_n)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import cosi, tools
|
from .. import cosi, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path, e.g. m/44'/0'/0'/0/0"
|
PATH_HELP = "BIP-32 path, e.g. m/44'/0'/0'/0/0"
|
||||||
|
|
||||||
@ -29,10 +30,9 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.argument("data")
|
@click.argument("data")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def commit(connect, address, data):
|
def commit(client, address, data):
|
||||||
"""Ask device to commit to CoSi signing."""
|
"""Ask device to commit to CoSi signing."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return cosi.commit(client, address_n, bytes.fromhex(data))
|
return cosi.commit(client, address_n, bytes.fromhex(data))
|
||||||
|
|
||||||
@ -42,10 +42,9 @@ def commit(connect, address, data):
|
|||||||
@click.argument("data")
|
@click.argument("data")
|
||||||
@click.argument("global_commitment")
|
@click.argument("global_commitment")
|
||||||
@click.argument("global_pubkey")
|
@click.argument("global_pubkey")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign(connect, address, data, global_commitment, global_pubkey):
|
def sign(client, address, data, global_commitment, global_pubkey):
|
||||||
"""Ask device to sign using CoSi."""
|
"""Ask device to sign using CoSi."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return cosi.sign(
|
return cosi.sign(
|
||||||
client,
|
client,
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import misc, tools
|
from .. import misc, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
|
|
||||||
@click.group(name="crypto")
|
@click.group(name="crypto")
|
||||||
@ -26,32 +27,29 @@ def cli():
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("size", type=int)
|
@click.argument("size", type=int)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_entropy(connect, size):
|
def get_entropy(client, size):
|
||||||
"""Get random bytes from device."""
|
"""Get random bytes from device."""
|
||||||
return misc.get_entropy(connect(), size).hex()
|
return misc.get_entropy(client, size).hex()
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/10016'/0")
|
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/10016'/0")
|
||||||
@click.argument("key")
|
@click.argument("key")
|
||||||
@click.argument("value")
|
@click.argument("value")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def encrypt_keyvalue(connect, address, key, value):
|
def encrypt_keyvalue(client, address, key, value):
|
||||||
"""Encrypt value by given key and path."""
|
"""Encrypt value by given key and path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
res = misc.encrypt_keyvalue(client, address_n, key, value.encode())
|
return misc.encrypt_keyvalue(client, address_n, key, value.encode()).hex()
|
||||||
return res.hex()
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/10016'/0")
|
@click.option("-n", "--address", required=True, help="BIP-32 path, e.g. m/10016'/0")
|
||||||
@click.argument("key")
|
@click.argument("key")
|
||||||
@click.argument("value")
|
@click.argument("value")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def decrypt_keyvalue(connect, address, key, value):
|
def decrypt_keyvalue(client, address, key, value):
|
||||||
"""Decrypt value by given key and path."""
|
"""Decrypt value by given key and path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return misc.decrypt_keyvalue(client, address_n, key, bytes.fromhex(value))
|
return misc.decrypt_keyvalue(client, address_n, key, bytes.fromhex(value))
|
||||||
|
@ -18,6 +18,7 @@ import click
|
|||||||
|
|
||||||
from .. import debuglink, mapping, messages, protobuf
|
from .. import debuglink, mapping, messages, protobuf
|
||||||
from ..messages import DebugLinkShowTextStyle as S
|
from ..messages import DebugLinkShowTextStyle as S
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
|
|
||||||
@click.group(name="debug")
|
@click.group(name="debug")
|
||||||
@ -40,8 +41,8 @@ STYLES = {
|
|||||||
@click.option("-c", "--color", help="Header icon color")
|
@click.option("-c", "--color", help="Header icon color")
|
||||||
@click.option("-h", "--header", help="Header text", default="Showing text")
|
@click.option("-h", "--header", help="Header text", default="Showing text")
|
||||||
@click.argument("body")
|
@click.argument("body")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def show_text(connect, icon, color, header, body):
|
def show_text(client, icon, color, header, body):
|
||||||
"""Show text on Trezor display.
|
"""Show text on Trezor display.
|
||||||
|
|
||||||
For usage instructions, see:
|
For usage instructions, see:
|
||||||
@ -68,16 +69,14 @@ def show_text(connect, icon, color, header, body):
|
|||||||
|
|
||||||
_flush()
|
_flush()
|
||||||
|
|
||||||
return debuglink.show_text(
|
return debuglink.show_text(client, header, body_text, icon=icon, icon_color=color)
|
||||||
connect(), header, body_text, icon=icon, icon_color=color
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("message_name_or_type")
|
@click.argument("message_name_or_type")
|
||||||
@click.argument("hex_data")
|
@click.argument("hex_data")
|
||||||
@click.pass_obj
|
@click.pass_obj
|
||||||
def send_bytes(connect, message_name_or_type, hex_data):
|
def send_bytes(obj, message_name_or_type, hex_data):
|
||||||
"""Send raw bytes to Trezor.
|
"""Send raw bytes to Trezor.
|
||||||
|
|
||||||
Message type and message data must be specified separately, due to how message
|
Message type and message data must be specified separately, due to how message
|
||||||
@ -100,7 +99,7 @@ def send_bytes(connect, message_name_or_type, hex_data):
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
raise click.ClickException("Invalid hex data.") from e
|
raise click.ClickException("Invalid hex data.") from e
|
||||||
|
|
||||||
transport = connect(return_transport=True)
|
transport = obj.get_transport()
|
||||||
transport.begin_session()
|
transport.begin_session()
|
||||||
transport.write(message_type, message_data)
|
transport.write(message_type, message_data)
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ import sys
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import debuglink, device, exceptions, messages, ui
|
from .. import debuglink, device, exceptions, messages, ui
|
||||||
from . import ChoiceType
|
from . import ChoiceType, with_client
|
||||||
|
|
||||||
RECOVERY_TYPE = {
|
RECOVERY_TYPE = {
|
||||||
"scrambled": messages.RecoveryDeviceType.ScrambledWords,
|
"scrambled": messages.RecoveryDeviceType.ScrambledWords,
|
||||||
@ -45,10 +45,10 @@ def cli():
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def self_test(connect):
|
def self_test(client):
|
||||||
"""Perform a self-test."""
|
"""Perform a self-test."""
|
||||||
return debuglink.self_test(connect())
|
return debuglink.self_test(client)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@ -58,10 +58,9 @@ def self_test(connect):
|
|||||||
help="Wipe device in bootloader mode. This also erases the firmware.",
|
help="Wipe device in bootloader mode. This also erases the firmware.",
|
||||||
is_flag=True,
|
is_flag=True,
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def wipe(connect, bootloader):
|
def wipe(client, bootloader):
|
||||||
"""Reset device to factory defaults and remove all private data."""
|
"""Reset device to factory defaults and remove all private data."""
|
||||||
client = connect()
|
|
||||||
if bootloader:
|
if bootloader:
|
||||||
if not client.features.bootloader_mode:
|
if not client.features.bootloader_mode:
|
||||||
click.echo("Please switch your device to bootloader mode.")
|
click.echo("Please switch your device to bootloader mode.")
|
||||||
@ -82,7 +81,7 @@ def wipe(connect, bootloader):
|
|||||||
click.echo("Wiping user data!")
|
click.echo("Wiping user data!")
|
||||||
|
|
||||||
try:
|
try:
|
||||||
return device.wipe(connect())
|
return device.wipe(client)
|
||||||
except exceptions.TrezorFailure as e:
|
except exceptions.TrezorFailure as e:
|
||||||
click.echo("Action failed: {} {}".format(*e.args))
|
click.echo("Action failed: {} {}".format(*e.args))
|
||||||
sys.exit(3)
|
sys.exit(3)
|
||||||
@ -97,9 +96,9 @@ def wipe(connect, bootloader):
|
|||||||
@click.option("-s", "--slip0014", is_flag=True)
|
@click.option("-s", "--slip0014", is_flag=True)
|
||||||
@click.option("-b", "--needs-backup", is_flag=True)
|
@click.option("-b", "--needs-backup", is_flag=True)
|
||||||
@click.option("-n", "--no-backup", is_flag=True)
|
@click.option("-n", "--no-backup", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def load(
|
def load(
|
||||||
connect,
|
client,
|
||||||
mnemonic,
|
mnemonic,
|
||||||
pin,
|
pin,
|
||||||
passphrase_protection,
|
passphrase_protection,
|
||||||
@ -116,8 +115,6 @@ def load(
|
|||||||
if slip0014 and mnemonic:
|
if slip0014 and mnemonic:
|
||||||
raise click.ClickException("Cannot use -s and -m together.")
|
raise click.ClickException("Cannot use -s and -m together.")
|
||||||
|
|
||||||
client = connect()
|
|
||||||
|
|
||||||
if slip0014:
|
if slip0014:
|
||||||
mnemonic = [" ".join(["all"] * 12)]
|
mnemonic = [" ".join(["all"] * 12)]
|
||||||
if not label:
|
if not label:
|
||||||
@ -147,9 +144,9 @@ def load(
|
|||||||
"-t", "--type", "rec_type", type=ChoiceType(RECOVERY_TYPE), default="scrambled"
|
"-t", "--type", "rec_type", type=ChoiceType(RECOVERY_TYPE), default="scrambled"
|
||||||
)
|
)
|
||||||
@click.option("-d", "--dry-run", is_flag=True)
|
@click.option("-d", "--dry-run", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def recover(
|
def recover(
|
||||||
connect,
|
client,
|
||||||
words,
|
words,
|
||||||
expand,
|
expand,
|
||||||
pin_protection,
|
pin_protection,
|
||||||
@ -167,7 +164,7 @@ def recover(
|
|||||||
click.echo(ui.RECOVERY_MATRIX_DESCRIPTION)
|
click.echo(ui.RECOVERY_MATRIX_DESCRIPTION)
|
||||||
|
|
||||||
return device.recover(
|
return device.recover(
|
||||||
connect(),
|
client,
|
||||||
word_count=int(words),
|
word_count=int(words),
|
||||||
passphrase_protection=passphrase_protection,
|
passphrase_protection=passphrase_protection,
|
||||||
pin_protection=pin_protection,
|
pin_protection=pin_protection,
|
||||||
@ -190,9 +187,9 @@ def recover(
|
|||||||
@click.option("-s", "--skip-backup", is_flag=True)
|
@click.option("-s", "--skip-backup", is_flag=True)
|
||||||
@click.option("-n", "--no-backup", is_flag=True)
|
@click.option("-n", "--no-backup", is_flag=True)
|
||||||
@click.option("-b", "--backup-type", type=ChoiceType(BACKUP_TYPE), default="single")
|
@click.option("-b", "--backup-type", type=ChoiceType(BACKUP_TYPE), default="single")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def setup(
|
def setup(
|
||||||
connect,
|
client,
|
||||||
show_entropy,
|
show_entropy,
|
||||||
strength,
|
strength,
|
||||||
passphrase_protection,
|
passphrase_protection,
|
||||||
@ -207,7 +204,6 @@ def setup(
|
|||||||
if strength:
|
if strength:
|
||||||
strength = int(strength)
|
strength = int(strength)
|
||||||
|
|
||||||
client = connect()
|
|
||||||
if (
|
if (
|
||||||
backup_type == messages.BackupType.Slip39_Basic
|
backup_type == messages.BackupType.Slip39_Basic
|
||||||
and messages.Capability.Shamir not in client.features.capabilities
|
and messages.Capability.Shamir not in client.features.capabilities
|
||||||
@ -236,16 +232,16 @@ def setup(
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def backup(connect):
|
def backup(client):
|
||||||
"""Perform device seed backup."""
|
"""Perform device seed backup."""
|
||||||
return device.backup(connect())
|
return device.backup(client)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("operation", type=ChoiceType(SD_PROTECT_OPERATIONS))
|
@click.argument("operation", type=ChoiceType(SD_PROTECT_OPERATIONS))
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sd_protect(connect, operation):
|
def sd_protect(client, operation):
|
||||||
"""Secure the device with SD card protection.
|
"""Secure the device with SD card protection.
|
||||||
|
|
||||||
When SD card protection is enabled, a randomly generated secret is stored
|
When SD card protection is enabled, a randomly generated secret is stored
|
||||||
@ -259,7 +255,6 @@ def sd_protect(connect, operation):
|
|||||||
disable - Remove SD card secret protection.
|
disable - Remove SD card secret protection.
|
||||||
refresh - Replace the current SD card secret with a new one.
|
refresh - Replace the current SD card secret with a new one.
|
||||||
"""
|
"""
|
||||||
client = connect()
|
|
||||||
if client.features.model == "1":
|
if client.features.model == "1":
|
||||||
raise click.BadUsage("Trezor One does not support SD card protection.")
|
raise click.BadUsage("Trezor One does not support SD card protection.")
|
||||||
return device.sd_protect(client, operation)
|
return device.sd_protect(client, operation)
|
||||||
|
@ -19,6 +19,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import eos, tools
|
from .. import eos, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path, e.g. m/44'/194'/0'/0/0"
|
PATH_HELP = "BIP-32 path, e.g. m/44'/194'/0'/0/0"
|
||||||
|
|
||||||
@ -31,10 +32,9 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_key(connect, address, show_display):
|
def get_public_key(client, address, show_display):
|
||||||
"""Get Eos public key in base58 encoding."""
|
"""Get Eos public key in base58 encoding."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
res = eos.get_public_key(client, address_n, show_display)
|
res = eos.get_public_key(client, address_n, show_display)
|
||||||
return "WIF: {}\nRaw: {}".format(res.wif_public_key, res.raw_public_key.hex())
|
return "WIF: {}\nRaw: {}".format(res.wif_public_key, res.raw_public_key.hex())
|
||||||
@ -49,11 +49,9 @@ def get_public_key(connect, address, show_display):
|
|||||||
required=True,
|
required=True,
|
||||||
help="Transaction in JSON format",
|
help="Transaction in JSON format",
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_transaction(connect, address, file):
|
def sign_transaction(client, address, file):
|
||||||
"""Sign EOS transaction."""
|
"""Sign EOS transaction."""
|
||||||
client = connect()
|
|
||||||
|
|
||||||
tx_json = json.load(file)
|
tx_json = json.load(file)
|
||||||
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
|
@ -21,6 +21,7 @@ from decimal import Decimal
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import ethereum, tools
|
from .. import ethereum, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import rlp
|
import rlp
|
||||||
@ -119,10 +120,9 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Ethereum address in hex encoding."""
|
"""Get Ethereum address in hex encoding."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return ethereum.get_address(client, address_n, show_display)
|
return ethereum.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
@ -130,10 +130,9 @@ def get_address(connect, address, show_display):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_node(connect, address, show_display):
|
def get_public_node(client, address, show_display):
|
||||||
"""Get Ethereum public node of given path."""
|
"""Get Ethereum public node of given path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
result = ethereum.get_public_node(client, address_n, show_display=show_display)
|
result = ethereum.get_public_node(client, address_n, show_display=show_display)
|
||||||
return {
|
return {
|
||||||
@ -179,9 +178,9 @@ def get_public_node(connect, address, show_display):
|
|||||||
)
|
)
|
||||||
@click.argument("to_address")
|
@click.argument("to_address")
|
||||||
@click.argument("amount", callback=_amount_to_int)
|
@click.argument("amount", callback=_amount_to_int)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(
|
def sign_tx(
|
||||||
connect,
|
client,
|
||||||
chain_id,
|
chain_id,
|
||||||
address,
|
address,
|
||||||
amount,
|
amount,
|
||||||
@ -234,7 +233,6 @@ def sign_tx(
|
|||||||
click.echo("Can't send tokens and custom data at the same time")
|
click.echo("Can't send tokens and custom data at the same time")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
from_address = ethereum.get_address(client, address_n)
|
from_address = ethereum.get_address(client, address_n)
|
||||||
|
|
||||||
@ -296,10 +294,9 @@ def sign_tx(
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_message(connect, address, message):
|
def sign_message(client, address, message):
|
||||||
"""Sign message with Ethereum address."""
|
"""Sign message with Ethereum address."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
ret = ethereum.sign_message(client, address_n, message)
|
ret = ethereum.sign_message(client, address_n, message)
|
||||||
output = {
|
output = {
|
||||||
@ -314,8 +311,8 @@ def sign_message(connect, address, message):
|
|||||||
@click.argument("address")
|
@click.argument("address")
|
||||||
@click.argument("signature")
|
@click.argument("signature")
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def verify_message(connect, address, signature, message):
|
def verify_message(client, address, signature, message):
|
||||||
"""Verify message signed with Ethereum address."""
|
"""Verify message signed with Ethereum address."""
|
||||||
signature = _decode_hex(signature)
|
signature = _decode_hex(signature)
|
||||||
return ethereum.verify_message(connect(), address, signature, message)
|
return ethereum.verify_message(client, address, signature, message)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import fido
|
from .. import fido
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
ALGORITHM_NAME = {-7: "ES256 (ECDSA w/ SHA-256)", -8: "EdDSA"}
|
ALGORITHM_NAME = {-7: "ES256 (ECDSA w/ SHA-256)", -8: "EdDSA"}
|
||||||
|
|
||||||
@ -34,11 +35,10 @@ def credentials():
|
|||||||
|
|
||||||
|
|
||||||
@credentials.command(name="list")
|
@credentials.command(name="list")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def credentials_list(connect):
|
def credentials_list(client):
|
||||||
"""List all resident credentials on the device."""
|
"""List all resident credentials on the device."""
|
||||||
|
creds = fido.list_credentials(client)
|
||||||
creds = fido.list_credentials(connect())
|
|
||||||
for cred in creds:
|
for cred in creds:
|
||||||
click.echo("")
|
click.echo("")
|
||||||
click.echo("WebAuthn credential at index {}:".format(cred.index))
|
click.echo("WebAuthn credential at index {}:".format(cred.index))
|
||||||
@ -72,23 +72,23 @@ def credentials_list(connect):
|
|||||||
|
|
||||||
@credentials.command(name="add")
|
@credentials.command(name="add")
|
||||||
@click.argument("hex_credential_id")
|
@click.argument("hex_credential_id")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def credentials_add(connect, hex_credential_id):
|
def credentials_add(client, hex_credential_id):
|
||||||
"""Add the credential with the given ID as a resident credential.
|
"""Add the credential with the given ID as a resident credential.
|
||||||
|
|
||||||
HEX_CREDENTIAL_ID is the credential ID as a hexadecimal string.
|
HEX_CREDENTIAL_ID is the credential ID as a hexadecimal string.
|
||||||
"""
|
"""
|
||||||
return fido.add_credential(connect(), bytes.fromhex(hex_credential_id))
|
return fido.add_credential(client, bytes.fromhex(hex_credential_id))
|
||||||
|
|
||||||
|
|
||||||
@credentials.command(name="remove")
|
@credentials.command(name="remove")
|
||||||
@click.option(
|
@click.option(
|
||||||
"-i", "--index", required=True, type=click.IntRange(0, 99), help="Credential index."
|
"-i", "--index", required=True, type=click.IntRange(0, 99), help="Credential index."
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def credentials_remove(connect, index):
|
def credentials_remove(client, index):
|
||||||
"""Remove the resident credential at the given index."""
|
"""Remove the resident credential at the given index."""
|
||||||
return fido.remove_credential(connect(), index)
|
return fido.remove_credential(client, index)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -103,19 +103,19 @@ def counter():
|
|||||||
|
|
||||||
@counter.command(name="set")
|
@counter.command(name="set")
|
||||||
@click.argument("counter", type=int)
|
@click.argument("counter", type=int)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def counter_set(connect, counter):
|
def counter_set(client, counter):
|
||||||
"""Set FIDO/U2F counter value."""
|
"""Set FIDO/U2F counter value."""
|
||||||
return fido.set_counter(connect(), counter)
|
return fido.set_counter(client, counter)
|
||||||
|
|
||||||
|
|
||||||
@counter.command(name="get-next")
|
@counter.command(name="get-next")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def counter_get_next(connect):
|
def counter_get_next(client):
|
||||||
"""Get-and-increase value of FIDO/U2F counter.
|
"""Get-and-increase value of FIDO/U2F counter.
|
||||||
|
|
||||||
FIDO counter value cannot be read directly. On each U2F exchange, the counter value
|
FIDO counter value cannot be read directly. On each U2F exchange, the counter value
|
||||||
is returned and atomically increased. This command performs the same operation
|
is returned and atomically increased. This command performs the same operation
|
||||||
and returns the counter value.
|
and returns the counter value.
|
||||||
"""
|
"""
|
||||||
return fido.get_next_counter(connect())
|
return fido.get_next_counter(client)
|
||||||
|
@ -20,6 +20,7 @@ import click
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from .. import exceptions, firmware
|
from .. import exceptions, firmware
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
ALLOWED_FIRMWARE_FORMATS = {
|
ALLOWED_FIRMWARE_FORMATS = {
|
||||||
1: (firmware.FirmwareFormat.TREZOR_ONE, firmware.FirmwareFormat.TREZOR_ONE_V2),
|
1: (firmware.FirmwareFormat.TREZOR_ONE, firmware.FirmwareFormat.TREZOR_ONE_V2),
|
||||||
@ -173,9 +174,9 @@ def find_best_firmware_version(
|
|||||||
@click.option("--fingerprint", help="Expected firmware fingerprint in hex")
|
@click.option("--fingerprint", help="Expected firmware fingerprint in hex")
|
||||||
@click.option("--skip-vendor-header", help="Skip vendor header validation on Trezor T")
|
@click.option("--skip-vendor-header", help="Skip vendor header validation on Trezor T")
|
||||||
# fmt: on
|
# fmt: on
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def firmware_update(
|
def firmware_update(
|
||||||
connect,
|
client,
|
||||||
filename,
|
filename,
|
||||||
url,
|
url,
|
||||||
version,
|
version,
|
||||||
@ -207,7 +208,6 @@ def firmware_update(
|
|||||||
click.echo("You can use only one of: filename, url, version.")
|
click.echo("You can use only one of: filename, url, version.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
client = connect()
|
|
||||||
if not dry_run and not client.features.bootloader_mode:
|
if not dry_run and not client.features.bootloader_mode:
|
||||||
click.echo("Please switch your device to bootloader mode.")
|
click.echo("Please switch your device to bootloader mode.")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -19,6 +19,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import lisk, tools
|
from .. import lisk, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path, e.g. m/44'/134'/0'/0'"
|
PATH_HELP = "BIP-32 path, e.g. m/44'/134'/0'/0'"
|
||||||
|
|
||||||
@ -31,10 +32,9 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Lisk address for specified path."""
|
"""Get Lisk address for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return lisk.get_address(client, address_n, show_display)
|
return lisk.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
@ -42,10 +42,9 @@ def get_address(connect, address, show_display):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_key(connect, address, show_display):
|
def get_public_key(client, address, show_display):
|
||||||
"""Get Lisk public key for specified path."""
|
"""Get Lisk public key for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
res = lisk.get_public_key(client, address_n, show_display)
|
res = lisk.get_public_key(client, address_n, show_display)
|
||||||
output = {"public_key": res.public_key.hex()}
|
output = {"public_key": res.public_key.hex()}
|
||||||
@ -58,10 +57,9 @@ def get_public_key(connect, address, show_display):
|
|||||||
"-f", "--file", type=click.File("r"), default="-", help="Transaction in JSON format"
|
"-f", "--file", type=click.File("r"), default="-", help="Transaction in JSON format"
|
||||||
)
|
)
|
||||||
# @click.option('-b', '--broadcast', help='Broadcast Lisk transaction')
|
# @click.option('-b', '--broadcast', help='Broadcast Lisk transaction')
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, address, file):
|
def sign_tx(client, address, file):
|
||||||
"""Sign Lisk transaction."""
|
"""Sign Lisk transaction."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
transaction = lisk.sign_tx(client, address_n, json.load(file))
|
transaction = lisk.sign_tx(client, address_n, json.load(file))
|
||||||
|
|
||||||
@ -73,10 +71,9 @@ def sign_tx(connect, address, file):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_message(connect, address, message):
|
def sign_message(client, address, message):
|
||||||
"""Sign message with Lisk address."""
|
"""Sign message with Lisk address."""
|
||||||
client = connect()
|
|
||||||
address_n = client.expand_path(address)
|
address_n = client.expand_path(address)
|
||||||
res = lisk.sign_message(client, address_n, message)
|
res = lisk.sign_message(client, address_n, message)
|
||||||
output = {
|
output = {
|
||||||
@ -91,9 +88,9 @@ def sign_message(connect, address, message):
|
|||||||
@click.argument("pubkey")
|
@click.argument("pubkey")
|
||||||
@click.argument("signature")
|
@click.argument("signature")
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def verify_message(connect, pubkey, signature, message):
|
def verify_message(client, pubkey, signature, message):
|
||||||
"""Verify message signed with Lisk address."""
|
"""Verify message signed with Lisk address."""
|
||||||
signature = bytes.fromhex(signature)
|
signature = bytes.fromhex(signature)
|
||||||
pubkey = bytes.fromhex(pubkey)
|
pubkey = bytes.fromhex(pubkey)
|
||||||
return lisk.verify_message(connect(), pubkey, signature, message)
|
return lisk.verify_message(client, pubkey, signature, message)
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import monero, tools
|
from .. import monero, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path, e.g. m/44'/128'/0'"
|
PATH_HELP = "BIP-32 path, e.g. m/44'/128'/0'"
|
||||||
|
|
||||||
@ -32,10 +33,9 @@ def cli():
|
|||||||
@click.option(
|
@click.option(
|
||||||
"-t", "--network-type", type=click.Choice(["0", "1", "2", "3"]), default="0"
|
"-t", "--network-type", type=click.Choice(["0", "1", "2", "3"]), default="0"
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display, network_type):
|
def get_address(client, address, show_display, network_type):
|
||||||
"""Get Monero address for specified path."""
|
"""Get Monero address for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
network_type = int(network_type)
|
network_type = int(network_type)
|
||||||
return monero.get_address(client, address_n, show_display, network_type)
|
return monero.get_address(client, address_n, show_display, network_type)
|
||||||
@ -46,10 +46,9 @@ def get_address(connect, address, show_display, network_type):
|
|||||||
@click.option(
|
@click.option(
|
||||||
"-t", "--network-type", type=click.Choice(["0", "1", "2", "3"]), default="0"
|
"-t", "--network-type", type=click.Choice(["0", "1", "2", "3"]), default="0"
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_watch_key(connect, address, network_type):
|
def get_watch_key(client, address, network_type):
|
||||||
"""Get Monero watch key for specified path."""
|
"""Get Monero watch key for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
network_type = int(network_type)
|
network_type = int(network_type)
|
||||||
res = monero.get_watch_key(client, address_n, network_type)
|
res = monero.get_watch_key(client, address_n, network_type)
|
||||||
|
@ -20,6 +20,7 @@ import click
|
|||||||
import requests
|
import requests
|
||||||
|
|
||||||
from .. import nem, tools
|
from .. import nem, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path, e.g. m/44'/134'/0'/0'"
|
PATH_HELP = "BIP-32 path, e.g. m/44'/134'/0'/0'"
|
||||||
|
|
||||||
@ -33,10 +34,9 @@ def cli():
|
|||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-N", "--network", type=int, default=0x68)
|
@click.option("-N", "--network", type=int, default=0x68)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, network, show_display):
|
def get_address(client, address, network, show_display):
|
||||||
"""Get NEM address for specified path."""
|
"""Get NEM address for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return nem.get_address(client, address_n, network, show_display)
|
return nem.get_address(client, address_n, network, show_display)
|
||||||
|
|
||||||
@ -51,10 +51,9 @@ def get_address(connect, address, network, show_display):
|
|||||||
help="Transaction in NIS (RequestPrepareAnnounce) format",
|
help="Transaction in NIS (RequestPrepareAnnounce) format",
|
||||||
)
|
)
|
||||||
@click.option("-b", "--broadcast", help="NIS to announce transaction to")
|
@click.option("-b", "--broadcast", help="NIS to announce transaction to")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, address, file, broadcast):
|
def sign_tx(client, address, file, broadcast):
|
||||||
"""Sign (and optionally broadcast) NEM transaction."""
|
"""Sign (and optionally broadcast) NEM transaction."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
transaction = nem.sign_tx(client, address_n, json.load(file))
|
transaction = nem.sign_tx(client, address_n, json.load(file))
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import ripple, tools
|
from .. import ripple, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path to key, e.g. m/44'/144'/0'/0/0"
|
PATH_HELP = "BIP-32 path to key, e.g. m/44'/144'/0'/0/0"
|
||||||
|
|
||||||
@ -31,10 +32,9 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Ripple address"""
|
"""Get Ripple address"""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return ripple.get_address(client, address_n, show_display)
|
return ripple.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
@ -44,10 +44,9 @@ def get_address(connect, address, show_display):
|
|||||||
@click.option(
|
@click.option(
|
||||||
"-f", "--file", type=click.File("r"), default="-", help="Transaction in JSON format"
|
"-f", "--file", type=click.File("r"), default="-", help="Transaction in JSON format"
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, address, file):
|
def sign_tx(client, address, file):
|
||||||
"""Sign Ripple transaction"""
|
"""Sign Ripple transaction"""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
msg = ripple.create_sign_tx_msg(json.load(file))
|
msg = ripple.create_sign_tx_msg(json.load(file))
|
||||||
|
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import device
|
from .. import device
|
||||||
from . import ChoiceType
|
from . import ChoiceType, with_client
|
||||||
|
|
||||||
ROTATION = {"north": 0, "east": 90, "south": 180, "west": 270}
|
ROTATION = {"north": 0, "east": 90, "south": 180, "west": 270}
|
||||||
|
|
||||||
@ -29,51 +29,51 @@ def cli():
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-r", "--remove", is_flag=True)
|
@click.option("-r", "--remove", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def pin(connect, remove):
|
def pin(client, remove):
|
||||||
"""Set, change or remove PIN."""
|
"""Set, change or remove PIN."""
|
||||||
return device.change_pin(connect(), remove)
|
return device.change_pin(client, remove)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-r", "--remove", is_flag=True)
|
@click.option("-r", "--remove", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def wipe_code(connect, remove):
|
def wipe_code(client, remove):
|
||||||
"""Set or remove the wipe code.
|
"""Set or remove the wipe code.
|
||||||
|
|
||||||
The wipe code functions as a "self-destruct PIN". If the wipe code is ever
|
The wipe code functions as a "self-destruct PIN". If the wipe code is ever
|
||||||
entered into any PIN entry dialog, then all private data will be immediately
|
entered into any PIN entry dialog, then all private data will be immediately
|
||||||
removed and the device will be reset to factory defaults.
|
removed and the device will be reset to factory defaults.
|
||||||
"""
|
"""
|
||||||
return device.change_wipe_code(connect(), remove)
|
return device.change_wipe_code(client, remove)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
# keep the deprecated -l/--label option, make it do nothing
|
# keep the deprecated -l/--label option, make it do nothing
|
||||||
@click.option("-l", "--label", "_ignore", is_flag=True, hidden=True, expose_value=False)
|
@click.option("-l", "--label", "_ignore", is_flag=True, hidden=True, expose_value=False)
|
||||||
@click.argument("label")
|
@click.argument("label")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def label(connect, label):
|
def label(client, label):
|
||||||
"""Set new device label."""
|
"""Set new device label."""
|
||||||
return device.apply_settings(connect(), label=label)
|
return device.apply_settings(client, label=label)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("rotation", type=ChoiceType(ROTATION))
|
@click.argument("rotation", type=ChoiceType(ROTATION))
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def display_rotation(connect, rotation):
|
def display_rotation(client, rotation):
|
||||||
"""Set display rotation.
|
"""Set display rotation.
|
||||||
|
|
||||||
Configure display rotation for Trezor Model T. The options are
|
Configure display rotation for Trezor Model T. The options are
|
||||||
north, east, south or west.
|
north, east, south or west.
|
||||||
"""
|
"""
|
||||||
return device.apply_settings(connect(), display_rotation=rotation)
|
return device.apply_settings(client, display_rotation=rotation)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("delay", type=str)
|
@click.argument("delay", type=str)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def auto_lock_delay(connect, delay):
|
def auto_lock_delay(client, delay):
|
||||||
"""Set auto-lock delay (in seconds)."""
|
"""Set auto-lock delay (in seconds)."""
|
||||||
value, unit = delay[:-1], delay[-1:]
|
value, unit = delay[:-1], delay[-1:]
|
||||||
units = {"s": 1, "m": 60, "h": 3600}
|
units = {"s": 1, "m": 60, "h": 3600}
|
||||||
@ -81,13 +81,13 @@ def auto_lock_delay(connect, delay):
|
|||||||
seconds = float(value) * units[unit]
|
seconds = float(value) * units[unit]
|
||||||
else:
|
else:
|
||||||
seconds = float(delay) # assume seconds if no unit is specified
|
seconds = float(delay) # assume seconds if no unit is specified
|
||||||
return device.apply_settings(connect(), auto_lock_delay_ms=int(seconds * 1000))
|
return device.apply_settings(client, auto_lock_delay_ms=int(seconds * 1000))
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("flags")
|
@click.argument("flags")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def flags(connect, flags):
|
def flags(client, flags):
|
||||||
"""Set device flags."""
|
"""Set device flags."""
|
||||||
flags = flags.lower()
|
flags = flags.lower()
|
||||||
if flags.startswith("0b"):
|
if flags.startswith("0b"):
|
||||||
@ -96,13 +96,13 @@ def flags(connect, flags):
|
|||||||
flags = int(flags, 16)
|
flags = int(flags, 16)
|
||||||
else:
|
else:
|
||||||
flags = int(flags)
|
flags = int(flags)
|
||||||
return device.apply_flags(connect(), flags=flags)
|
return device.apply_flags(client, flags=flags)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-f", "--filename", default=None)
|
@click.option("-f", "--filename", default=None)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def homescreen(connect, filename):
|
def homescreen(client, filename):
|
||||||
"""Set new homescreen."""
|
"""Set new homescreen."""
|
||||||
if filename is None:
|
if filename is None:
|
||||||
img = b"\x00"
|
img = b"\x00"
|
||||||
@ -125,7 +125,7 @@ def homescreen(connect, filename):
|
|||||||
o = i + j * 128
|
o = i + j * 128
|
||||||
img[o // 8] |= 1 << (7 - o % 8)
|
img[o // 8] |= 1 << (7 - o % 8)
|
||||||
img = bytes(img)
|
img = bytes(img)
|
||||||
return device.apply_settings(connect(), homescreen=img)
|
return device.apply_settings(client, homescreen=img)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
@ -140,16 +140,16 @@ def passphrase():
|
|||||||
|
|
||||||
@passphrase.command(name="enabled")
|
@passphrase.command(name="enabled")
|
||||||
@click.option("-f/-F", "--force-on-device/--no-force-on-device", default=None)
|
@click.option("-f/-F", "--force-on-device/--no-force-on-device", default=None)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def passphrase_enable(connect, force_on_device: bool):
|
def passphrase_enable(client, force_on_device: bool):
|
||||||
"""Enable passphrase."""
|
"""Enable passphrase."""
|
||||||
return device.apply_settings(
|
return device.apply_settings(
|
||||||
connect(), use_passphrase=True, passphrase_always_on_device=force_on_device
|
client, use_passphrase=True, passphrase_always_on_device=force_on_device
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@passphrase.command(name="disabled")
|
@passphrase.command(name="disabled")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def passphrase_disable(connect):
|
def passphrase_disable(client):
|
||||||
"""Disable passphrase."""
|
"""Disable passphrase."""
|
||||||
return device.apply_settings(connect(), use_passphrase=False)
|
return device.apply_settings(client, use_passphrase=False)
|
||||||
|
@ -19,6 +19,7 @@ import base64
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import stellar, tools
|
from .. import stellar, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP32 path. Always use hardened paths and the m/44'/148'/ prefix"
|
PATH_HELP = "BIP32 path. Always use hardened paths and the m/44'/148'/ prefix"
|
||||||
|
|
||||||
@ -37,10 +38,9 @@ def cli():
|
|||||||
default=stellar.DEFAULT_BIP32_PATH,
|
default=stellar.DEFAULT_BIP32_PATH,
|
||||||
)
|
)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Stellar public address."""
|
"""Get Stellar public address."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return stellar.get_address(client, address_n, show_display)
|
return stellar.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
@ -61,14 +61,13 @@ def get_address(connect, address, show_display):
|
|||||||
help="Network passphrase (blank for public network).",
|
help="Network passphrase (blank for public network).",
|
||||||
)
|
)
|
||||||
@click.argument("b64envelope")
|
@click.argument("b64envelope")
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_transaction(connect, b64envelope, address, network_passphrase):
|
def sign_transaction(client, b64envelope, address, network_passphrase):
|
||||||
"""Sign a base64-encoded transaction envelope.
|
"""Sign a base64-encoded transaction envelope.
|
||||||
|
|
||||||
For testnet transactions, use the following network passphrase:
|
For testnet transactions, use the following network passphrase:
|
||||||
'Test SDF Network ; September 2015'
|
'Test SDF Network ; September 2015'
|
||||||
"""
|
"""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
tx, operations = stellar.parse_transaction_bytes(base64.b64decode(b64envelope))
|
tx, operations = stellar.parse_transaction_bytes(base64.b64decode(b64envelope))
|
||||||
resp = stellar.sign_tx(client, tx, operations, address_n, network_passphrase)
|
resp = stellar.sign_tx(client, tx, operations, address_n, network_passphrase)
|
||||||
|
@ -19,6 +19,7 @@ import json
|
|||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import messages, protobuf, tezos, tools
|
from .. import messages, protobuf, tezos, tools
|
||||||
|
from . import with_client
|
||||||
|
|
||||||
PATH_HELP = "BIP-32 path, e.g. m/44'/1729'/0'"
|
PATH_HELP = "BIP-32 path, e.g. m/44'/1729'/0'"
|
||||||
|
|
||||||
@ -31,10 +32,9 @@ def cli():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_address(connect, address, show_display):
|
def get_address(client, address, show_display):
|
||||||
"""Get Tezos address for specified path."""
|
"""Get Tezos address for specified path."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return tezos.get_address(client, address_n, show_display)
|
return tezos.get_address(client, address_n, show_display)
|
||||||
|
|
||||||
@ -42,10 +42,9 @@ def get_address(connect, address, show_display):
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
@click.option("-n", "--address", required=True, help=PATH_HELP)
|
||||||
@click.option("-d", "--show-display", is_flag=True)
|
@click.option("-d", "--show-display", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_public_key(connect, address, show_display):
|
def get_public_key(client, address, show_display):
|
||||||
"""Get Tezos public key."""
|
"""Get Tezos public key."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
return tezos.get_public_key(client, address_n, show_display)
|
return tezos.get_public_key(client, address_n, show_display)
|
||||||
|
|
||||||
@ -59,10 +58,9 @@ def get_public_key(connect, address, show_display):
|
|||||||
default="-",
|
default="-",
|
||||||
help="Transaction in JSON format (byte fields should be hexlified)",
|
help="Transaction in JSON format (byte fields should be hexlified)",
|
||||||
)
|
)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def sign_tx(connect, address, file):
|
def sign_tx(client, address, file):
|
||||||
"""Sign Tezos transaction."""
|
"""Sign Tezos transaction."""
|
||||||
client = connect()
|
|
||||||
address_n = tools.parse_path(address)
|
address_n = tools.parse_path(address)
|
||||||
msg = protobuf.dict_to_proto(messages.TezosSignTx, json.load(file))
|
msg = protobuf.dict_to_proto(messages.TezosSignTx, json.load(file))
|
||||||
return tezos.sign_tx(client, address_n, msg)
|
return tezos.sign_tx(client, address_n, msg)
|
||||||
|
@ -17,17 +17,18 @@
|
|||||||
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
# If not, see <https://www.gnu.org/licenses/lgpl-3.0.html>.
|
||||||
|
|
||||||
import json
|
import json
|
||||||
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import time
|
import time
|
||||||
|
|
||||||
import click
|
import click
|
||||||
|
|
||||||
from .. import log, messages, protobuf, ui
|
from .. import log, messages, protobuf, ui
|
||||||
from ..client import TrezorClient
|
from ..client import TrezorClient
|
||||||
from ..transport import enumerate_devices, get_transport
|
from ..transport import enumerate_devices
|
||||||
from ..transport.udp import UdpTransport
|
from ..transport.udp import UdpTransport
|
||||||
from . import (
|
from . import (
|
||||||
|
TrezorConnection,
|
||||||
binance,
|
binance,
|
||||||
btc,
|
btc,
|
||||||
cardano,
|
cardano,
|
||||||
@ -46,8 +47,11 @@ from . import (
|
|||||||
settings,
|
settings,
|
||||||
stellar,
|
stellar,
|
||||||
tezos,
|
tezos,
|
||||||
|
with_client,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
COMMAND_ALIASES = {
|
COMMAND_ALIASES = {
|
||||||
"change-pin": settings.pin,
|
"change-pin": settings.pin,
|
||||||
"enable-passphrase": settings.passphrase_enable,
|
"enable-passphrase": settings.passphrase_enable,
|
||||||
@ -157,26 +161,7 @@ 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(return_transport=False):
|
ctx.obj = TrezorConnection(path, session_id, passphrase_on_host)
|
||||||
try:
|
|
||||||
transport = get_transport(path, prefix_search=False)
|
|
||||||
except Exception:
|
|
||||||
try:
|
|
||||||
transport = get_transport(path, prefix_search=True)
|
|
||||||
except Exception:
|
|
||||||
click.echo("Failed to find a Trezor device.")
|
|
||||||
if path is not None:
|
|
||||||
click.echo("Using path: {}".format(path))
|
|
||||||
sys.exit(1)
|
|
||||||
if return_transport:
|
|
||||||
return transport
|
|
||||||
return TrezorClient(
|
|
||||||
transport=transport,
|
|
||||||
ui=ui.ClickUI(passphrase_on_host=passphrase_on_host),
|
|
||||||
session_id=session_id,
|
|
||||||
)
|
|
||||||
|
|
||||||
ctx.obj = get_device
|
|
||||||
|
|
||||||
|
|
||||||
@cli.resultcallback()
|
@cli.resultcallback()
|
||||||
@ -211,6 +196,7 @@ def format_device_name(features):
|
|||||||
label = features.label or "(unnamed)"
|
label = features.label or "(unnamed)"
|
||||||
return "{} [Trezor {}, {}]".format(label, model, features.device_id)
|
return "{} [Trezor {}, {}]".format(label, model, features.device_id)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Common functions
|
# Common functions
|
||||||
#
|
#
|
||||||
@ -244,15 +230,15 @@ def version():
|
|||||||
@cli.command()
|
@cli.command()
|
||||||
@click.argument("message")
|
@click.argument("message")
|
||||||
@click.option("-b", "--button-protection", is_flag=True)
|
@click.option("-b", "--button-protection", is_flag=True)
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def ping(connect, message, button_protection):
|
def ping(client, message, button_protection):
|
||||||
"""Send ping message."""
|
"""Send ping message."""
|
||||||
return connect().ping(message, button_protection=button_protection)
|
return client.ping(message, button_protection=button_protection)
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_session(connect):
|
def get_session(client):
|
||||||
"""Get a session ID for subsequent commands.
|
"""Get a session ID for subsequent commands.
|
||||||
|
|
||||||
Unlocks Trezor with a passphrase and returns a session ID. Use this session ID with
|
Unlocks Trezor with a passphrase and returns a session ID. Use this session ID with
|
||||||
@ -265,7 +251,6 @@ def get_session(connect):
|
|||||||
from ..btc import get_address
|
from ..btc import get_address
|
||||||
from ..client import PASSPHRASE_TEST_PATH
|
from ..client import PASSPHRASE_TEST_PATH
|
||||||
|
|
||||||
client = connect()
|
|
||||||
if client.features.model == "1" and client.version < (1, 9, 0):
|
if client.features.model == "1" and client.version < (1, 9, 0):
|
||||||
raise click.ClickException("Upgrade your firmware to enable session support.")
|
raise click.ClickException("Upgrade your firmware to enable session support.")
|
||||||
|
|
||||||
@ -277,17 +262,17 @@ def get_session(connect):
|
|||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def clear_session(connect):
|
def clear_session(client):
|
||||||
"""Clear session (remove cached PIN, passphrase, etc.)."""
|
"""Clear session (remove cached PIN, passphrase, etc.)."""
|
||||||
return connect().clear_session()
|
return client.clear_session()
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.pass_obj
|
@with_client
|
||||||
def get_features(connect):
|
def get_features(client):
|
||||||
"""Retrieve device features and settings."""
|
"""Retrieve device features and settings."""
|
||||||
return connect().features
|
return client.features
|
||||||
|
|
||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@ -304,13 +289,13 @@ def usb_reset():
|
|||||||
|
|
||||||
@cli.command()
|
@cli.command()
|
||||||
@click.option("-t", "--timeout", type=float, default=10, help="Timeout in seconds")
|
@click.option("-t", "--timeout", type=float, default=10, help="Timeout in seconds")
|
||||||
@click.pass_context
|
@click.pass_obj
|
||||||
def wait_for_emulator(ctx, timeout):
|
def wait_for_emulator(obj, timeout):
|
||||||
"""Wait until Trezor Emulator comes up.
|
"""Wait until Trezor Emulator comes up.
|
||||||
|
|
||||||
Tries to connect to emulator and returns when it succeeds.
|
Tries to connect to emulator and returns when it succeeds.
|
||||||
"""
|
"""
|
||||||
path = ctx.parent.params.get("path")
|
path = obj.path
|
||||||
if path:
|
if path:
|
||||||
if not path.startswith("udp:"):
|
if not path.startswith("udp:"):
|
||||||
raise click.ClickException("You must use UDP path, not {}".format(path))
|
raise click.ClickException("You must use UDP path, not {}".format(path))
|
||||||
@ -320,8 +305,7 @@ def wait_for_emulator(ctx, timeout):
|
|||||||
UdpTransport(path).wait_until_ready(timeout)
|
UdpTransport(path).wait_until_ready(timeout)
|
||||||
end = time.monotonic()
|
end = time.monotonic()
|
||||||
|
|
||||||
if ctx.parent.params.get("verbose"):
|
LOG.info("Waited for {:.3f} seconds".format(end - start))
|
||||||
click.echo("Waited for {:.3f} seconds".format(end - start))
|
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -21,8 +21,6 @@ import struct
|
|||||||
import unicodedata
|
import unicodedata
|
||||||
from typing import List, NewType
|
from typing import List, NewType
|
||||||
|
|
||||||
from .exceptions import TrezorFailure
|
|
||||||
|
|
||||||
HARDENED_FLAG = 1 << 31
|
HARDENED_FLAG = 1 << 31
|
||||||
|
|
||||||
Address = NewType("Address", List[int])
|
Address = NewType("Address", List[int])
|
||||||
|
Loading…
Reference in New Issue
Block a user