More keepkey / trezor commonizing and cleanup
This commit is contained in:
parent
33e57fe5a7
commit
f3329988b2
|
@ -5,8 +5,6 @@ from plugins.trezor.plugin_generic import TrezorCompatiblePlugin
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from keepkeylib.client import proto, BaseClient, ProtocolMixin
|
from keepkeylib.client import proto, BaseClient, ProtocolMixin
|
||||||
from keepkeylib.transport import ConnectionError
|
|
||||||
from keepkeylib.transport_hid import HidTransport
|
|
||||||
KEEPKEY = True
|
KEEPKEY = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
KEEPKEY = False
|
KEEPKEY = False
|
||||||
|
@ -19,46 +17,12 @@ class KeepKeyWallet(BIP32_Hardware_Wallet):
|
||||||
|
|
||||||
|
|
||||||
class KeepKeyPlugin(TrezorCompatiblePlugin):
|
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
|
import keepkeylib.ckd_public as ckd_public
|
||||||
from keepkeylib.client import types
|
from keepkeylib.client import types
|
||||||
|
from keepkeylib.transport_hid import HidTransport
|
||||||
@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
|
|
||||||
|
|
|
@ -3,10 +3,7 @@ from sys import stderr
|
||||||
from electrum.i18n import _
|
from electrum.i18n import _
|
||||||
|
|
||||||
class GuiMixin(object):
|
class GuiMixin(object):
|
||||||
# Requires: self.protcol, self.device
|
# Requires: self.proto, self.device
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs):
|
|
||||||
super(GuiMixin, self).__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
def callback_ButtonRequest(self, msg):
|
def callback_ButtonRequest(self, msg):
|
||||||
if msg.code == 3:
|
if msg.code == 3:
|
||||||
|
@ -26,7 +23,7 @@ class GuiMixin(object):
|
||||||
cancel_callback = None
|
cancel_callback = None
|
||||||
|
|
||||||
self.handler.show_message(message % self.device, cancel_callback)
|
self.handler.show_message(message % self.device, cancel_callback)
|
||||||
return self.protocol.ButtonAck()
|
return self.proto.ButtonAck()
|
||||||
|
|
||||||
def callback_PinMatrixRequest(self, msg):
|
def callback_PinMatrixRequest(self, msg):
|
||||||
if msg.type == 1:
|
if msg.type == 1:
|
||||||
|
@ -39,19 +36,39 @@ class GuiMixin(object):
|
||||||
msg = _("Please enter %s PIN")
|
msg = _("Please enter %s PIN")
|
||||||
pin = self.handler.get_pin(msg % self.device)
|
pin = self.handler.get_pin(msg % self.device)
|
||||||
if not pin:
|
if not pin:
|
||||||
return self.protocol.Cancel()
|
return self.proto.Cancel()
|
||||||
return self.protocol.PinMatrixAck(pin=pin)
|
return self.proto.PinMatrixAck(pin=pin)
|
||||||
|
|
||||||
def callback_PassphraseRequest(self, req):
|
def callback_PassphraseRequest(self, req):
|
||||||
msg = _("Please enter your %s passphrase")
|
msg = _("Please enter your %s passphrase")
|
||||||
passphrase = self.handler.get_passphrase(msg % self.device)
|
passphrase = self.handler.get_passphrase(msg % self.device)
|
||||||
if passphrase is None:
|
if passphrase is None:
|
||||||
return self.protocol.Cancel()
|
return self.proto.Cancel()
|
||||||
return self.protocol.PassphraseAck(passphrase=passphrase)
|
return self.proto.PassphraseAck(passphrase=passphrase)
|
||||||
|
|
||||||
def callback_WordRequest(self, msg):
|
def callback_WordRequest(self, msg):
|
||||||
#TODO
|
#TODO
|
||||||
stderr.write("Enter one word of mnemonic:\n")
|
stderr.write("Enter one word of mnemonic:\n")
|
||||||
stderr.flush()
|
stderr.flush()
|
||||||
word = raw_input()
|
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
|
|
@ -8,39 +8,32 @@ from electrum.transaction import deserialize, is_extended_pubkey
|
||||||
|
|
||||||
class TrezorCompatiblePlugin(BasePlugin):
|
class TrezorCompatiblePlugin(BasePlugin):
|
||||||
# Derived classes provide:
|
# Derived classes provide:
|
||||||
|
#
|
||||||
# libraries_available()
|
# class-static variables: client_class, firmware_URL,
|
||||||
# constructor()
|
# libraries_available, libraries_URL, minimum_firmware,
|
||||||
# ckd_public
|
# wallet_class, ckd_public, types, HidTransport
|
||||||
# types
|
|
||||||
# wallet_type
|
|
||||||
|
|
||||||
def __init__(self, parent, config, name):
|
def __init__(self, parent, config, name):
|
||||||
BasePlugin.__init__(self, parent, config, name)
|
BasePlugin.__init__(self, parent, config, name)
|
||||||
|
self.device = self.wallet_class.device
|
||||||
self.wallet = None
|
self.wallet = None
|
||||||
self.handler = None
|
self.handler = None
|
||||||
self.client = None
|
self.client = None
|
||||||
self.transport = None
|
|
||||||
|
|
||||||
def constructor(self, s):
|
def constructor(self, s):
|
||||||
raise NotImplementedError
|
return self.wallet_class(s)
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def libraries_available():
|
|
||||||
raise NotImplementedError
|
|
||||||
|
|
||||||
def give_error(self, message):
|
def give_error(self, message):
|
||||||
self.print_error(message)
|
self.print_error(message)
|
||||||
raise Exception(message)
|
raise Exception(message)
|
||||||
|
|
||||||
def is_available(self):
|
def is_available(self):
|
||||||
if not self.libraries_available():
|
if not self.libraries_available:
|
||||||
return False
|
return False
|
||||||
if not self.wallet:
|
if not self.wallet:
|
||||||
return False
|
return False
|
||||||
if self.wallet.storage.get('wallet_type') != self.wallet_type:
|
wallet_type = self.wallet.storage.get('wallet_type')
|
||||||
return False
|
return wallet_type == self.wallet_class.wallet_type
|
||||||
return True
|
|
||||||
|
|
||||||
def set_enabled(self, enabled):
|
def set_enabled(self, enabled):
|
||||||
self.wallet.storage.put('use_' + self.name, enabled)
|
self.wallet.storage.put('use_' + self.name, enabled)
|
||||||
|
@ -52,9 +45,32 @@ class TrezorCompatiblePlugin(BasePlugin):
|
||||||
return False
|
return False
|
||||||
return True
|
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):
|
def compare_version(self, major, minor=0, patch=0):
|
||||||
features = self.get_client().features
|
f = self.get_client().features
|
||||||
v = [features.major_version, features.minor_version, features.patch_version]
|
v = [f.major_version, f.minor_version, f.patch_version]
|
||||||
self.print_error('firmware version', v)
|
self.print_error('firmware version', v)
|
||||||
return cmp(v, [major, minor, patch])
|
return cmp(v, [major, minor, patch])
|
||||||
|
|
|
@ -1,12 +1,10 @@
|
||||||
from electrum.wallet import BIP32_Hardware_Wallet
|
from electrum.wallet import BIP32_Hardware_Wallet
|
||||||
|
|
||||||
from plugins.trezor.gui_mixin import GuiMixin
|
from plugins.trezor.client import trezor_client_class
|
||||||
from plugins.trezor.plugin_generic import TrezorCompatiblePlugin
|
from plugins.trezor.plugin import TrezorCompatiblePlugin
|
||||||
|
|
||||||
try:
|
try:
|
||||||
from trezorlib.client import proto, BaseClient, ProtocolMixin
|
from trezorlib.client import proto, BaseClient, ProtocolMixin
|
||||||
from trezorlib.transport import ConnectionError
|
|
||||||
from trezorlib.transport_hid import HidTransport
|
|
||||||
TREZOR = True
|
TREZOR = True
|
||||||
except ImportError:
|
except ImportError:
|
||||||
TREZOR = False
|
TREZOR = False
|
||||||
|
@ -17,46 +15,14 @@ class TrezorWallet(BIP32_Hardware_Wallet):
|
||||||
root_derivation = "m/44'/0'"
|
root_derivation = "m/44'/0'"
|
||||||
device = 'Trezor'
|
device = 'Trezor'
|
||||||
|
|
||||||
|
|
||||||
class TrezorPlugin(TrezorCompatiblePlugin):
|
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
|
import trezorlib.ckd_public as ckd_public
|
||||||
from trezorlib.client import types
|
from trezorlib.client import types
|
||||||
|
from trezorlib.transport_hid import HidTransport
|
||||||
@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
|
|
||||||
|
|
Loading…
Reference in New Issue