openethereum/js/packages/ledger/ledger.js

137 lines
3.8 KiB
JavaScript
Raw Normal View History

UI support for hardware wallets (#4539) * Add parity_hardwareAccountsInfo * Ledger Promise interface wrapper * Initial hardwarestore * Move ~/views/historyStore to ~/mobx * split scanLedger * test createEntry * Also scan via parity_hardwareAccountsInfo * Explanation for scanning options * react-intl-inify tooltips * add hwstore * Listen for hw walet updates * Return arrays from scanning * Readability * add u2f-api polyfill * check response.errorCode * Support hardware types in state.personal * Tooltips (to be split into sep. PR) * Tooltips support intl strings * FormattedMessage for strings to Tooltip * Fix TabBar tooltip display * signLedger * Use wallets as an object map * PendingForm -> FormattedMessage * Pending form doesn't render password for hardware * Groundwork for JS API signing * Show hardware accounts in list * Cleanup rendering conditions * Update RequestPending rendering tests (verification) * Tests for extended signer middleware * sign properly & handle response, error * Align outputs between Parity & Ledger u2f * Ledger returns checksummed addresses * Update ethereum-tx for EIP155 support * Update construction of tx * Updates after sanity checks (thanks @tomusdrw) * Allow display for disabled IdentityIcon * Disabled accounts * Disabled auto-disabling * Password button ebaled for hardware * Don't display password hint for hardware * Disable non-applicable options when not connected * Fix failing test * Confirmation via ledger (u2f) * Confirm on device message * Cleanups & support checks * Mark u2f as unsupported (until https) * rewording * Pass account & disabled flags * Render attach device message * Use isConnected for checking availability * Show hardware accounts in defaults list * Pass signerstore * Update u2f to correct version * remove debug u2f lib * Update test (prop name change) * Add ETC path (future work) * new Buffer -> Buffer.from (thanks @derhuerst)
2017-03-02 23:51:56 +01:00
// Copyright 2015-2017 Parity Technologies (UK) Ltd.
// This file is part of Parity.
// Parity 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.
// Parity 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 Parity. If not, see <http://www.gnu.org/licenses/>.
import 'u2f-api-polyfill';
import BigNumber from 'bignumber.js';
import Transaction from 'ethereumjs-tx';
import u2fapi from 'u2f-api';
import Ledger3 from './vendor/ledger3';
import LedgerEth from './vendor/ledger-eth';
const LEDGER_PATH_ETC = "44/60/160720'/0'/0";
const LEDGER_PATH_ETH = "44'/60'/0'/0";
const SCRAMBLE_KEY = 'w0w';
function numberToHex (number) {
return `0x${new BigNumber(number).toString(16)}`;
}
export default class Ledger {
constructor (api, ledger) {
this._api = api;
this._ledger = ledger;
this._isSupported = false;
this.checkJSSupport();
}
// FIXME: Until we have https support from Parity u2f will not work. Here we mark it completely
// as unsupported until a full end-to-end environment is available.
get isSupported () {
return false && this._isSupported;
}
checkJSSupport () {
return u2fapi
.isSupported()
.then((isSupported) => {
console.log('Ledger:checkJSSupport', isSupported);
this._isSupported = isSupported;
});
}
getAppConfiguration () {
return new Promise((resolve, reject) => {
this._ledger.getAppConfiguration((response, error) => {
if (error) {
reject(error);
return;
}
resolve(response);
});
});
}
scan () {
return new Promise((resolve, reject) => {
this._ledger.getAddress(LEDGER_PATH_ETH, (response, error) => {
if (error) {
reject(error);
return;
}
resolve([response.address]);
}, true, false);
});
}
signTransaction (transaction) {
return this._api.net.version().then((_chainId) => {
return new Promise((resolve, reject) => {
const chainId = new BigNumber(_chainId).toNumber();
const tx = new Transaction({
data: transaction.data || transaction.input,
gasPrice: numberToHex(transaction.gasPrice),
gasLimit: numberToHex(transaction.gasLimit),
nonce: numberToHex(transaction.nonce),
to: transaction.to ? transaction.to.toLowerCase() : undefined,
value: numberToHex(transaction.value),
v: Buffer.from([chainId]), // pass the chainId to the ledger
r: Buffer.from([]),
s: Buffer.from([])
});
const rawTransaction = tx.serialize().toString('hex');
this._ledger.signTransaction(LEDGER_PATH_ETH, rawTransaction, (response, error) => {
if (error) {
reject(error);
return;
}
tx.v = Buffer.from(response.v, 'hex');
tx.r = Buffer.from(response.r, 'hex');
tx.s = Buffer.from(response.s, 'hex');
if (chainId !== Math.floor((tx.v[0] - 35) / 2)) {
reject(new Error('Invalid EIP155 signature received from Ledger.'));
return;
}
resolve(`0x${tx.serialize().toString('hex')}`);
});
});
});
}
static create (api, ledger) {
if (!ledger) {
ledger = new LedgerEth(new Ledger3(SCRAMBLE_KEY));
}
return new Ledger(api, ledger);
}
}
export {
LEDGER_PATH_ETC,
LEDGER_PATH_ETH
};