aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBruno <brunobar79@gmail.com>2018-06-13 13:32:13 +0800
committerBruno <brunobar79@gmail.com>2018-06-13 13:32:13 +0800
commit8763ea898e7838d08315063b0e2181405a2ae3d5 (patch)
tree3acb847a6353e8451dc406d4f3d50f6bf61baebe
parentd4201ae1cc990ba6b69e84586caabc0848c2c38e (diff)
downloadtangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.tar
tangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.tar.gz
tangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.tar.bz2
tangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.tar.lz
tangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.tar.xz
tangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.tar.zst
tangerine-wallet-browser-8763ea898e7838d08315063b0e2181405a2ae3d5.zip
move TrezorKeyring to its own package
-rw-r--r--app/scripts/lib/trezor-connect.js1138
-rw-r--r--app/scripts/lib/trezorKeyring.js239
-rw-r--r--app/scripts/metamask-controller.js5
-rw-r--r--package-lock.json46
-rw-r--r--package.json2
-rw-r--r--ui/app/components/pages/create-account/connect-hardware.js6
6 files changed, 53 insertions, 1383 deletions
diff --git a/app/scripts/lib/trezor-connect.js b/app/scripts/lib/trezor-connect.js
deleted file mode 100644
index 574e88104..000000000
--- a/app/scripts/lib/trezor-connect.js
+++ /dev/null
@@ -1,1138 +0,0 @@
-/* eslint-disable */
-/* prettier-ignore */
-
-/**
- * (C) 2017 SatoshiLabs
- *
- * GPLv3
- */
-var TREZOR_CONNECT_VERSION = 4;
-
-if (!Array.isArray) {
- Array.isArray = function(arg) {
- return Object.prototype.toString.call(arg) === "[object Array]";
- };
-}
-
-var HD_HARDENED = 0x80000000;
-
-// react sometimes adds some other parameters that should not be there
-function _fwStrFix(obj, fw) {
- if (typeof fw === "string") {
- obj.requiredFirmware = fw;
- }
- return obj;
-}
-
-("use strict");
-
-var chrome = window.chrome;
-var IS_CHROME_APP = chrome && chrome.app && chrome.app.window;
-
-var ERR_TIMED_OUT = "Loading timed out";
-var ERR_WINDOW_CLOSED = "Window closed";
-var ERR_WINDOW_BLOCKED = "Window blocked";
-var ERR_ALREADY_WAITING = "Already waiting for a response";
-var ERR_CHROME_NOT_CONNECTED = "Internal Chrome popup is not responding.";
-
-var DISABLE_LOGIN_BUTTONS = window.TREZOR_DISABLE_LOGIN_BUTTONS || false;
-var CHROME_URL = window.TREZOR_CHROME_URL || "./chrome/wrapper.html";
-var POPUP_ORIGIN = window.TREZOR_POPUP_ORIGIN || "https://connect.trezor.io";
-var POPUP_PATH =
- window.TREZOR_POPUP_PATH || POPUP_ORIGIN + "/" + TREZOR_CONNECT_VERSION;
-var POPUP_URL =
- window.TREZOR_POPUP_URL ||
- POPUP_PATH + "/popup/popup.html?v=" + new Date().getTime();
-
-var POPUP_INIT_TIMEOUT = 15000;
-
-/**
- * Public API.
- */
-function TrezorConnect() {
- var manager = new PopupManager();
-
- /**
- * Popup errors.
- */
- this.ERR_TIMED_OUT = ERR_TIMED_OUT;
- this.ERR_WINDOW_CLOSED = ERR_WINDOW_CLOSED;
- this.ERR_WINDOW_BLOCKED = ERR_WINDOW_BLOCKED;
- this.ERR_ALREADY_WAITING = ERR_ALREADY_WAITING;
- this.ERR_CHROME_NOT_CONNECTED = ERR_CHROME_NOT_CONNECTED;
-
- /**
- * Open the popup for further communication. All API functions open the
- * popup automatically, but if you need to generate some parameters
- * asynchronously, use `open` first to avoid popup blockers.
- * @param {function(?Error)} callback
- */
- this.open = function(callback) {
- var onchannel = function(result) {
- if (result instanceof Error) {
- callback(result);
- } else {
- callback();
- }
- };
- manager.waitForChannel(onchannel);
- };
-
- /**
- * Close the opened popup, if any.
- */
- this.close = function() {
- manager.close();
- };
-
- /**
- * Enable or disable closing the opened popup after a successful call.
- * @param {boolean} value
- */
- this.closeAfterSuccess = function(value) {
- manager.closeAfterSuccess = value;
- };
-
- /**
- * Enable or disable closing the opened popup after a failed call.
- * @param {boolean} value
- */
- this.closeAfterFailure = function(value) {
- manager.closeAfterFailure = value;
- };
-
- /**
- * Set bitcore server
- * @param {string|Array<string>} value
- */
- this.setBitcoreURLS = function(value) {
- if (typeof value === "string") {
- manager.bitcoreURLS = [value];
- } else if (value instanceof Array) {
- manager.bitcoreURLS = value;
- }
- };
-
- /**
- * Set currency. Human readable coin name
- * @param {string|Array<string>} value
- */
- this.setCurrency = function(value) {
- if (typeof value === "string") {
- manager.currency = value;
- }
- };
-
- /**
- * Set currency units (mBTC, BTC)
- * @param {string|Array<string>} value
- */
- this.setCurrencyUnits = function(value) {
- if (typeof value === "string") {
- manager.currencyUnits = value;
- }
- };
-
- /**
- * Set coin info json url
- * @param {string|Array<string>} value
- */
- this.setCoinInfoURL = function(value) {
- if (typeof value === "string") {
- manager.coinInfoURL = value;
- }
- };
-
- /**
- * Set max. limit for account discovery
- * @param {number} value
- */
- this.setAccountDiscoveryLimit = function(value) {
- if (!isNaN(value)) manager.accountDiscoveryLimit = value;
- };
-
- /**
- * Set max. gap for account discovery
- * @param {number} value
- */
- this.setAccountDiscoveryGapLength = function(value) {
- if (!isNaN(value)) manager.accountDiscoveryGapLength = value;
- };
-
- /**
- * Set discovery BIP44 coin type
- * @param {number} value
- */
- this.setAccountDiscoveryBip44CoinType = function(value) {
- if (!isNaN(value)) manager.accountDiscoveryBip44CoinType = value;
- };
-
- /**
- * @typedef XPubKeyResult
- * @param {boolean} success
- * @param {?string} error
- * @param {?string} xpubkey serialized extended public key
- * @param {?string} path BIP32 serializd path of the key
- */
-
- /**
- * Load BIP32 extended public key by path.
- *
- * Path can be specified either in the string form ("m/44'/1/0") or as
- * raw integer array. In case you omit the path, user is asked to select
- * a BIP32 account to export, and the result contains m/44'/0'/x' node
- * of the account.
- *
- * @param {?(string|array<number>)} path
- * @param {function(XPubKeyResult)} callback
- * @param {?(string|array<number>)} requiredFirmware
- */
- this.getXPubKey = function(path, callback, requiredFirmware) {
- if (typeof path === "string") {
- path = parseHDPath(path);
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "xpubkey",
- path: path
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- this.getFreshAddress = function(callback, requiredFirmware) {
- var wrapperCallback = function(result) {
- if (result.success) {
- callback({ success: true, address: result.freshAddress });
- } else {
- callback(result);
- }
- };
-
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "accountinfo"
- },
- requiredFirmware
- ),
- wrapperCallback
- );
- };
-
- this.getAccountInfo = function(input, callback, requiredFirmware) {
- try {
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "accountinfo",
- description: input
- },
- requiredFirmware
- ),
- callback
- );
- } catch (e) {
- callback({ success: false, error: e });
- }
- };
-
- this.getAllAccountsInfo = function(callback, requiredFirmware) {
- try {
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "allaccountsinfo",
- description: "all"
- },
- requiredFirmware
- ),
- callback
- );
- } catch (e) {
- callback({ success: false, error: e });
- }
- };
-
- this.getBalance = function(callback, requiredFirmware) {
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "accountinfo"
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * @typedef SignTxResult
- * @param {boolean} success
- * @param {?string} error
- * @param {?string} serialized_tx serialized tx, in hex, including signatures
- * @param {?array<string>} signatures array of input signatures, in hex
- */
-
- /**
- * Sign a transaction in the device and return both serialized
- * transaction and the signatures.
- *
- * @param {array<TxInputType>} inputs
- * @param {array<TxOutputType>} outputs
- * @param {function(SignTxResult)} callback
- * @param {?(string|array<number>)} requiredFirmware
- *
- * @see https://github.com/trezor/trezor-common/blob/master/protob/types.proto
- */
- this.signTx = function(inputs, outputs, callback, requiredFirmware, coin) {
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "signtx",
- inputs: inputs,
- outputs: outputs,
- coin: coin
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- // new implementation with ethereum at beginnig
- this.ethereumSignTx = function() {
- this.signEthereumTx.apply(this, arguments);
- };
-
- // old fallback
- this.signEthereumTx = function(
- address_n,
- nonce,
- gas_price,
- gas_limit,
- to,
- value,
- data,
- chain_id,
- callback,
- requiredFirmware
- ) {
- if (requiredFirmware == null) {
- requiredFirmware = "1.4.0"; // first firmware that supports ethereum
- }
- if (typeof address_n === "string") {
- address_n = parseHDPath(address_n);
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "signethtx",
- address_n: address_n,
- nonce: nonce,
- gas_price: gas_price,
- gas_limit: gas_limit,
- to: to,
- value: value,
- data: data,
- chain_id: chain_id
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * @typedef TxRecipient
- * @param {number} amount the amount to send, in satoshis
- * @param {string} address the address of the recipient
- */
-
- /**
- * Compose a transaction by doing BIP-0044 discovery, letting the user
- * select an account, and picking UTXO by internal preferences.
- * Transaction is then signed and returned in the same format as
- * `signTx`. Only supports BIP-0044 accounts (single-signature).
- *
- * @param {array<TxRecipient>} recipients
- * @param {function(SignTxResult)} callback
- * @param {?(string|array<number>)} requiredFirmware
- */
- this.composeAndSignTx = function(recipients, callback, requiredFirmware) {
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "composetx",
- recipients: recipients
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * @typedef RequestLoginResult
- * @param {boolean} success
- * @param {?string} error
- * @param {?string} public_key public key used for signing, in hex
- * @param {?string} signature signature, in hex
- */
-
- /**
- * Sign a login challenge for active origin.
- *
- * @param {?string} hosticon
- * @param {string} challenge_hidden
- * @param {string} challenge_visual
- * @param {string|function(RequestLoginResult)} callback
- * @param {?(string|array<number>)} requiredFirmware
- *
- * @see https://github.com/trezor/trezor-common/blob/master/protob/messages.proto
- */
- this.requestLogin = function(
- hosticon,
- challenge_hidden,
- challenge_visual,
- callback,
- requiredFirmware
- ) {
- if (typeof callback === "string") {
- // special case for a login through <trezor:login> button.
- // `callback` is name of global var
- callback = window[callback];
- }
- if (!callback) {
- throw new TypeError("TrezorConnect: login callback not found");
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "login",
- icon: hosticon,
- challenge_hidden: challenge_hidden,
- challenge_visual: challenge_visual
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * @typedef SignMessageResult
- * @param {boolean} success
- * @param {?string} error
- * @param {?string} address address (in base58check)
- * @param {?string} signature signature, in base64
- */
-
- /**
- * Sign a message
- *
- * @param {string|array} path
- * @param {string} message to sign (ascii)
- * @param {string|function(SignMessageResult)} callback
- * @param {?string} opt_coin - (optional) name of coin (default Bitcoin)
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.signMessage = function(
- path,
- message,
- callback,
- opt_coin,
- requiredFirmware
- ) {
- if (typeof path === "string") {
- path = parseHDPath(path);
- }
- if (!opt_coin) {
- opt_coin = "Bitcoin";
- }
- if (!callback) {
- throw new TypeError("TrezorConnect: callback not found");
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "signmsg",
- path: path,
- message: message,
- coin: opt_coin
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * Sign an Ethereum message
- *
- * @param {string|array} path
- * @param {string} message to sign (ascii)
- * @param {string|function(SignMessageResult)} callback
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.ethereumSignMessage = function(
- path,
- message,
- callback,
- requiredFirmware
- ) {
- if (typeof path === "string") {
- path = parseHDPath(path);
- }
- if (!callback) {
- throw new TypeError("TrezorConnect: callback not found");
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "signethmsg",
- path: path,
- message: message
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * Verify message
- *
- * @param {string} address
- * @param {string} signature (base64)
- * @param {string} message (string)
- * @param {string|function()} callback
- * @param {?string} opt_coin - (optional) name of coin (default Bitcoin)
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.verifyMessage = function(
- address,
- signature,
- message,
- callback,
- opt_coin,
- requiredFirmware
- ) {
- if (!opt_coin) {
- opt_coin = "Bitcoin";
- }
- if (!callback) {
- throw new TypeError("TrezorConnect: callback not found");
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "verifymsg",
- address: address,
- signature: signature,
- message: message,
- coin: { coin_name: opt_coin }
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * Verify ethereum message
- *
- * @param {string} address
- * @param {string} signature (base64)
- * @param {string} message (string)
- * @param {string|function()} callback
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.ethereumVerifyMessage = function(
- address,
- signature,
- message,
- callback,
- requiredFirmware
- ) {
- if (!callback) {
- throw new TypeError("TrezorConnect: callback not found");
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "verifyethmsg",
- address: address,
- signature: signature,
- message: message
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * Symmetric key-value encryption
- *
- * @param {string|array} path
- * @param {string} key to show on device display
- * @param {string} value hexadecimal value, length a multiple of 16 bytes
- * @param {boolean} encrypt / decrypt direction
- * @param {boolean} ask_on_encrypt (should user confirm on encrypt?)
- * @param {boolean} ask_on_decrypt (should user confirm on decrypt?)
- * @param {string|function()} callback
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.cipherKeyValue = function(
- path,
- key,
- value,
- encrypt,
- ask_on_encrypt,
- ask_on_decrypt,
- callback,
- requiredFirmware
- ) {
- if (typeof path === "string") {
- path = parseHDPath(path);
- }
- if (typeof value !== "string") {
- throw new TypeError("TrezorConnect: Value must be a string");
- }
- if (!/^[0-9A-Fa-f]*$/.test(value)) {
- throw new TypeError("TrezorConnect: Value must be hexadecimal");
- }
- if (value.length % 32 !== 0) {
- // 1 byte == 2 hex strings
- throw new TypeError(
- "TrezorConnect: Value length must be multiple of 16 bytes"
- );
- }
- if (!callback) {
- throw new TypeError("TrezorConnect: callback not found");
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "cipherkeyvalue",
- path: path,
- key: key,
- value: value,
- encrypt: !!encrypt,
- ask_on_encrypt: !!ask_on_encrypt,
- ask_on_decrypt: !!ask_on_decrypt
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- this.nemGetAddress = function(
- address_n,
- network,
- callback,
- requiredFirmware
- ) {
- if (requiredFirmware == null) {
- requiredFirmware = "1.6.0"; // first firmware that supports NEM
- }
- if (typeof address_n === "string") {
- address_n = parseHDPath(address_n);
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "nemGetAddress",
- address_n: address_n,
- network: network
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- this.nemSignTx = function(
- address_n,
- transaction,
- callback,
- requiredFirmware
- ) {
- if (requiredFirmware == null) {
- requiredFirmware = "1.6.0"; // first firmware that supports NEM
- }
- if (typeof address_n === "string") {
- address_n = parseHDPath(address_n);
- }
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "nemSignTx",
- address_n: address_n,
- transaction: transaction
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- this.pushTransaction = function(rawTx, callback) {
- if (!/^[0-9A-Fa-f]*$/.test(rawTx)) {
- throw new TypeError("TrezorConnect: Transaction must be hexadecimal");
- }
- if (!callback) {
- throw new TypeError("TrezorConnect: callback not found");
- }
-
- manager.sendWithChannel(
- {
- type: "pushtx",
- rawTx: rawTx
- },
- callback
- );
- };
-
- /**
- * Display address on device
- *
- * @param {array} address
- * @param {string} coin
- * @param {boolean} segwit
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.getAddress = function(
- address,
- coin,
- segwit,
- callback,
- requiredFirmware
- ) {
- if (typeof address === "string") {
- address = parseHDPath(address);
- }
-
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "getaddress",
- address_n: address,
- coin: coin,
- segwit: segwit
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- /**
- * Display ethereum address on device
- *
- * @param {array} address
- * @param {?(string|array<number>)} requiredFirmware
- *
- */
- this.ethereumGetAddress = function(address, callback, requiredFirmware) {
- if (typeof address === "string") {
- address = parseHDPath(address);
- }
-
- manager.sendWithChannel(
- _fwStrFix(
- {
- type: "ethgetaddress",
- address_n: address
- },
- requiredFirmware
- ),
- callback
- );
- };
-
- var LOGIN_CSS =
- '<style>@import url("@connect_path@/login_buttons.css")</style>';
-
- var LOGIN_ONCLICK =
- "TrezorConnect.requestLogin(" +
- "'@hosticon@','@challenge_hidden@','@challenge_visual@','@callback@'" +
- ")";
-
- var LOGIN_HTML =
- '<div id="trezorconnect-wrapper">' +
- ' <a id="trezorconnect-button" onclick="' +
- LOGIN_ONCLICK +
- '">' +
- ' <span id="trezorconnect-icon"></span>' +
- ' <span id="trezorconnect-text">@text@</span>' +
- " </a>" +
- ' <span id="trezorconnect-info">' +
- ' <a id="trezorconnect-infolink" href="https://www.buytrezor.com/"' +
- ' target="_blank">What is TREZOR?</a>' +
- " </span>" +
- "</div>";
-
- /**
- * Find <trezor:login> elements and replace them with login buttons.
- * It's not required to use these special elements, feel free to call
- * `TrezorConnect.requestLogin` directly.
- */
- this.renderLoginButtons = function() {
- var elements = document.getElementsByTagName("trezor:login");
-
- for (var i = 0; i < elements.length; i++) {
- var e = elements[i];
- var text = e.getAttribute("text") || "Sign in with TREZOR";
- var callback = e.getAttribute("callback") || "";
- var hosticon = e.getAttribute("icon") || "";
- var challenge_hidden = e.getAttribute("challenge_hidden") || "";
- var challenge_visual = e.getAttribute("challenge_visual") || "";
-
- // it's not valid to put markup into attributes, so let users
- // supply a raw text and make TREZOR bold
- text = text.replace("TREZOR", "<strong>TREZOR</strong>");
- e.outerHTML = (LOGIN_CSS + LOGIN_HTML)
- .replace("@text@", text)
- .replace("@callback@", callback)
- .replace("@hosticon@", hosticon)
- .replace("@challenge_hidden@", challenge_hidden)
- .replace("@challenge_visual@", challenge_visual)
- .replace("@connect_path@", POPUP_PATH);
- }
- };
-}
-
-/*
- * `getXPubKey()`
- */
-
-function parseHDPath(string) {
- return string
- .toLowerCase()
- .split("/")
- .filter(function(p) {
- return p !== "m";
- })
- .map(function(p) {
- var hardened = false;
- if (p[p.length - 1] === "'") {
- hardened = true;
- p = p.substr(0, p.length - 1);
- }
- if (isNaN(p)) {
- throw new Error("Not a valid path.");
- }
- var n = parseInt(p);
- if (hardened) {
- // hardened index
- n = (n | 0x80000000) >>> 0;
- }
- return n;
- });
-}
-
-/*
- * Popup management
- */
-
-function ChromePopup(url, name, width, height) {
- var left = (screen.width - width) / 2;
- var top = (screen.height - height) / 2;
- var opts = {
- id: name,
- innerBounds: {
- width: width,
- height: height,
- left: left,
- top: top
- }
- };
-
- var closed = function() {
- if (this.onclose) {
- this.onclose(false); // never report as blocked
- }
- }.bind(this);
-
- var opened = function(w) {
- this.window = w;
- this.window.onClosed.addListener(closed);
- }.bind(this);
-
- chrome.app.window.create(url, opts, opened);
-
- this.name = name;
- this.window = null;
- this.onclose = null;
-}
-
-function ChromeChannel(popup, waiting) {
- var port = null;
-
- var respond = function(data) {
- if (waiting) {
- var w = waiting;
- waiting = null;
- w(data);
- }
- };
-
- var setup = function(p) {
- if (p.name === popup.name) {
- port = p;
- port.onMessage.addListener(respond);
- chrome.runtime.onConnect.removeListener(setup);
- }
- };
-
- chrome.runtime.onConnect.addListener(setup);
-
- this.respond = respond;
-
- this.close = function() {
- chrome.runtime.onConnect.removeListener(setup);
- port.onMessage.removeListener(respond);
- port.disconnect();
- port = null;
- };
-
- this.send = function(value, callback) {
- if (waiting === null) {
- waiting = callback;
-
- if (port) {
- port.postMessage(value);
- } else {
- throw new Error(ERR_CHROME_NOT_CONNECTED);
- }
- } else {
- throw new Error(ERR_ALREADY_WAITING);
- }
- };
-}
-
-function Popup(url, origin, name, width, height) {
- var left = (screen.width - width) / 2;
- var top = (screen.height - height) / 2;
- var opts =
- "width=" +
- width +
- ",height=" +
- height +
- ",left=" +
- left +
- ",top=" +
- top +
- ",menubar=no" +
- ",toolbar=no" +
- ",location=no" +
- ",personalbar=no" +
- ",status=no";
- var w = window.open(url, name, opts);
-
- var interval;
- var blocked = w.closed;
- var iterate = function() {
- if (w.closed) {
- clearInterval(interval);
- if (this.onclose) {
- this.onclose(blocked);
- }
- }
- }.bind(this);
- interval = setInterval(iterate, 100);
-
- this.window = w;
- this.origin = origin;
- this.onclose = null;
-}
-
-function Channel(popup, waiting) {
- var respond = function(data) {
- if (waiting) {
- var w = waiting;
- waiting = null;
- w(data);
- }
- };
-
- var receive = function(event) {
- var org1 = event.origin.match(/^.+\:\/\/[^\‌​/]+/)[0];
- var org2 = popup.origin.match(/^.+\:\/\/[^\‌​/]+/)[0];
- //if (event.source === popup.window && event.origin === popup.origin) {
- if (event.source === popup.window && org1 === org2) {
- respond(event.data);
- }
- };
-
- window.addEventListener("message", receive);
-
- this.respond = respond;
-
- this.close = function() {
- window.removeEventListener("message", receive);
- };
-
- this.send = function(value, callback) {
- if (waiting === null) {
- waiting = callback;
- popup.window.postMessage(value, popup.origin);
- } else {
- throw new Error(ERR_ALREADY_WAITING);
- }
- };
-}
-
-function ConnectedChannel(p) {
- var ready = function() {
- clearTimeout(this.timeout);
- this.popup.onclose = null;
- this.ready = true;
- this.onready();
- }.bind(this);
-
- var closed = function(blocked) {
- clearTimeout(this.timeout);
- this.channel.close();
- if (blocked) {
- this.onerror(new Error(ERR_WINDOW_BLOCKED));
- } else {
- this.onerror(new Error(ERR_WINDOW_CLOSED));
- }
- }.bind(this);
-
- var timedout = function() {
- this.popup.onclose = null;
- if (this.popup.window) {
- this.popup.window.close();
- }
- this.channel.close();
- this.onerror(new Error(ERR_TIMED_OUT));
- }.bind(this);
-
- if (IS_CHROME_APP) {
- this.popup = new ChromePopup(p.chromeUrl, p.name, p.width, p.height);
- this.channel = new ChromeChannel(this.popup, ready);
- } else {
- this.popup = new Popup(p.url, p.origin, p.name, p.width, p.height);
- this.channel = new Channel(this.popup, ready);
- }
-
- this.timeout = setTimeout(timedout, POPUP_INIT_TIMEOUT);
-
- this.popup.onclose = closed;
-
- this.ready = false;
- this.onready = null;
- this.onerror = null;
-}
-
-function PopupManager() {
- var cc = null;
-
- var closed = function() {
- cc.channel.respond(new Error(ERR_WINDOW_CLOSED));
- cc.channel.close();
- cc = null;
- };
-
- var open = function(callback) {
- cc = new ConnectedChannel({
- name: "trezor-connect",
- width: 600,
- height: 500,
- origin: POPUP_ORIGIN,
- path: POPUP_PATH,
- url: POPUP_URL,
- chromeUrl: CHROME_URL
- });
- cc.onready = function() {
- cc.popup.onclose = closed;
- callback(cc.channel);
- };
- cc.onerror = function(error) {
- cc = null;
- callback(error);
- };
- }.bind(this);
-
- this.closeAfterSuccess = true;
- this.closeAfterFailure = true;
-
- this.close = function() {
- if (cc && cc.popup.window) {
- cc.popup.window.close();
- }
- };
-
- this.waitForChannel = function(callback) {
- if (cc) {
- if (cc.ready) {
- callback(cc.channel);
- } else {
- callback(new Error(ERR_ALREADY_WAITING));
- }
- } else {
- try {
- open(callback);
- } catch (e) {
- callback(new Error(ERR_WINDOW_BLOCKED));
- }
- }
- };
-
- this.sendWithChannel = function(message, callback) {
- message.bitcoreURLS = this.bitcoreURLS || null;
- message.currency = this.currency || null;
- message.currencyUnits = this.currencyUnits || null;
- message.coinInfoURL = this.coinInfoURL || null;
- message.accountDiscoveryLimit = this.accountDiscoveryLimit || null;
- message.accountDiscoveryGapLength = this.accountDiscoveryGapLength || null;
- message.accountDiscoveryBip44CoinType =
- this.accountDiscoveryBip44CoinType || null;
-
- var respond = function(response) {
- var succ = response.success && this.closeAfterSuccess;
- var fail = !response.success && this.closeAfterFailure;
- if (succ || fail) {
- this.close();
- }
- callback(response);
- }.bind(this);
-
- var onresponse = function(response) {
- if (response instanceof Error) {
- var error = response;
- respond({ success: false, error: error.message });
- } else {
- respond(response);
- }
- };
-
- var onchannel = function(channel) {
- if (channel instanceof Error) {
- var error = channel;
- respond({ success: false, error: error.message });
- } else {
- channel.send(message, onresponse);
- }
- };
-
- this.waitForChannel(onchannel);
- };
-}
-
-const connect = new TrezorConnect();
-module.exports = connect; \ No newline at end of file
diff --git a/app/scripts/lib/trezorKeyring.js b/app/scripts/lib/trezorKeyring.js
deleted file mode 100644
index 6a483fdcd..000000000
--- a/app/scripts/lib/trezorKeyring.js
+++ /dev/null
@@ -1,239 +0,0 @@
-const { EventEmitter } = require('events')
-const ethUtil = require('ethereumjs-util')
-const sigUtil = require('eth-sig-util')
-
-const hdPathString = `m/44'/60'/0'/0`
-const keyringType = 'Trezor Hardware'
-const Transaction = require('ethereumjs-tx')
-const pathBase = 'm'
-const TrezorConnect = require('./trezor-connect.js')
-const HDKey = require('hdkey')
-const TREZOR_MIN_FIRMWARE_VERSION = '1.5.2'
-const log = require('loglevel')
-
-class TrezorKeyring extends EventEmitter {
- constructor (opts = {}) {
- super()
- this.type = keyringType
- this.accounts = []
- this.hdk = new HDKey()
- this.deserialize(opts)
- this.page = 0
- this.perPage = 5
- this.unlockedAccount = 0
- }
-
- serialize () {
- return Promise.resolve({
- hdPath: this.hdPath,
- accounts: this.accounts,
- page: this.page,
- })
- }
-
- deserialize (opts = {}) {
- this.hdPath = opts.hdPath || hdPathString
- this.accounts = opts.accounts || []
- this.page = opts.page || 0
- return Promise.resolve()
- }
-
- unlock () {
-
- if (this.hdk.publicKey) return Promise.resolve()
-
- return new Promise((resolve, reject) => {
- TrezorConnect.getXPubKey(
- this.hdPath,
- response => {
- if (response.success) {
- this.hdk.publicKey = new Buffer(response.publicKey, 'hex')
- this.hdk.chainCode = new Buffer(response.chainCode, 'hex')
- resolve()
- } else {
- reject(response.error || 'Unknown error')
- }
- },
- TREZOR_MIN_FIRMWARE_VERSION
- )
- })
- }
-
- setAccountToUnlock (index) {
- this.unlockedAccount = parseInt(index, 10)
- }
-
- addAccounts (n = 1) {
-
- return new Promise((resolve, reject) => {
- return this.unlock()
- .then(_ => {
- const from = this.unlockedAccount
- const to = from + 1
- this.accounts = []
-
- for (let i = from; i < to; i++) {
-
- this.accounts.push(this._addressFromId(pathBase, i))
- this.page = 0
- }
- resolve(this.accounts)
- })
- .catch(e => {
- reject(e)
- })
- })
- }
-
- getPage () {
-
- return new Promise((resolve, reject) => {
- return this.unlock()
- .then(_ => {
-
- const from = this.page === 0 ? 0 : (this.page - 1) * this.perPage
- const to = from + this.perPage
-
- const accounts = []
-
- for (let i = from; i < to; i++) {
-
- accounts.push({
- address: this._addressFromId(pathBase, i),
- balance: 0,
- index: i,
- })
- }
- log.debug(accounts)
- resolve(accounts)
- })
- .catch(e => {
- reject(e)
- })
- })
- }
-
- async getPrevAccountSet () {
- this.page--
- return await this.getPage()
- }
-
- async getNextAccountSet () {
- this.page++
- return await this.getPage()
- }
-
- getAccounts () {
- return Promise.resolve(this.accounts.slice())
- }
-
- // tx is an instance of the ethereumjs-transaction class.
- async signTransaction (address, tx) {
-
- return new Promise((resolve, reject) => {
-
- log.debug('sign transaction ', address, tx)
-
- TrezorConnect.ethereumSignTx(
- this._getUnlockedAccount(),
- this._normalize(tx.nonce),
- this._normalize(tx.gasPrice),
- this._normalize(tx.gasLimit),
- this._normalize(tx.to),
- this._normalize(tx.value),
- this._normalize(tx.data),
- tx._chainId,
- response => {
- if (response.success) {
-
- tx.v = `0x${response.v.toString(16)}`
- tx.r = `0x${response.r}`
- tx.s = `0x${response.s}`
- log.debug('about to create new tx with data', tx)
-
- const signedTx = new Transaction(tx)
-
- const addressSignedWith = ethUtil.toChecksumAddress(`0x${signedTx.from.toString('hex')}`)
- const correctAddress = ethUtil.toChecksumAddress(address)
- if (addressSignedWith !== correctAddress) {
- log.error('signature doesnt match the right address', addressSignedWith, correctAddress)
- throw new Error('signature doesnt match the right address')
- }
-
- resolve(signedTx)
-
- } else {
- throw new Error(response.error || 'Unknown error')
- }
- },
- TREZOR_MIN_FIRMWARE_VERSION)
- })
- }
-
- async signMessage (withAccount, data) {
- throw new Error('Not supported on this device')
- }
-
- // For personal_sign, we need to prefix the message:
- async signPersonalMessage (withAccount, message) {
-
- TrezorConnect.ethereumSignMessage(this._getUnlockedAccount(), message, response => {
- if (response.success) {
-
- const signature = this._personalToRawSig(response.signature)
- const addressSignedWith = sigUtil.recoverPersonalSignature({data: message, sig: signature})
- const correctAddress = ethUtil.toChecksumAddress(withAccount)
- if (addressSignedWith !== correctAddress) {
- log.error('signature doesnt match the right address', addressSignedWith, correctAddress)
- throw new Error('signature doesnt match the right address')
- }
- return signature
-
- } else {
- throw new Error(response.error || 'Unknown error')
- }
-
- }, TREZOR_MIN_FIRMWARE_VERSION)
- }
-
- async signTypedData (withAccount, typedData) {
- // Waiting on trezor to enable this
- throw new Error('Not supported on this device')
- }
-
- async exportAccount (address) {
- throw new Error('Not supported on this device')
- }
-
- _padLeftEven (hex) {
- return hex.length % 2 !== 0 ? `0${hex}` : hex
- }
-
- _normalize (buf) {
- return this._padLeftEven(ethUtil.bufferToHex(buf).substring(2).toLowerCase())
- }
-
- _addressFromId (pathBase, i) {
- const dkey = this.hdk.derive(`${pathBase}/${i}`)
- const address = ethUtil
- .publicToAddress(dkey.publicKey, true)
- .toString('hex')
- return ethUtil.toChecksumAddress(address)
- }
-
- _getUnlockedAccount () {
- return `${this.hdPath}/${this.unlockedAccount}`
- }
-
- _personalToRawSig (signature) {
- var v = signature['v'] - 27
- v = v.toString(16)
- if (v.length < 2) {
- v = '0' + v
- }
- return '0x' + signature['r'] + signature['s'] + v
- }
-}
-
-TrezorKeyring.type = keyringType
-module.exports = TrezorKeyring
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index daab5baa5..abe7ff8a2 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -48,7 +48,7 @@ const seedPhraseVerifier = require('./lib/seed-phrase-verifier')
const cleanErrorStack = require('./lib/cleanErrorStack')
const DiagnosticsReporter = require('./lib/diagnostics-reporter')
const log = require('loglevel')
-const TrezorKeyring = require('./lib/trezorKeyring')
+const TrezorKeyring = require('eth-trezor-keyring')
module.exports = class MetamaskController extends EventEmitter {
@@ -549,7 +549,8 @@ module.exports = class MetamaskController extends EventEmitter {
throw new Error('MetamaskController - No Trezor Hardware Keyring found')
}
- const accounts = page === -1 ? await keyring.getPrevAccountSet(this.provider) : await keyring.getNextAccountSet(this.provider)
+ const accounts = await keyring.getPage(page)
+
this.accountTracker.syncWithAddresses(accounts.map(a => a.address))
return accounts
diff --git a/package-lock.json b/package-lock.json
index e8df9cc11..0fdbc02d6 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8488,6 +8488,52 @@
}
}
},
+ "eth-trezor-keyring": {
+ "version": "github:brunobar79/eth-trezor-keyring#c138d26c36a01f15be5e12a81e4fcbf56b044fa4",
+ "from": "github:brunobar79/eth-trezor-keyring#c138d26c36a01f15be5e12a81e4fcbf56b044fa4",
+ "requires": {
+ "eth-sig-util": "^1.4.2",
+ "ethereumjs-tx": "^1.3.4",
+ "ethereumjs-util": "^5.1.5",
+ "events": "^2.0.0",
+ "hdkey": "0.8.0"
+ },
+ "dependencies": {
+ "ethereum-common": {
+ "version": "0.0.18",
+ "resolved": "https://registry.npmjs.org/ethereum-common/-/ethereum-common-0.0.18.tgz",
+ "integrity": "sha1-L9w1dvIykDNYl26znaeDIT/5Uj8="
+ },
+ "ethereumjs-tx": {
+ "version": "1.3.4",
+ "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.4.tgz",
+ "integrity": "sha512-kOgUd5jC+0tgV7t52UDECMMz9Uf+Lro+6fSpCvzWemtXfMEcwI3EOxf5mVPMRbTFkMMhuERokNNVF3jItAjidg==",
+ "requires": {
+ "ethereum-common": "^0.0.18",
+ "ethereumjs-util": "^5.0.0"
+ }
+ },
+ "ethereumjs-util": {
+ "version": "5.2.0",
+ "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-5.2.0.tgz",
+ "integrity": "sha512-CJAKdI0wgMbQFLlLRtZKGcy/L6pzVRgelIZqRqNbuVFM3K9VEnyfbcvz0ncWMRNCe4kaHWjwRYQcYMucmwsnWA==",
+ "requires": {
+ "bn.js": "^4.11.0",
+ "create-hash": "^1.1.2",
+ "ethjs-util": "^0.1.3",
+ "keccak": "^1.0.2",
+ "rlp": "^2.0.0",
+ "safe-buffer": "^5.1.1",
+ "secp256k1": "^3.0.1"
+ }
+ },
+ "events": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-2.1.0.tgz",
+ "integrity": "sha512-3Zmiobend8P9DjmKAty0Era4jV8oJ0yGYe2nJJAxgymF9+N8F2m0hhZiMoWtcfepExzNKZumFU3ksdQbInGWCg=="
+ }
+ }
+ },
"eth-tx-summary": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/eth-tx-summary/-/eth-tx-summary-3.2.1.tgz",
diff --git a/package.json b/package.json
index 830382590..fbe79b234 100644
--- a/package.json
+++ b/package.json
@@ -102,6 +102,7 @@
"eth-query": "^2.1.2",
"eth-sig-util": "^1.4.2",
"eth-token-tracker": "^1.1.4",
+ "eth-trezor-keyring": "github:brunobar79/eth-trezor-keyring#c138d26c36a01f15be5e12a81e4fcbf56b044fa4",
"ethereumjs-abi": "^0.6.4",
"ethereumjs-tx": "^1.3.0",
"ethereumjs-util": "github:ethereumjs/ethereumjs-util#ac5d0908536b447083ea422b435da27f26615de9",
@@ -124,7 +125,6 @@
"gulp-eslint": "^4.0.0",
"gulp-sass": "^4.0.0",
"hat": "0.0.3",
- "hdkey": "0.8.0",
"human-standard-token-abi": "^1.0.2",
"idb-global": "^2.1.0",
"identicon.js": "^2.3.1",
diff --git a/ui/app/components/pages/create-account/connect-hardware.js b/ui/app/components/pages/create-account/connect-hardware.js
index 6f1e03550..152a4f275 100644
--- a/ui/app/components/pages/create-account/connect-hardware.js
+++ b/ui/app/components/pages/create-account/connect-hardware.js
@@ -25,10 +25,10 @@ class ConnectHardwareForm extends Component {
return null
}
this.setState({ btnText: 'Connecting...' })
- this.getPage()
+ this.getPage(1)
}
- getPage (page = 1) {
+ getPage (page) {
this.props
.connectHardware('trezor', page)
.then(accounts => {
@@ -133,7 +133,7 @@ class ConnectHardwareForm extends Component {
h(
'button.btn-primary.hw-list-pagination__button',
{
- onClick: () => this.getPage(),
+ onClick: () => this.getPage(1),
},
'Next >'
),