More keepkey / trezor commonizing and cleanup

This commit is contained in:
Neil Booth 2015-12-27 13:56:50 +09:00
parent 33e57fe5a7
commit f3329988b2
4 changed files with 78 additions and 115 deletions

View File

@ -5,8 +5,6 @@ from plugins.trezor.plugin_generic import TrezorCompatiblePlugin
try:
from keepkeylib.client import proto, BaseClient, ProtocolMixin
from keepkeylib.transport import ConnectionError
from keepkeylib.transport_hid import HidTransport
KEEPKEY = True
except ImportError:
KEEPKEY = False
@ -19,46 +17,12 @@ class KeepKeyWallet(BIP32_Hardware_Wallet):
class KeepKeyPlugin(TrezorCompatiblePlugin):
wallet_type = 'keepkey'
client_class = trezor_client_class(ProtocolMixin, BaseClient, proto)
firmware_URL = 'https://www.keepkey.com'
libraries_URL = 'https://github.com/keepkey/python-keepkey'
libraries_available = KEEPKEY
minimum_firmware = (1, 0, 0)
wallet_class = KeepKeyWallet
import keepkeylib.ckd_public as ckd_public
from keepkeylib.client import types
@staticmethod
def libraries_available():
return KEEPKEY
def constructor(self, s):
return KeepKeyWallet(s)
def get_client(self):
if not KEEPKEY:
give_error('please install github.com/keepkey/python-keepkey')
if not self.client or self.client.bad:
d = HidTransport.enumerate()
if not d:
give_error('Could not connect to your KeepKey. Please verify the cable is connected and that no other app is using it.')
self.transport = HidTransport(d[0])
self.client = QtGuiKeepKeyClient(self.transport)
self.client.handler = self.handler
self.client.set_tx_api(self)
self.client.bad = False
if not self.atleast_version(1, 0, 0):
self.client = None
give_error('Outdated KeepKey firmware. Please update the firmware from https://www.keepkey.com')
return self.client
if KEEPKEY:
class QtGuiKeepKeyClient(ProtocolMixin, GuiMixin, BaseClient):
protocol = proto
device = 'KeepKey'
def call_raw(self, msg):
try:
resp = BaseClient.call_raw(self, msg)
except ConnectionError:
self.bad = True
raise
return resp
from keepkeylib.transport_hid import HidTransport

View File

@ -3,10 +3,7 @@ from sys import stderr
from electrum.i18n import _
class GuiMixin(object):
# Requires: self.protcol, self.device
def __init__(self, *args, **kwargs):
super(GuiMixin, self).__init__(*args, **kwargs)
# Requires: self.proto, self.device
def callback_ButtonRequest(self, msg):
if msg.code == 3:
@ -26,7 +23,7 @@ class GuiMixin(object):
cancel_callback = None
self.handler.show_message(message % self.device, cancel_callback)
return self.protocol.ButtonAck()
return self.proto.ButtonAck()
def callback_PinMatrixRequest(self, msg):
if msg.type == 1:
@ -39,19 +36,39 @@ class GuiMixin(object):
msg = _("Please enter %s PIN")
pin = self.handler.get_pin(msg % self.device)
if not pin:
return self.protocol.Cancel()
return self.protocol.PinMatrixAck(pin=pin)
return self.proto.Cancel()
return self.proto.PinMatrixAck(pin=pin)
def callback_PassphraseRequest(self, req):
msg = _("Please enter your %s passphrase")
passphrase = self.handler.get_passphrase(msg % self.device)
if passphrase is None:
return self.protocol.Cancel()
return self.protocol.PassphraseAck(passphrase=passphrase)
return self.proto.Cancel()
return self.proto.PassphraseAck(passphrase=passphrase)
def callback_WordRequest(self, msg):
#TODO
stderr.write("Enter one word of mnemonic:\n")
stderr.flush()
word = raw_input()
return self.protocol.WordAck(word=word)
return self.proto.WordAck(word=word)
def trezor_client_class(protocol_mixin, base_client, proto):
'''Returns a class dynamically.'''
class TrezorClient(protocol_mixin, GuiMixin, base_client):
def __init__(self, transport, device):
base_client.__init__(self, transport)
protocol_mixin.__init__(self, transport)
self.proto = proto
self.device = device
def call_raw(self, msg):
try:
return base_client.call_raw(self, msg)
except:
self.bad = True
raise
return TrezorClient

View File

