Skip to content

Commit

Permalink
added offline ledger and trezor support. upgraded trezor doesn't work…
Browse files Browse the repository at this point in the history
…, though
  • Loading branch information
sadoci committed Apr 5, 2019
1 parent f6e0c93 commit e446af9
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 23 deletions.
179 changes: 179 additions & 0 deletions accounts/usbwallet/offline.go
@@ -0,0 +1,179 @@
// Copyright 2019 The go-ethereum / go-metadium Authors
// This file is part of the go-ethereum library.
//
// The go-ethereum 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.
//
// The go-ethereum 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 the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.

package usbwallet

import (
"errors"
"io"
"math/big"

"github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/log"
"github.com/karalabe/hid"
)

// a simple wrapper for offline use, mainly for Close()
type offlineWallet struct {
driver driver
info hid.DeviceInfo
device *hid.Device
log log.Logger
}

// dummy Hub structures for offline wallet use
var (
offlineHubs []*Hub
)

func init() {
// nano ledger
offlineHubs = append(offlineHubs, &Hub{
scheme: LedgerScheme,
vendorID: 0x2c97,
productIDs: []uint16{0x0000, 0x0001},
usageID: 0xffa0,
endpointID: 0,
})
// trezor 1
offlineHubs = append(offlineHubs, &Hub{
scheme: TrezorScheme,
vendorID: 0x534c,
productIDs: []uint16{0x0001},
usageID: 0xff00,
endpointID: 0,
})
// trezor 2, this doesn't seem to work yet.
offlineHubs = append(offlineHubs, &Hub{
scheme: TrezorScheme,
vendorID: 0x1209,
productIDs: []uint16{0x53c0, 0x53c1},
usageID: 0xf1d0,
endpointID: -1,
})
}

func (w *offlineWallet) Status() (string, error) {
return w.driver.Status()
}

func (w *offlineWallet) Open(device io.ReadWriter, passphrase string) error {
return w.driver.Open(device, passphrase)
}

func (w *offlineWallet) Close() error {
if w.device == nil {
return nil
}
w.driver.Close()
w.device.Close()
w.device = nil
return nil
}

func (w *offlineWallet) Heartbeat() error {
return w.driver.Heartbeat()
}

func (w *offlineWallet) Derive(path accounts.DerivationPath) (common.Address, error) {
return w.driver.Derive(path)
}

func (w *offlineWallet) SignTx(path accounts.DerivationPath, tx *types.Transaction, chainID *big.Int) (common.Address, *types.Transaction, error) {
return w.driver.SignTx(path, tx, chainID)
}

// ListDevices returns the array of ledger or trezor device paths
// for mostly informational use
func ListDevices(scheme string) []string {
var devices []string

// triple loop!
for _, hub := range offlineHubs {
if len(scheme) > 0 && hub.scheme != scheme {
continue
}
for _, info := range hid.Enumerate(hub.vendorID, 0) {
for _, id := range hub.productIDs {
if info.ProductID == id && (info.UsagePage == hub.usageID || info.Interface == hub.endpointID) {
devices = append(devices, info.Path)
break
}
}
}
}
return devices
}

// OpenOffline opens usb wallet for offline use.
// If path is not specified, the first device is used.
// Note that Trezor 1 after firmware upgrade doesn't work any more.
func OpenOffline(scheme, path string) (interface{}, error) {
if scheme != LedgerScheme && scheme != TrezorScheme {
return nil, errors.New("Not Supported")
}
if path == "" {
paths := ListDevices(scheme)
if len(paths) == 0 {
return nil, errors.New("Not Found")
}
path = paths[0]
}

for _, hub := range offlineHubs {
if hub.scheme != scheme {
continue
}
for _, info := range hid.Enumerate(hub.vendorID, 0) {
if info.Path == path {
if scheme == TrezorScheme && info.Interface == -1 {
// Trezor 2. It's going to hang. Stop here.
return nil, errors.New("Trezor 2 doesn't work yet. You shouldn't have upgraded the firmware.")
}

logger := log.New("url", accounts.URL{Scheme: scheme, Path: path})
var drv driver
switch scheme {
case LedgerScheme:
drv = newLedgerDriver(logger)
case TrezorScheme:
drv = newTrezorDriver(logger)
}
device, err := info.Open()
if err != nil {
return nil, err
}
err = drv.Open(device, "")
if err != nil {
return nil, err
}
w := &offlineWallet{
driver: drv,
info: info,
device: device,
log: logger,
}
return w, nil
}
}
}

return nil, errors.New("Not Found")
}

// EOF
1 change: 1 addition & 0 deletions internal/jsre/jsre.go
Expand Up @@ -84,6 +84,7 @@ func New(assetPath string, output io.Writer) *JSRE {
re.Set("offlineWalletAddress", re.offlineWalletAddress)
re.Set("offlineWalletClose", re.offlineWalletClose)
re.Set("offlineWalletSignTx", re.offlineWalletSignTx)
re.Set("offlineWalletList", re.offlineWalletList)
return re
}

Expand Down

0 comments on commit e446af9

Please sign in to comment.