From b24550c72f9e66de8d1777247c1246168d7572a4 Mon Sep 17 00:00:00 2001 From: Tomas Susanka Date: Fri, 2 Mar 2018 16:37:34 +0100 Subject: [PATCH 01/14] tests: ethereum sign/verify is skipped (#224) --- trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py | 1 + trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py | 1 + 2 files changed, 2 insertions(+) diff --git a/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py b/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py index 67a8a05bee..24531b21c4 100644 --- a/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py +++ b/trezorlib/tests/device_tests/test_msg_ethereum_signmessage.py @@ -18,6 +18,7 @@ from .common import * +@pytest.mark.skip_t2 class TestMsgEthereumSignmessage(TrezorTest): def test_sign(self): diff --git a/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py b/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py index bfe65a64fe..7b27d24a69 100644 --- a/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py +++ b/trezorlib/tests/device_tests/test_msg_ethereum_verifymessage.py @@ -18,6 +18,7 @@ from .common import * +@pytest.mark.skip_t2 class TestMsgEthereumVerifymessage(TrezorTest): def test_verify(self): From 55641dd8b5e52fdad8235ab97ecee70dd1d6d6e3 Mon Sep 17 00:00:00 2001 From: matejcik Date: Fri, 2 Mar 2018 16:47:29 +0100 Subject: [PATCH 02/14] make flake8 happy (#225) --- tools/pwd_reader.py | 19 ++++++++++++++----- trezorlib/client.py | 2 +- .../device_tests/test_msg_signtx_bcash.py | 1 - 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/tools/pwd_reader.py b/tools/pwd_reader.py index 2c6c4bd259..7fdea73fa8 100755 --- a/tools/pwd_reader.py +++ b/tools/pwd_reader.py @@ -18,10 +18,12 @@ except: from trezorlib.client import TrezorClient from trezorlib.transport_hid import HidTransport + # Return path by BIP-32 def getPath(client): return client.expand_path("10016'/0") + # Deriving master key def getMasterKey(client): bip32_path = getPath(client) @@ -36,14 +38,16 @@ def getMasterKey(client): )) return key + # Deriving file name and encryption key def getFileEncKey(key): - filekey, enckey = key[:len(key) // 2], key[len(key) //2:] + filekey, enckey = key[:len(key) // 2], key[len(key) // 2:] FILENAME_MESS = b'5f91add3fa1c3c76e90c90a3bd0999e2bd7833d06a483fe884ee60397aca277a' digest = hmac.new(filekey, FILENAME_MESS, hashlib.sha256).hexdigest() filename = digest + '.pswd' return [filename, filekey, enckey] + # File level decryption and file reading def decryptStorage(path, key): cipherkey = unhexlify(key) @@ -64,6 +68,7 @@ def decryptStorage(path, key): data = data + decryptor.finalize().decode() return json.loads(data) + def decryptEntryValue(nonce, val): cipherkey = unhexlify(nonce) iv = val[:12] @@ -83,6 +88,7 @@ def decryptEntryValue(nonce, val): data = data + decryptor.finalize().decode() return json.loads(data) + # Decrypt give entry nonce def getDecryptedNonce(client, entry): print() @@ -99,7 +105,7 @@ def getDecryptedNonce(client, entry): ENC_KEY = 'Unlock %s for user %s?' % (item, entry['username']) ENC_VALUE = entry['nonce'] - decrypted_nonce = hexlify(client.decrypt_keyvalue( + decrypted_nonce = hexlify(client.decrypt_keyvalue( getPath(client), ENC_KEY, unhexlify(ENC_VALUE), @@ -108,6 +114,7 @@ def getDecryptedNonce(client, entry): )) return decrypted_nonce + # Pretty print of list def printEntries(entries): print('Password entries') @@ -117,7 +124,8 @@ def printEntries(entries): print('Entry id: #%s' % k) print('-------------') for kk, vv in v.items(): - if kk in ['nonce', 'safe_note', 'password']: continue # skip these fields + if kk in ['nonce', 'safe_note', 'password']: + continue # skip these fields print('*', kk, ': ', vv) print() return @@ -160,14 +168,15 @@ def main(): plain_nonce = getDecryptedNonce(client, entries[entry_id]) pwdArr = entries[entry_id]['password']['data'] - pwdHex = ''.join([ hex(x)[2:].zfill(2) for x in pwdArr ]) + pwdHex = ''.join([hex(x)[2:].zfill(2) for x in pwdArr]) print('password: ', decryptEntryValue(plain_nonce, unhexlify(pwdHex))) safeNoteArr = entries[entry_id]['safe_note']['data'] - safeNoteHex = ''.join([ hex(x)[2:].zfill(2) for x in safeNoteArr ]) + safeNoteHex = ''.join([hex(x)[2:].zfill(2) for x in safeNoteArr]) print('safe_note:', decryptEntryValue(plain_nonce, unhexlify(safeNoteHex))) return + if __name__ == '__main__': main() diff --git a/trezorlib/client.py b/trezorlib/client.py index 40643e1c9a..d7356e3b7b 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -425,7 +425,7 @@ class DebugLinkMixin(object): continue if getattr(msg, field) != value: raise AssertionException(proto.FailureType.UnexpectedMessage, - "Expected %s, got %s" % (pprint(expected), pprint(msg))) + "Expected %s, got %s" % (pprint(expected), pprint(msg))) def callback_ButtonRequest(self, msg): log("ButtonRequest code: " + get_buttonrequest_value(msg.code)) diff --git a/trezorlib/tests/device_tests/test_msg_signtx_bcash.py b/trezorlib/tests/device_tests/test_msg_signtx_bcash.py index 4b219a81b4..61a27c0dd0 100644 --- a/trezorlib/tests/device_tests/test_msg_signtx_bcash.py +++ b/trezorlib/tests/device_tests/test_msg_signtx_bcash.py @@ -187,7 +187,6 @@ class TestMsgSigntxBch(TrezorTest): else: assert False # exception expected - def test_attack_change_input(self): self.setup_mnemonic_allallall() self.client.set_tx_api(TxApiBcash) From 8a62d12217311e1de850682c4e4c8efa51986bf8 Mon Sep 17 00:00:00 2001 From: Jochen Hoenicke Date: Mon, 5 Mar 2018 13:09:57 +0100 Subject: [PATCH 03/14] Update ethereum_sign_tx to python3 (#227) --- trezorctl | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/trezorctl b/trezorctl index 7646d44395..f890a2ae2f 100755 --- a/trezorctl +++ b/trezorctl @@ -582,9 +582,9 @@ def ethereum_sign_message(connect, address, message): def ethereum_decode_hex(value): if value.startswith('0x') or value.startswith('0X'): - return value[2:].decode('hex') + return binascii.unhexlify(value[2:]) else: - return value.decode('hex') + return binascii.unhexlify(value) @cli.command(help='Verify message signed with Ethereum address.') @@ -731,7 +731,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri client = connect() address_n = client.expand_path(address) - address = '0x%s' % (binascii.hexlify(client.ethereum_get_address(address_n)),) + address = '0x%s' % (binascii.hexlify(client.ethereum_get_address(address_n)).decode()) if gas_price is None or gas_limit is None or nonce is None: host, port = host.split(':') @@ -749,7 +749,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri to_address=to, from_address=address, value=('0x%x' % value), - data='0x' + data) + data='0x%s' % (binascii.hexlify(data).decode())) if nonce is None: nonce = eth.eth_getTransactionCount(address) @@ -766,7 +766,7 @@ def ethereum_sign_tx(connect, host, chain_id, address, value, gas_limit, gas_pri transaction = rlp.encode( (nonce, gas_price, gas_limit, to_address, value, data) + sig) - tx_hex = '0x%s' % binascii.hexlify(transaction) + tx_hex = '0x%s' % binascii.hexlify(transaction).decode() if publish: tx_hash = eth.eth_sendRawTransaction(tx_hex) From 0e065237c9eaf8af51dae31500eefd579efed690 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Mon, 5 Mar 2018 15:49:04 +0100 Subject: [PATCH 04/14] tests: disable TestBip32Speed::test_cache on t2 --- trezorlib/tests/device_tests/test_bip32_speed.py | 1 + 1 file changed, 1 insertion(+) diff --git a/trezorlib/tests/device_tests/test_bip32_speed.py b/trezorlib/tests/device_tests/test_bip32_speed.py index bb5e11f259..11c7ecbf88 100644 --- a/trezorlib/tests/device_tests/test_bip32_speed.py +++ b/trezorlib/tests/device_tests/test_bip32_speed.py @@ -50,6 +50,7 @@ class TestBip32Speed(TrezorTest): print("DEPTH", depth, "EXPECTED DELAY", expected, "REAL DELAY", delay) assert delay <= expected + @pytest.mark.skip_t2 def test_cache(self): self.setup_mnemonic_nopin_nopassphrase() From db827bfe018a1b659bd28395635f6983a61196c4 Mon Sep 17 00:00:00 2001 From: Pavol Rusnak Date: Mon, 5 Mar 2018 17:37:36 +0100 Subject: [PATCH 05/14] tests: update test_msg_getpublickey.py, add test_msg_getpublickey_curve.py --- .../device_tests/test_msg_getpublickey.py | 21 ++++++--- .../test_msg_getpublickey_curve.py | 43 +++++++++++++++++++ 2 files changed, 59 insertions(+), 5 deletions(-) create mode 100644 trezorlib/tests/device_tests/test_msg_getpublickey_curve.py diff --git a/trezorlib/tests/device_tests/test_msg_getpublickey.py b/trezorlib/tests/device_tests/test_msg_getpublickey.py index a8df505aba..77e2547920 100644 --- a/trezorlib/tests/device_tests/test_msg_getpublickey.py +++ b/trezorlib/tests/device_tests/test_msg_getpublickey.py @@ -25,19 +25,30 @@ class TestMsgGetpublickey(TrezorTest): def test_btc(self): self.setup_mnemonic_nopin_nopassphrase() assert bip32.serialize(self.client.get_public_node([]).node, 0x0488B21E) == 'xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy' + assert self.client.get_public_node([], coin_name='Bitcoin').xpub == 'xpub661MyMwAqRbcF1zGijBb2K6x9YiJPh58xpcCeLvTxMX6spkY3PcpJ4ABcCyWfskq5DDxM3e6Ez5ePCqG5bnPUXR4wL8TZWyoDaUdiWW7bKy' assert bip32.serialize(self.client.get_public_node([1]).node, 0x0488B21E) == 'xpub68zNxjsTrV8y9AadThLW7dTAqEpZ7xBLFSyJ3X9pjTv6Njg6kxgjXJkzxq8u3ttnjBw1jupQHMP3gpGZzZqd1eh5S4GjkaMhPR18vMyUi8N' + assert self.client.get_public_node([1], coin_name='Bitcoin').xpub == 'xpub68zNxjsTrV8y9AadThLW7dTAqEpZ7xBLFSyJ3X9pjTv6Njg6kxgjXJkzxq8u3ttnjBw1jupQHMP3gpGZzZqd1eh5S4GjkaMhPR18vMyUi8N' assert bip32.serialize(self.client.get_public_node([0, -1]).node, 0x0488B21E) == 'xpub6A3FoZqYXj1AbW4thRwBh26YwZWbmoyjTaZwwxJjY1oKUpefLepL3RFS9DHKQrjAfxDrzDepYMDZPqXN6upQm3bHQ9xaXD5a3mqni3goF4v' + assert self.client.get_public_node([0, -1], coin_name='Bitcoin').xpub == 'xpub6A3FoZqYXj1AbW4thRwBh26YwZWbmoyjTaZwwxJjY1oKUpefLepL3RFS9DHKQrjAfxDrzDepYMDZPqXN6upQm3bHQ9xaXD5a3mqni3goF4v' assert bip32.serialize(self.client.get_public_node([-9, 0]).node, 0x0488B21E) == 'xpub6A2h5mzLDfYginoD7q7wCWbq18wTbN9gducRr2w5NRTwdLeoT3cJSwefFqW7uXTpVFGtpUyDMBNYs3DNvvXx6NPjF9YEbUQrtxFSWnPtVrv' + assert self.client.get_public_node([-9, 0], coin_name='Bitcoin').xpub == 'xpub6A2h5mzLDfYginoD7q7wCWbq18wTbN9gducRr2w5NRTwdLeoT3cJSwefFqW7uXTpVFGtpUyDMBNYs3DNvvXx6NPjF9YEbUQrtxFSWnPtVrv' assert bip32.serialize(self.client.get_public_node([0, 9999999]).node, 0x0488B21E) == 'xpub6A3FoZqQEK6iwLZ4HFkqSo5fb35BH4bpjC4SPZ63prfLdGYPwYxEuC6o91bUvFFdMzKWe5rs3axHRUjxJaSvBnKKFtnfLwDACRxPxabsv2r' + assert self.client.get_public_node([0, 9999999], coin_name='Bitcoin').xpub == 'xpub6A3FoZqQEK6iwLZ4HFkqSo5fb35BH4bpjC4SPZ63prfLdGYPwYxEuC6o91bUvFFdMzKWe5rs3axHRUjxJaSvBnKKFtnfLwDACRxPxabsv2r' def test_ltc(self): self.setup_mnemonic_nopin_nopassphrase() - assert bip32.serialize(self.client.get_public_node([]).node, 0x019dA462) == 'Ltub2SSUS19CirucVPGDKDBatBDBEM2s9UbH66pBURfaKrMocCPLhQ7Z7hecy5VYLHA5fRdXwB2e61j2VJCNzVsqKTCVEU1vECjqi5EyczFX9xp' - assert bip32.serialize(self.client.get_public_node([1]).node, 0x019dA462) == 'Ltub2VRVRP5VjvSyPXra4BLVyVZPv397sjhUNjBGsbtw6xko77JuQyBULxFSKheviJJ3KQLbL3Cx8P2RnudguTw4raUVjCACRG7jsumUptYx55C' - assert bip32.serialize(self.client.get_public_node([0, -1]).node, 0x019dA462) == 'Ltub2WUNGD3aRAKAqsLqHuwBYtCn2MqAXbVsarmvn33quWe2DCHTzfK4s4jsW5oM5G8RGAdSaM3NPNrwVvtV1ourbyNhhHr3BtqcYGc8caf5GoT' - assert bip32.serialize(self.client.get_public_node([-9, 0]).node, 0x019dA462) == 'Ltub2WToYRCN76rgyA59iK7w4Ni45wG2M9fpmBpQg7gBjvJeMiHc7473Gb96ci29Zvs55TgUQcMmCD1vy8aVqpdPwJB9YHRhGAAuPT1nRLLXmFu' - assert bip32.serialize(self.client.get_public_node([0, 9999999]).node, 0x019dA462) == 'Ltub2WUNGD3S7kQjBhpzsjkqJfBtfqPk2r7xrUGRDdqACMW3MeBCbZSyiqbEVt7WaeesxCj6EDFQtcbfXa75DUYN2i6jZ2g81cyCgvijs9J2u2n' + assert bip32.serialize(self.client.get_public_node([]).node, 0x019DA462) == 'Ltub2SSUS19CirucVPGDKDBatBDBEM2s9UbH66pBURfaKrMocCPLhQ7Z7hecy5VYLHA5fRdXwB2e61j2VJCNzVsqKTCVEU1vECjqi5EyczFX9xp' + assert self.client.get_public_node([], coin_name='Litecoin').xpub == 'Ltub2SSUS19CirucVPGDKDBatBDBEM2s9UbH66pBURfaKrMocCPLhQ7Z7hecy5VYLHA5fRdXwB2e61j2VJCNzVsqKTCVEU1vECjqi5EyczFX9xp' + assert bip32.serialize(self.client.get_public_node([1]).node, 0x019DA462) == 'Ltub2VRVRP5VjvSyPXra4BLVyVZPv397sjhUNjBGsbtw6xko77JuQyBULxFSKheviJJ3KQLbL3Cx8P2RnudguTw4raUVjCACRG7jsumUptYx55C' + assert self.client.get_public_node([1], coin_name='Litecoin').xpub == 'Ltub2VRVRP5VjvSyPXra4BLVyVZPv397sjhUNjBGsbtw6xko77JuQyBULxFSKheviJJ3KQLbL3Cx8P2RnudguTw4raUVjCACRG7jsumUptYx55C' + assert bip32.serialize(self.client.get_public_node([0, -1]).node, 0x019DA462) == 'Ltub2WUNGD3aRAKAqsLqHuwBYtCn2MqAXbVsarmvn33quWe2DCHTzfK4s4jsW5oM5G8RGAdSaM3NPNrwVvtV1ourbyNhhHr3BtqcYGc8caf5GoT' + assert self.client.get_public_node([0, -1], coin_name='Litecoin').xpub == 'Ltub2WUNGD3aRAKAqsLqHuwBYtCn2MqAXbVsarmvn33quWe2DCHTzfK4s4jsW5oM5G8RGAdSaM3NPNrwVvtV1ourbyNhhHr3BtqcYGc8caf5GoT' + assert bip32.serialize(self.client.get_public_node([-9, 0]).node, 0x019DA462) == 'Ltub2WToYRCN76rgyA59iK7w4Ni45wG2M9fpmBpQg7gBjvJeMiHc7473Gb96ci29Zvs55TgUQcMmCD1vy8aVqpdPwJB9YHRhGAAuPT1nRLLXmFu' + assert self.client.get_public_node([-9, 0], coin_name='Litecoin').xpub == 'Ltub2WToYRCN76rgyA59iK7w4Ni45wG2M9fpmBpQg7gBjvJeMiHc7473Gb96ci29Zvs55TgUQcMmCD1vy8aVqpdPwJB9YHRhGAAuPT1nRLLXmFu' + assert bip32.serialize(self.client.get_public_node([0, 9999999]).node, 0x019DA462) == 'Ltub2WUNGD3S7kQjBhpzsjkqJfBtfqPk2r7xrUGRDdqACMW3MeBCbZSyiqbEVt7WaeesxCj6EDFQtcbfXa75DUYN2i6jZ2g81cyCgvijs9J2u2n' + assert self.client.get_public_node([0, 9999999], coin_name='Litecoin').xpub == 'Ltub2WUNGD3S7kQjBhpzsjkqJfBtfqPk2r7xrUGRDdqACMW3MeBCbZSyiqbEVt7WaeesxCj6EDFQtcbfXa75DUYN2i6jZ2g81cyCgvijs9J2u2n' def test_tbtc(self): self.setup_mnemonic_nopin_nopassphrase() assert bip32.serialize(self.client.get_public_node([111, 42]).node, 0x043587CF) == 'tpubDAgixSyai5PWbc8N1mBkHDR5nLgAnHFtY7r4y5EzxqAxrt9YUDpZL3kaRoHVvCfrcwNo31c2isBP2uTHcZxEosuKbyJhCAbrvGoPuLUZ7Mz' + assert self.client.get_public_node([111, 42], coin_name='Testnet').xpub == 'tpubDAgixSyai5PWbc8N1mBkHDR5nLgAnHFtY7r4y5EzxqAxrt9YUDpZL3kaRoHVvCfrcwNo31c2isBP2uTHcZxEosuKbyJhCAbrvGoPuLUZ7Mz' diff --git a/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py b/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py new file mode 100644 index 0000000000..cbab0eaabd --- /dev/null +++ b/trezorlib/tests/device_tests/test_msg_getpublickey_curve.py @@ -0,0 +1,43 @@ +# This file is part of the TREZOR project. +# +# Copyright (C) 2012-2016 Marek Palatinus +# Copyright (C) 2012-2016 Pavol Rusnak +# +# This library is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with this library. If not, see . + +from .common import * +import trezorlib.ckd_public as bip32 + + +class TestMsgGetpublickeyCurve(TrezorTest): + + def test_default_curve(self): + self.setup_mnemonic_nopin_nopassphrase() + assert hexlify(self.client.get_public_node([0x80000000 | 111, 42]).node.public_key).decode() == '02e7fcec053f0df94d88c86447970743e8a1979d242d09338dcf8687a9966f7fbc' + assert hexlify(self.client.get_public_node([0x80000000 | 111, 0x80000000 | 42]).node.public_key).decode() == '03ce7b690969d773ba9ed212464eb2b534b87b9b8a9383300bddabe1f093f79220' + + def test_secp256k1_curve(self): + self.setup_mnemonic_nopin_nopassphrase() + assert hexlify(self.client.get_public_node([0x80000000 | 111, 42], ecdsa_curve_name='secp256k1').node.public_key).decode() == '02e7fcec053f0df94d88c86447970743e8a1979d242d09338dcf8687a9966f7fbc' + assert hexlify(self.client.get_public_node([0x80000000 | 111, 0x80000000 | 42], ecdsa_curve_name='secp256k1').node.public_key).decode() == '03ce7b690969d773ba9ed212464eb2b534b87b9b8a9383300bddabe1f093f79220' + + def test_nist256p1_curve(self): + self.setup_mnemonic_nopin_nopassphrase() + assert hexlify(self.client.get_public_node([0x80000000 | 111, 42], ecdsa_curve_name='nist256p1').node.public_key).decode() == '02a9ce59b32bd64a70bc52aca96e5d09af65c6b9593ba2a60af8fccfe1437f2129' + assert hexlify(self.client.get_public_node([0x80000000 | 111, 0x80000000 | 42], ecdsa_curve_name='nist256p1').node.public_key).decode() == '026fe35d8afed67dbf0561a1d32922e8ad0cd0d86effbc82be970cbed7d9bab2c2' + + def test_ed25519_curve(self): + self.setup_mnemonic_nopin_nopassphrase() + assert hexlify(self.client.get_public_node([0x80000000 | 111, 42], ecdsa_curve_name='ed25519').node.public_key).decode() == '001d9a1e56f69828d44ec96dad345678411976d3ea6d290fe3ae8032c47699ce15' + assert hexlify(self.client.get_public_node([0x80000000 | 111, 0x80000000 | 42], ecdsa_curve_name='ed25519').node.public_key).decode() == '0069a14b478e508eab6e93303f4e6f5c50b8136627830f2ed5c3a835fc6c0ea2b7' From 4979c296b764b080071086416cbded1c18a1ceda Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Mon, 5 Mar 2018 17:34:42 +0100 Subject: [PATCH 06/14] tests: enable test_apply_settings, test_apply_settings_passphrase for t2 --- trezorlib/tests/device_tests/test_msg_applysettings.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/trezorlib/tests/device_tests/test_msg_applysettings.py b/trezorlib/tests/device_tests/test_msg_applysettings.py index 967bf9a6ea..cf57378fe0 100644 --- a/trezorlib/tests/device_tests/test_msg_applysettings.py +++ b/trezorlib/tests/device_tests/test_msg_applysettings.py @@ -21,7 +21,6 @@ from .common import * from trezorlib import messages as proto -@pytest.mark.skip_t2 class TestMsgApplysettings(TrezorTest): def test_apply_settings(self): @@ -33,10 +32,13 @@ class TestMsgApplysettings(TrezorTest): proto.ButtonRequest(), proto.Success(), proto.Features()]) + if self.client.features.major_version >= 2: + self.client.expected_responses.pop(0) # skip PinMatrixRequest self.client.apply_settings(label='new label') assert self.client.features.label == 'new label' + @pytest.mark.skip_t2 def test_invalid_language(self): self.setup_mnemonic_pin_passphrase() assert self.client.features.language == 'english' @@ -60,6 +62,8 @@ class TestMsgApplysettings(TrezorTest): proto.ButtonRequest(), proto.Success(), proto.Features()]) + if self.client.features.major_version >= 2: + self.client.expected_responses.pop(0) # skip PinMatrixRequest self.client.apply_settings(use_passphrase=True) assert self.client.features.passphrase_protection is True @@ -80,6 +84,7 @@ class TestMsgApplysettings(TrezorTest): assert self.client.features.passphrase_protection is True + @pytest.mark.skip_t2 def test_apply_homescreen(self): self.setup_mnemonic_pin_passphrase() From 95603b85dd7c88e4f909866bce0d066767f634d7 Mon Sep 17 00:00:00 2001 From: Jan Pochyla Date: Mon, 5 Mar 2018 17:44:55 +0100 Subject: [PATCH 07/14] tests: enable segwit sign&verify tests for t2 --- trezorlib/tests/device_tests/test_msg_signmessage_segwit.py | 1 - .../tests/device_tests/test_msg_signmessage_segwit_native.py | 1 - trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py | 1 - .../tests/device_tests/test_msg_verifymessage_segwit_native.py | 1 - 4 files changed, 4 deletions(-) diff --git a/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py b/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py index 93d456d008..d46a9edf03 100644 --- a/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py +++ b/trezorlib/tests/device_tests/test_msg_signmessage_segwit.py @@ -20,7 +20,6 @@ from .common import * from trezorlib import messages as proto -@pytest.mark.skip_t2 class TestMsgSignmessageSegwit(TrezorTest): def test_sign(self): diff --git a/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py b/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py index d3b23b7016..b895c8f2e2 100644 --- a/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py +++ b/trezorlib/tests/device_tests/test_msg_signmessage_segwit_native.py @@ -20,7 +20,6 @@ from .common import * from trezorlib import messages as proto -@pytest.mark.skip_t2 class TestMsgSignmessageSegwitNative(TrezorTest): def test_sign(self): diff --git a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py index 67d2663d98..ba8cf46c2b 100644 --- a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py +++ b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit.py @@ -20,7 +20,6 @@ from .common import * import base64 -@pytest.mark.skip_t2 class TestMsgVerifymessageSegwit(TrezorTest): def test_message_long(self): diff --git a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py index b719557f92..fa2beb084a 100644 --- a/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py +++ b/trezorlib/tests/device_tests/test_msg_verifymessage_segwit_native.py @@ -20,7 +20,6 @@ from .common import * import base64 -@pytest.mark.skip_t2 class TestMsgVerifymessageSegwitNative(TrezorTest): def test_message_long(self): From 07ceb9aacc117a099b34bd3b85c1476da6db1870 Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 28 Feb 2018 14:04:34 +0100 Subject: [PATCH 08/14] pretty printing protobufs --- trezorctl | 6 ++++-- trezorlib/client.py | 32 +++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/trezorctl b/trezorctl index f890a2ae2f..fb9d048678 100755 --- a/trezorctl +++ b/trezorctl @@ -28,7 +28,7 @@ import json import os import sys -from trezorlib.client import TrezorClient, TrezorClientVerbose, CallException +from trezorlib.client import TrezorClient, TrezorClientVerbose, CallException, format_protobuf from trezorlib.device import TrezorDevice from trezorlib import messages as proto from trezorlib import protobuf @@ -80,7 +80,7 @@ def cli(ctx, path, verbose, is_json): @cli.resultcallback() def print_result(res, path, verbose, is_json): if is_json: - if issubclass(res.__class__, protobuf.MessageType): + if isinstance(res, protobuf.MessageType): click.echo(json.dumps({res.__class__.__name__: res.__dict__})) else: click.echo(json.dumps(res, sort_keys=True, indent=4)) @@ -95,6 +95,8 @@ def print_result(res, path, verbose, is_json): click.echo('%s.%s: %s' % (k, kk, vv)) else: click.echo('%s: %s' % (k, v)) + elif isinstance(res, protobuf.MessageType): + click.echo(format_protobuf(res)) else: click.echo(res) diff --git a/trezorlib/client.py b/trezorlib/client.py index d7356e3b7b..d0c63b0264 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -36,6 +36,7 @@ from . import tools from . import mapping from .coins import coins_slip44 from .debuglink import DebugLink +from .protobuf import MessageType # Python2 vs Python3 try: @@ -86,13 +87,42 @@ def get_buttonrequest_value(code): return [k for k in dir(proto.ButtonRequestType) if getattr(proto.ButtonRequestType, k) == code][0] +def format_protobuf(pb, indent=0, sep=' '*4): + def pformat_value(value, indent): + level = sep * indent + leadin = sep * (indent + 1) + if isinstance(value, MessageType): + return format_protobuf(value, indent, sep) + if isinstance(value, list): + lines = [] + lines.append('[') + lines += [leadin + pformat_value(x, indent + 1) + ',' for x in value] + lines.append(level + ']') + return '\n'.join(lines) + if isinstance(value, dict): + lines = [] + lines.append('{') + for key, val in sorted(value.items()): + if val is None or val == []: + continue + lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',') + lines.append(level + '}') + return '\n'.join(lines) + if isinstance(value, bytes) or isinstance(value, bytearray): + return '{type}(0x{hex})'.format(type=type(value).__name__, hex=value.hex()) + + return repr(value) + + return pb.__class__.__name__ + ' ' + pformat_value(pb.__dict__, indent) + + def pprint(msg): msg_class = msg.__class__.__name__ msg_size = msg.ByteSize() if isinstance(msg, proto.FirmwareUpload) or isinstance(msg, proto.SelfTest): return "<%s> (%d bytes):\n" % (msg_class, msg_size) else: - return "<%s> (%d bytes):\n%s" % (msg_class, msg_size, msg) + return "<%s> (%d bytes):\n%s" % (msg_class, msg_size, format_protobuf(msg)) def log(msg): From db3767f7ef2b551eb6a0d776192a3f09eb4c5ea4 Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 28 Feb 2018 17:13:52 +0100 Subject: [PATCH 09/14] tweak prettyprint for some known elements --- trezorlib/client.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/trezorlib/client.py b/trezorlib/client.py index d0c63b0264..62c8ca441f 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -105,11 +105,14 @@ def format_protobuf(pb, indent=0, sep=' '*4): for key, val in sorted(value.items()): if val is None or val == []: continue - lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',') + if key == 'address_n' and isinstance(val, list): + lines.append(leadin + key + ': ' + repr(val) + ',') + else: + lines.append(leadin + key + ': ' + pformat_value(val, indent + 1) + ',') lines.append(level + '}') return '\n'.join(lines) - if isinstance(value, bytes) or isinstance(value, bytearray): - return '{type}(0x{hex})'.format(type=type(value).__name__, hex=value.hex()) + if isinstance(value, bytearray): + return 'bytearray(0x{})'.format(value.hex()) return repr(value) From 52c2319822226fbdf478d275494b16747f09e418 Mon Sep 17 00:00:00 2001 From: matejcik Date: Wed, 28 Feb 2018 17:14:18 +0100 Subject: [PATCH 10/14] omit Features message from debug dumps --- trezorlib/client.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/trezorlib/client.py b/trezorlib/client.py index 62c8ca441f..a1da975b70 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -122,8 +122,9 @@ def format_protobuf(pb, indent=0, sep=' '*4): def pprint(msg): msg_class = msg.__class__.__name__ msg_size = msg.ByteSize() - if isinstance(msg, proto.FirmwareUpload) or isinstance(msg, proto.SelfTest): - return "<%s> (%d bytes):\n" % (msg_class, msg_size) + if isinstance(msg, proto.FirmwareUpload) or isinstance(msg, proto.SelfTest) \ + or isinstance(msg, proto.Features): + return "<%s> (%d bytes)" % (msg_class, msg_size) else: return "<%s> (%d bytes):\n%s" % (msg_class, msg_size, format_protobuf(msg)) From cd9bd06163cfe557ae2eadd98a39c10bfd5187e1 Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 5 Mar 2018 19:10:54 +0100 Subject: [PATCH 11/14] prettyprint: fix flake8 complaints --- trezorlib/client.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/trezorlib/client.py b/trezorlib/client.py index a1da975b70..6f3e6a6732 100644 --- a/trezorlib/client.py +++ b/trezorlib/client.py @@ -87,9 +87,9 @@ def get_buttonrequest_value(code): return [k for k in dir(proto.ButtonRequestType) if getattr(proto.ButtonRequestType, k) == code][0] -def format_protobuf(pb, indent=0, sep=' '*4): +def format_protobuf(pb, indent=0, sep=' ' * 4): def pformat_value(value, indent): - level = sep * indent + level = sep * indent leadin = sep * (indent + 1) if isinstance(value, MessageType): return format_protobuf(value, indent, sep) From f63b34dbea54bdfb54cf3f82537e5b8b5833ae1c Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 5 Mar 2018 19:11:16 +0100 Subject: [PATCH 12/14] setup.py: add markers specifying Python 3 only compatibility --- setup.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/setup.py b/setup.py index 8da3a4b48b..0639e902a9 100755 --- a/setup.py +++ b/setup.py @@ -40,6 +40,7 @@ setup( ], scripts=['trezorctl'], install_requires=install_requires, + python_requires='>=3.3', include_package_data=True, zip_safe=False, classifiers=[ @@ -47,5 +48,6 @@ setup( 'Operating System :: POSIX :: Linux', 'Operating System :: Microsoft :: Windows', 'Operating System :: MacOS :: MacOS X', + 'Programming Language :: Python :: 3 :: Only', ], ) From 43c71ca8e0228776eb9e8d3335e3fd0d5f64a1ba Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 5 Mar 2018 19:11:45 +0100 Subject: [PATCH 13/14] add changelog --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000000..fd33099958 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +The changelog format is bound to change as we figure out a way to autogenerate it. + +## version 0.9.1 (released 2018-03-05) + +- proper support for Trezor model T +- gradually dropping Python 2 compatibility (pypi package will now be marked as Python 3 only) +- support for Monacoin +- improvements to `trezorctl`: + - add pretty-printing of features and protobuf debug dumps (fixes #199) + - support `TREZOR_PATH` environment variable to preselect a Trezor device. From 2752e6d0467e4adbbe7c0f27c0f4ab6b7af12256 Mon Sep 17 00:00:00 2001 From: matejcik Date: Mon, 5 Mar 2018 19:14:04 +0100 Subject: [PATCH 14/14] bump version to 0.9.1 --- trezorlib/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trezorlib/__init__.py b/trezorlib/__init__.py index e4e49b3bb8..8969d49666 100644 --- a/trezorlib/__init__.py +++ b/trezorlib/__init__.py @@ -1 +1 @@ -__version__ = '0.9.0' +__version__ = '0.9.1'