@ -8,39 +8,32 @@ from electrum.transaction import deserialize, is_extended_pubkey
class TrezorCompatiblePlugin(BasePlugin):
# Derived classes provide:
# libraries_available()
# constructor()
# ckd_public
# types
# wallet_type
#
# class-static variables: client_class, firmware_URL,
# libraries_available, libraries_URL, minimum_firmware,
# wallet_class, ckd_public, types, HidTransport
def __init__(self, parent, config, name):
BasePlugin.__init__(self, parent, config, name)
self.device = self.wallet_class.device
self.wallet = None
self.handler = None
self.client = None
self.transport = None
def constructor(self, s):
raise NotImplementedError
@staticmethod
def libraries_available():
raise NotImplementedError
return self.wallet_class(s)
def give_error(self, message):
self.print_error(message)
raise Exception(message)
def is_available(self):
if not self.libraries_available():
if not self.libraries_available:
return False
if not self.wallet:
return False
if self.wallet.storage.get('wallet_type') != self.wallet_type:
return False
return True
wallet_type = self.wallet.storage.get('wallet_type')
return wallet_type == self.wallet_class.wallet_type
def set_enabled(self, enabled):
self.wallet.storage.put('use_' + self.name, enabled)
@ -52,9 +45,32 @@ class TrezorCompatiblePlugin(BasePlugin):
return False
return True
def get_client(self):
if not self.libraries_available:
self.give_error(_('please install the %s libraries from %s')
% (self.device, self.libraries_URL))
if not self.client or self.client.bad:
d = self.HidTransport.enumerate()
if not d:
self.give_error(_('Could not connect to your %s. Please '
'verify the cable is connected and that no '
'other app is using it.' % self.device))
transport = self.HidTransport(d[0])
self.client = self.client_class(transport, self.device)
self.client.handler = self.handler
self.client.set_tx_api(self)
self.client.bad = False
if not self.atleast_version(*self.minimum_firmware):
self.client = None
self.give_error(_('Outdated %s firmware. Please update the '
'firmware from %s') % (self.device,
self.firmware_URL))
return self.client
def compare_version(self, major, minor=0, patch=0):
features = self.get_client().features
v = [features.major_version, features.minor_version, features.patch_version]
f = self.get_client().features
v = [f.major_version, f.minor_version, f.patch_version]
self.print_error('firmware version', v)
return cmp(v, [major, minor, patch])

View File

@ -1,12 +1,10 @@
from electrum.wallet import BIP32_Hardware_Wallet
from plugins.trezor.gui_mixin import GuiMixin
from plugins.trezor.plugin_generic import TrezorCompatiblePlugin
from plugins.trezor.client import trezor_client_class
from plugins.trezor.plugin import TrezorCompatiblePlugin
try:
from trezorlib.client import proto, BaseClient, ProtocolMixin
from trezorlib.transport import ConnectionError
from trezorlib.transport_hid import HidTransport
TREZOR = True
except ImportError:
TREZOR = False
@ -17,46 +15,14 @@ class TrezorWallet(BIP32_Hardware_Wallet):
root_derivation = "m/44'/0'"
device = 'Trezor'
class TrezorPlugin(TrezorCompatiblePlugin):
wallet_type = 'trezor'
client_class = trezor_client_class(ProtocolMixin, BaseClient, proto)
firmware_URL = 'https://www.mytrezor.com'
libraries_URL = 'https://github.com/trezor/python-trezor'
libraries_available = TREZOR
minimum_firmware = (1, 2, 1)
wallet_class = TrezorWallet
import trezorlib.ckd_public as ckd_public
from trezorlib.client import types
@staticmethod
def libraries_available():
return TREZOR
def constructor(self, s):
return TrezorWallet(s)
def get_client(self):
if not TREZOR:
self.give_error('please install github.com/trezor/python-trezor')
if not self.client or self.client.bad:
d = HidTransport.enumerate()
if not d:
self.give_error('Could not connect to your Trezor. Please verify the cable is connected and that no other app is using it.')
self.transport = HidTransport(d[0])
self.client = QtGuiTrezorClient(self.transport)
self.client.handler = self.handler
self.client.set_tx_api(self)
self.client.bad = False
if not self.atleast_version(1, 2, 1):
self.client = None
self.give_error('Outdated Trezor firmware. Please update the firmware from https://www.mytrezor.com')
return self.client
if TREZOR:
class QtGuiTrezorClient(ProtocolMixin, GuiMixin, BaseClient):
protocol = proto
device = 'Trezor'
def call_raw(self, msg):
try:
resp = BaseClient.call_raw(self, msg)
except ConnectionError:
self.bad = True
raise
return resp
from trezorlib.transport_hid import HidTransport