Browse Source

hw_wallet: Create HW_PluginBase and use it

283
Neil Booth 9 years ago
parent
commit
012f500976
  1. 1
      plugins/hw_wallet/__init__.py
  2. 85
      plugins/hw_wallet/plugin.py
  3. 44
      plugins/ledger/ledger.py
  4. 32
      plugins/trezor/plugin.py

1
plugins/hw_wallet/__init__.py

@ -1,2 +1,3 @@
from hw_wallet import BIP44_HW_Wallet from hw_wallet import BIP44_HW_Wallet
from qt import QtHandlerBase from qt import QtHandlerBase
from plugin import HW_PluginBase

85
plugins/hw_wallet/plugin.py

@ -0,0 +1,85 @@
#!/usr/bin/env python2
# -*- mode: python -*-
#
# Electrum - lightweight Bitcoin client
# Copyright (C) 2016 The Electrum developers
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program 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 General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import time
from electrum.util import ThreadJob
from electrum.plugins import BasePlugin, hook
class HW_PluginBase(BasePlugin, ThreadJob):
# Derived classes provide:
#
# class-static variables: client_class, firmware_URL, handler_class,
# 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_class.plugin = self
self.prevent_timeout = time.time() + 3600 * 24 * 365
def is_enabled(self):
return self.libraries_available
def device_manager(self):
return self.parent.device_manager
def thread_jobs(self):
# Thread job to handle device timeouts
return [self] if self.libraries_available else []
def run(self):
'''Handle device timeouts. Runs in the context of the Plugins
thread.'''
now = time.time()
for wallet in self.device_manager().paired_wallets():
if (isinstance(wallet, self.wallet_class)
and hasattr(wallet, 'last_operation')
and now > wallet.last_operation + wallet.session_timeout):
wallet.timeout()
wallet.last_operation = self.prevent_timeout
@hook
def close_wallet(self, wallet):
if isinstance(wallet, self.wallet_class):
self.device_manager().unpair_wallet(wallet)
def on_restore_wallet(self, wallet, wizard):
assert isinstance(wallet, self.wallet_class)
msg = _("Enter the seed for your %s wallet:" % self.device)
seed = wizard.request_seed(msg, is_valid = self.is_valid_seed)
# Restored wallets are not hardware wallets
wallet_class = self.wallet_class.restore_wallet_class
wallet.storage.put('wallet_type', wallet_class.wallet_type)
wallet = wallet_class(wallet.storage)
passphrase = wizard.request_passphrase(self.device, restore=True)
password = wizard.request_password()
wallet.add_seed(seed, password)
wallet.add_xprv_from_seed(seed, 'x/', password, passphrase)
wallet.create_hd_account(password)
return wallet
@staticmethod
def is_valid_seed(seed):
return True

44
plugins/ledger/ledger.py

