aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbrunobar79 <brunobar79@gmail.com>2018-08-12 13:34:01 +0800
committerbrunobar79 <brunobar79@gmail.com>2018-08-12 13:34:01 +0800
commit0b9b892c6b27c55a016378387cb8d227957f8528 (patch)
tree4a712f3e7536a2b8852863d893887b73a31a9291
parent2355573340d0287582d0cd6a467e13126fbddd7c (diff)
downloadtangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.tar
tangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.tar.gz
tangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.tar.bz2
tangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.tar.lz
tangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.tar.xz
tangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.tar.zst
tangerine-wallet-browser-0b9b892c6b27c55a016378387cb8d227957f8528.zip
this should be ready to go
-rw-r--r--app/scripts/eth-ledger-keyring-listener.js320
-rw-r--r--app/scripts/metamask-controller.js6
-rw-r--r--package-lock.json56
-rw-r--r--package.json1
4 files changed, 60 insertions, 323 deletions
diff --git a/app/scripts/eth-ledger-keyring-listener.js b/app/scripts/eth-ledger-keyring-listener.js
deleted file mode 100644
index 91507455a..000000000
--- a/app/scripts/eth-ledger-keyring-listener.js
+++ /dev/null
@@ -1,320 +0,0 @@
-const {EventEmitter} = require('events')
-const HDKey = require('hdkey')
-const ethUtil = require('ethereumjs-util')
-const sigUtil = require('eth-sig-util')
-const Transaction = require('ethereumjs-tx')
-
-const hdPathString = `44'/60'/0'`
-const type = 'Ledger Hardware'
-const BRIDGE_URL = 'https://localhost:3000'
-const pathBase = 'm'
-const MAX_INDEX = 1000
-
-class LedgerKeyring extends EventEmitter {
- constructor (opts = {}) {
- super()
- this.type = type
- this.page = 0
- this.perPage = 5
- this.unlockedAccount = 0
- this.hdk = new HDKey()
- this.paths = {}
- this.iframe = null
- this.setupIframe()
- this.deserialize(opts)
- }
-
- setupIframe () {
- this.iframe = document.createElement('iframe')
- this.iframe.src = BRIDGE_URL
- document.head.appendChild(this.iframe)
- }
-
- sendMessage (msg, cb) {
- this.iframe.contentWindow.postMessage({...msg, target: 'LEDGER-IFRAME'}, '*')
- window.addEventListener('message', ({ origin, data }) => {
- if (origin !== BRIDGE_URL) return false
- if (data && data.action && data.action === `${msg.action}-reply`) {
- cb(data)
- }
- })
- }
-
- serialize () {
- return Promise.resolve({hdPath: this.hdPath, accounts: this.accounts})
- }
-
- deserialize (opts = {}) {
- this.hdPath = opts.hdPath || hdPathString
- this.unlocked = opts.unlocked || false
- this.accounts = opts.accounts || []
- return Promise.resolve()
- }
-
- isUnlocked () {
- return this.unlocked
- }
-
- setAccountToUnlock (index) {
- this.unlockedAccount = parseInt(index, 10)
- }
-
- unlock () {
-
- if (this.isUnlocked()) return Promise.resolve('already unlocked')
-
- return new Promise((resolve, reject) => {
- this.sendMessage({
- action: 'ledger-unlock',
- params: {
- hdPath: this.hdPath,
- },
- },
- ({success, payload}) => {
- if (success) {
- this.hdk.publicKey = new Buffer(payload.publicKey, 'hex')
- this.hdk.chainCode = new Buffer(payload.chainCode, 'hex')
- resolve('just unlocked')
- } else {
- reject(payload.error || 'Unknown error')
- }
- })
- })
- }
-
- addAccounts (n = 1) {
-
- return new Promise((resolve, reject) => {
- this.unlock()
- .then(_ => {
- const from = this.unlockedAccount
- const to = from + n
- this.accounts = []
-
- for (let i = from; i < to; i++) {
- const address = this._addressFromIndex(pathBase, i)
- this.accounts.push(address)
- this.page = 0
- }
- resolve(this.accounts)
- })
- .catch(e => {
- reject(e)
- })
- })
- }
-
- getFirstPage () {
- this.page = 0
- return this.__getPage(1)
- }
-
- getNextPage () {
- return this.__getPage(1)
- }
-
- getPreviousPage () {
- return this.__getPage(-1)
- }
-
- __getPage (increment) {
-
- this.page += increment
-
- if (this.page <= 0) { this.page = 1 }
-
- return new Promise((resolve, reject) => {
- this.unlock()
- .then(_ => {
-
- const from = (this.page - 1) * this.perPage
- const to = from + this.perPage
-
- const accounts = []
-
- for (let i = from; i < to; i++) {
- const address = this._addressFromIndex(pathBase, i)
- accounts.push({
- address: address,
- balance: null,
- index: i,
- })
- this.paths[ethUtil.toChecksumAddress(address)] = i
-
- }
- resolve(accounts)
- })
- .catch(e => {
- reject(e)
- })
- })
- }
-
- getAccounts () {
- return Promise.resolve(this.accounts.slice())
- }
-
- removeAccount (address) {
- if (!this.accounts.map(a => a.toLowerCase()).includes(address.toLowerCase())) {
- throw new Error(`Address ${address} not found in this keyring`)
- }
- this.accounts = this.accounts.filter(a => a.toLowerCase() !== address.toLowerCase())
- }
-
-
- // tx is an instance of the ethereumjs-transaction class.
- async signTransaction (address, tx) {
- return new Promise((resolve, reject) => {
- this.unlock()
- .then(_ => {
-
- const newTx = new Transaction({
- from: this._normalize(address),
- to: this._normalize(tx.to),
- value: this._normalize(tx.value),
- data: this._normalize(tx.data),
- chainId: tx._chainId,
- nonce: this._normalize(tx.nonce),
- gasLimit: this._normalize(tx.gasLimit),
- gasPrice: this._normalize(tx.gasPrice),
- v: ethUtil.bufferToHex(tx.getChainId()),
- r: '0x00',
- s: '0x00',
- })
-
- this.sendMessage({
- action: 'ledger-sign-transaction',
- params: {
- tx: newTx.serialize().toString('hex'),
- hdPath: this._pathFromAddress(address),
- },
- },
- ({success, payload}) => {
- if (success) {
-
- newTx.v = Buffer.from(payload.v, 'hex')
- newTx.r = Buffer.from(payload.r, 'hex')
- newTx.s = Buffer.from(payload.s, 'hex')
-
- const valid = newTx.verifySignature()
- if (valid) {
- resolve(newTx)
- } else {
- reject('The transaction signature is not valid')
- }
- } else {
- reject(payload)
- }
- })
- })
- })
- }
-
- 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) {
- const humanReadableMsg = this._toAscii(message)
- const bufferMsg = Buffer.from(humanReadableMsg).toString('hex')
- return new Promise((resolve, reject) => {
- this.unlock()
- .then(_ => {
- this.sendMessage({
- action: 'ledger-sign-personal-message',
- params: {
- hdPath: this._pathFromAddress(withAccount),
- message: bufferMsg,
- },
- },
- ({success, payload}) => {
- if (success) {
- let v = payload['v'] - 27
- v = v.toString(16)
- if (v.length < 2) {
- v = `0${v}`
- }
- const signature = `0x${payload['r']}${payload['s']}${v}`
- const addressSignedWith = sigUtil.recoverPersonalSignature({data: message, sig: signature})
- if (ethUtil.toChecksumAddress(addressSignedWith) !== ethUtil.toChecksumAddress(withAccount)) {
- reject('signature doesnt match the right address')
- }
- resolve(signature)
- } else {
- reject(payload)
- }
- })
- })
- })
- }
-
- async signTypedData (withAccount, typedData) {
- throw new Error('Not supported on this device')
- }
-
- async exportAccount (address) {
- throw new Error('Not supported on this device')
- }
-
- forgetDevice () {
- this.accounts = []
- this.unlocked = false
- this.page = 0
- this.unlockedAccount = 0
- this.paths = {}
- }
-
- /* PRIVATE METHODS */
-
- _padLeftEven (hex) {
- return hex.length % 2 !== 0 ? `0${hex}` : hex
- }
-
- _normalize (buf) {
- return this._padLeftEven(ethUtil.bufferToHex(buf).toLowerCase())
- }
-
- _addressFromIndex (pathBase, i) {
- const dkey = this.hdk.derive(`${pathBase}/${i}`)
- const address = ethUtil
- .publicToAddress(dkey.publicKey, true)
- .toString('hex')
- return ethUtil.toChecksumAddress(address)
- }
-
- _pathFromAddress (address) {
- const checksummedAddress = ethUtil.toChecksumAddress(address)
- let index = this.paths[checksummedAddress]
- if (typeof index === 'undefined') {
- for (let i = 0; i < MAX_INDEX; i++) {
- if (checksummedAddress === this._addressFromIndex(pathBase, i)) {
- index = i
- break
- }
- }
- }
-
- if (typeof index === 'undefined') {
- throw new Error('Unknown address')
- }
- return `${this.hdPath}/${index}`
- }
-
- _toAscii (hex) {
- let str = ''
- let i = 0; const l = hex.length
- if (hex.substring(0, 2) === '0x') {
- i = 2
- }
- for (; i < l; i += 2) {
- const code = parseInt(hex.substr(i, 2), 16)
- str += String.fromCharCode(code)
- }
-
- return str
- }
-}
-
-LedgerKeyring.type = type
-module.exports = LedgerKeyring
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index c79e5141e..fed00077e 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -49,7 +49,7 @@ const seedPhraseVerifier = require('./lib/seed-phrase-verifier')
const cleanErrorStack = require('./lib/cleanErrorStack')
const log = require('loglevel')
const TrezorKeyring = require('eth-trezor-keyring')
-const LedgerKeyring = require('./eth-ledger-keyring-listener')
+const LedgerBridgeKeyring = require('eth-ledger-bridge-keyring')
module.exports = class MetamaskController extends EventEmitter {
@@ -128,7 +128,7 @@ module.exports = class MetamaskController extends EventEmitter {
})
// key mgmt
- const additionalKeyrings = [TrezorKeyring, LedgerKeyring]
+ const additionalKeyrings = [TrezorKeyring, LedgerBridgeKeyring]
this.keyringController = new KeyringController({
keyringTypes: additionalKeyrings,
initState: initState.KeyringController,
@@ -546,7 +546,7 @@ module.exports = class MetamaskController extends EventEmitter {
keyringName = TrezorKeyring.type
break
case 'ledger':
- keyringName = LedgerKeyring.type
+ keyringName = LedgerBridgeKeyring.type
break
default:
throw new Error('MetamaskController:connectHardware - Unknown device')
diff --git a/package-lock.json b/package-lock.json
index d48415cbc..249a78d3b 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -8458,6 +8458,62 @@
}
}
},
+ "eth-ledger-bridge-keyring": {
+ "version": "github:brunobar79/eth-ledger-bridge-keyring#f8f05925519a34e2d5ee3083ca95960fa70ddd11",
+ "from": "github:brunobar79/eth-ledger-bridge-keyring",
+ "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.7",
+ "resolved": "https://registry.npmjs.org/ethereumjs-tx/-/ethereumjs-tx-1.3.7.tgz",
+ "integrity": "sha512-wvLMxzt1RPhAQ9Yi3/HKZTn0FZYpnsmQdbKYfUUpi4j1SEIcbkd9tndVjcPrufY3V7j2IebOpC00Zp2P/Ay2kA==",
+ "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=="
+ },
+ "hdkey": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/hdkey/-/hdkey-0.8.0.tgz",
+ "integrity": "sha512-oYsdlK22eobT68N5faWI3776f6tOLyqxLLYwxMx+TP0rkWzuCs0oiOm2VbLWcxdpHFP4LtiRR8udaIX8VkEaZQ==",
+ "requires": {
+ "coinstring": "^2.0.0",
+ "safe-buffer": "^5.1.1",
+ "secp256k1": "^3.0.1"
+ }
+ }
+ }
+ },
"eth-lib": {
"version": "0.1.27",
"resolved": "https://registry.npmjs.org/eth-lib/-/eth-lib-0.1.27.tgz",
diff --git a/package.json b/package.json
index c8a37f564..718e1e60d 100644
--- a/package.json
+++ b/package.json
@@ -111,6 +111,7 @@
"eth-hd-keyring": "^1.2.2",
"eth-json-rpc-filters": "^1.2.6",
"eth-json-rpc-infura": "^3.0.0",
+ "eth-ledger-bridge-keyring": "github:brunobar79/eth-ledger-bridge-keyring",
"eth-method-registry": "^1.0.0",
"eth-phishing-detect": "^1.1.4",
"eth-query": "^2.1.2",