|
|
@ -88,6 +88,18 @@ class expect(object):
|
|
|
|
return ret
|
|
|
|
return ret
|
|
|
|
return wrapped_f
|
|
|
|
return wrapped_f
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def session(f):
|
|
|
|
|
|
|
|
# Decorator wraps a BaseClient method
|
|
|
|
|
|
|
|
# with session activation / deactivation
|
|
|
|
|
|
|
|
def wrapped_f(*args, **kwargs):
|
|
|
|
|
|
|
|
client = args[0]
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
client.transport.session_begin()
|
|
|
|
|
|
|
|
return f(*args, **kwargs)
|
|
|
|
|
|
|
|
finally:
|
|
|
|
|
|
|
|
client.transport.session_end()
|
|
|
|
|
|
|
|
return wrapped_f
|
|
|
|
|
|
|
|
|
|
|
|
def normalize_nfc(txt):
|
|
|
|
def normalize_nfc(txt):
|
|
|
|
if sys.version_info[0] < 3:
|
|
|
|
if sys.version_info[0] < 3:
|
|
|
|
if isinstance(txt, unicode):
|
|
|
|
if isinstance(txt, unicode):
|
|
|
@ -112,20 +124,13 @@ class BaseClient(object):
|
|
|
|
def cancel(self):
|
|
|
|
def cancel(self):
|
|
|
|
self.transport.write(proto.Cancel())
|
|
|
|
self.transport.write(proto.Cancel())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@session
|
|
|
|
def call_raw(self, msg):
|
|
|
|
def call_raw(self, msg):
|
|
|
|
try:
|
|
|
|
|
|
|
|
self.transport.session_begin()
|
|
|
|
|
|
|
|
self.transport.write(msg)
|
|
|
|
self.transport.write(msg)
|
|
|
|
resp = self.transport.read_blocking()
|
|
|
|
return self.transport.read_blocking()
|
|
|
|
finally:
|
|
|
|
|
|
|
|
self.transport.session_end()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return resp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@session
|
|
|
|
def call(self, msg):
|
|
|
|
def call(self, msg):
|
|
|
|
try:
|
|
|
|
|
|
|
|
self.transport.session_begin()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
resp = self.call_raw(msg)
|
|
|
|
resp = self.call_raw(msg)
|
|
|
|
handler_name = "callback_%s" % resp.__class__.__name__
|
|
|
|
handler_name = "callback_%s" % resp.__class__.__name__
|
|
|
|
handler = getattr(self, handler_name, None)
|
|
|
|
handler = getattr(self, handler_name, None)
|
|
|
@ -134,12 +139,8 @@ class BaseClient(object):
|
|
|
|
msg = handler(resp)
|
|
|
|
msg = handler(resp)
|
|
|
|
if msg == None:
|
|
|
|
if msg == None:
|
|
|
|
raise Exception("Callback %s must return protobuf message, not None" % handler)
|
|
|
|
raise Exception("Callback %s must return protobuf message, not None" % handler)
|
|
|
|
|
|
|
|
|
|
|
|
resp = self.call(msg)
|
|
|
|
resp = self.call(msg)
|
|
|
|
|
|
|
|
|
|
|
|
finally:
|
|
|
|
|
|
|
|
self.transport.session_end()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return resp
|
|
|
|
return resp
|
|
|
|
|
|
|
|
|
|
|
|
def callback_Failure(self, msg):
|
|
|
|
def callback_Failure(self, msg):
|
|
|
@ -423,6 +424,7 @@ class ProtocolMixin(object):
|
|
|
|
n = self._convert_prime(n)
|
|
|
|
n = self._convert_prime(n)
|
|
|
|
return self.call(proto.EthereumGetAddress(address_n=n, show_display=show_display))
|
|
|
|
return self.call(proto.EthereumGetAddress(address_n=n, show_display=show_display))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@session
|
|
|
|
def ethereum_sign_tx(self, n, nonce, gas_price, gas_limit, to, value, data=None):
|
|
|
|
def ethereum_sign_tx(self, n, nonce, gas_price, gas_limit, to, value, data=None):
|
|
|
|
def int_to_big_endian(value):
|
|
|
|
def int_to_big_endian(value):
|
|
|
|
import rlp.utils
|
|
|
|
import rlp.utils
|
|
|
@ -432,9 +434,6 @@ class ProtocolMixin(object):
|
|
|
|
|
|
|
|
|
|
|
|
n = self._convert_prime(n)
|
|
|
|
n = self._convert_prime(n)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
self.transport.session_begin()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
msg = proto.EthereumSignTx(
|
|
|
|
msg = proto.EthereumSignTx(
|
|
|
|
address_n=n,
|
|
|
|
address_n=n,
|
|
|
|
nonce=int_to_big_endian(nonce),
|
|
|
|
nonce=int_to_big_endian(nonce),
|
|
|
@ -459,8 +458,6 @@ class ProtocolMixin(object):
|
|
|
|
|
|
|
|
|
|
|
|
return response.signature_v, response.signature_r, response.signature_s
|
|
|
|
return response.signature_v, response.signature_r, response.signature_s
|
|
|
|
|
|
|
|
|
|
|
|
finally:
|
|
|
|
|
|
|
|
self.transport.session_end()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@field('entropy')
|
|
|
|
@field('entropy')
|
|
|
|
@expect(proto.Entropy)
|
|
|
|
@expect(proto.Entropy)
|
|
|
@ -634,14 +631,12 @@ class ProtocolMixin(object):
|
|
|
|
|
|
|
|
|
|
|
|
return txes
|
|
|
|
return txes
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@session
|
|
|
|
def sign_tx(self, coin_name, inputs, outputs, debug_processor=None):
|
|
|
|
def sign_tx(self, coin_name, inputs, outputs, debug_processor=None):
|
|
|
|
|
|
|
|
|
|
|
|
start = time.time()
|
|
|
|
start = time.time()
|
|
|
|
txes = self._prepare_sign_tx(coin_name, inputs, outputs)
|
|
|
|
txes = self._prepare_sign_tx(coin_name, inputs, outputs)
|
|
|
|
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
|
|
|
self.transport.session_begin()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# Prepare and send initial message
|
|
|
|
# Prepare and send initial message
|
|
|
|
tx = proto.SignTx()
|
|
|
|
tx = proto.SignTx()
|
|
|
|
tx.inputs_count = len(inputs)
|
|
|
|
tx.inputs_count = len(inputs)
|
|
|
@ -714,9 +709,6 @@ class ProtocolMixin(object):
|
|
|
|
res = self.call(proto.TxAck(tx=msg))
|
|
|
|
res = self.call(proto.TxAck(tx=msg))
|
|
|
|
continue
|
|
|
|
continue
|
|
|
|
|
|
|
|
|
|
|
|
finally:
|
|
|
|
|
|
|
|
self.transport.session_end()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if None in signatures:
|
|
|
|
if None in signatures:
|
|
|
|
raise Exception("Some signatures are missing!")
|
|
|
|
raise Exception("Some signatures are missing!")
|
|
|
|
|
|
|
|
|
|
|
@ -753,6 +745,7 @@ class ProtocolMixin(object):
|
|
|
|
|
|
|
|
|
|
|
|
@field('message')
|
|
|
|
@field('message')
|
|
|
|
@expect(proto.Success)
|
|
|
|
@expect(proto.Success)
|
|
|
|
|
|
|
|
@session
|
|
|
|
def reset_device(self, display_random, strength, passphrase_protection, pin_protection, label, language):
|
|
|
|
def reset_device(self, display_random, strength, passphrase_protection, pin_protection, label, language):
|
|
|
|
if self.features.initialized:
|
|
|
|
if self.features.initialized:
|
|
|
|
raise Exception("Device is initialized already. Call wipe_device() and try again.")
|
|
|
|
raise Exception("Device is initialized already. Call wipe_device() and try again.")
|
|
|
@ -843,6 +836,7 @@ class ProtocolMixin(object):
|
|
|
|
self.init_device()
|
|
|
|
self.init_device()
|
|
|
|
return resp
|
|
|
|
return resp
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@session
|
|
|
|
def firmware_update(self, fp):
|
|
|
|
def firmware_update(self, fp):
|
|
|
|
if self.features.bootloader_mode == False:
|
|
|
|
if self.features.bootloader_mode == False:
|
|
|
|
raise Exception("Device must be in bootloader mode")
|
|
|
|
raise Exception("Device must be in bootloader mode")
|
|
|
|