@ -1,12 +1,14 @@
from binascii import hexlify from binascii import hexlify
from struct import unpack from struct import unpack
import hashlib import hashlib
import time
import electrum import electrum
from electrum.bitcoin import EncodeBase58Check, DecodeBase58Check, TYPE_ADDRESS from electrum.bitcoin import EncodeBase58Check, DecodeBase58Check, TYPE_ADDRESS
from electrum.i18n import _ from electrum.i18n import _
from electrum.plugins import BasePlugin, hook from electrum.plugins import BasePlugin, hook
from ..hw_wallet import BIP44_HW_Wallet from ..hw_wallet import BIP44_HW_Wallet
from ..hw_wallet import HW_PluginBase
from electrum.util import format_satoshis_plain, print_error from electrum.util import format_satoshis_plain, print_error
@ -306,18 +308,15 @@ class BTChipWallet(BIP44_HW_Wallet):
return True, response, response return True, response, response
class LedgerPlugin(BasePlugin): class LedgerPlugin(HW_PluginBase):
libraries_available = BTCHIP
wallet_class = BTChipWallet wallet_class = BTChipWallet
def __init__(self, parent, config, name): def __init__(self, parent, config, name):
BasePlugin.__init__(self, parent, config, name) HW_PluginBase.__init__(self, parent, config, name)
self.wallet_class.plugin = self # FIXME shouldn't be a plugin member. Then this constructor can go.
self.device = self.wallet_class.device
self.client = None self.client = None
def is_enabled(self):
return BTCHIP
def btchip_is_connected(self, wallet): def btchip_is_connected(self, wallet):
try: try:
wallet.get_client().getFirmwareVersion() wallet.get_client().getFirmwareVersion()
@ -325,33 +324,6 @@ class LedgerPlugin(BasePlugin):
return False return False
return True return True
@staticmethod
def is_valid_seed(seed):
return True
def on_restore_wallet(self, wallet, wizard):
assert isinstance(wallet, self.wallet_class)
msg = _("Enter the seed for your %s wallet:" % self.device)
seed = wizard.request_seed(msg, is_valid = self.is_valid_seed)
# Restored wallets are not hardware wallets
wallet_class = self.wallet_class.restore_wallet_class
wallet.storage.put('wallet_type', wallet_class.wallet_type)
wallet = wallet_class(wallet.storage)
# Ledger wallets don't use passphrases
passphrase = unicode()
password = wizard.request_password()
wallet.add_seed(seed, password)
wallet.add_xprv_from_seed(seed, 'x/', password, passphrase)
wallet.create_hd_account(password)
return wallet
@hook
def close_wallet(self, wallet):
self.client = None
def get_client(self, wallet, force_pair=True, noPin=False): def get_client(self, wallet, force_pair=True, noPin=False):
aborted = False aborted = False
client = self.client client = self.client
@ -421,4 +393,8 @@ class LedgerPlugin(BasePlugin):
wallet.proper_device = False wallet.proper_device = False
self.client = client self.client = client
if client:
self.print_error("set last_operation")
wallet.last_operation = time.time()
return self.client return self.client

32
plugins/trezor/plugin.py

@ -14,8 +14,7 @@ from electrum.i18n import _
from electrum.plugins import BasePlugin, hook from electrum.plugins import BasePlugin, hook
from electrum.transaction import (deserialize, is_extended_pubkey, from electrum.transaction import (deserialize, is_extended_pubkey,
Transaction, x_to_xpub) Transaction, x_to_xpub)
from ..hw_wallet import BIP44_HW_Wallet from ..hw_wallet import BIP44_HW_Wallet, HW_PluginBase
from electrum.util import ThreadJob
# TREZOR initialization methods # TREZOR initialization methods
@ -85,7 +84,7 @@ class TrezorCompatibleWallet(BIP44_HW_Wallet):
self.plugin.sign_transaction(self, tx, prev_tx, xpub_path) self.plugin.sign_transaction(self, tx, prev_tx, xpub_path)
class TrezorCompatiblePlugin(BasePlugin, ThreadJob): class TrezorCompatiblePlugin(HW_PluginBase):
# Derived classes provide: # Derived classes provide:
# #
# class-static variables: client_class, firmware_URL, handler_class, # class-static variables: client_class, firmware_URL, handler_class,
@ -95,35 +94,12 @@ class TrezorCompatiblePlugin(BasePlugin, ThreadJob):
MAX_LABEL_LEN = 32 MAX_LABEL_LEN = 32
def __init__(self, parent, config, name): def __init__(self, parent, config, name):
BasePlugin.__init__(self, parent, config, name) HW_PluginBase.__init__(self, parent, config, name)
self.main_thread = threading.current_thread() self.main_thread = threading.current_thread()
self.device = self.wallet_class.device # FIXME: move to base class when Ledger is fixed
self.wallet_class.plugin = self
self.prevent_timeout = time.time() + 3600 * 24 * 365
if self.libraries_available: if self.libraries_available:
self.device_manager().register_devices(self.DEVICE_IDS) self.device_manager().register_devices(self.DEVICE_IDS)
def is_enabled(self):
return self.libraries_available
def device_manager(self):
return self.parent.device_manager
def thread_jobs(self):
# Thread job to handle device timeouts
return [self] if self.libraries_available else []
def run(self):
'''Handle device timeouts. Runs in the context of the Plugins
thread.'''
now = time.time()
for wallet in self.device_manager().paired_wallets():
if (isinstance(wallet, self.wallet_class)
and hasattr(wallet, 'last_operation')
and now > wallet.last_operation + wallet.session_timeout):
wallet.timeout()
wallet.last_operation = self.prevent_timeout
def create_client(self, device, handler): def create_client(self, device, handler):
if device.interface_number == 1: if device.interface_number == 1:
pair = [None, device.path] pair = [None, device.path]

Loading…
Cancel
Save