aboutsummaryrefslogtreecommitdiffstats
path: root/app
diff options
context:
space:
mode:
authorbrunobar79 <brunobar79@gmail.com>2018-08-11 14:35:20 +0800
committerbrunobar79 <brunobar79@gmail.com>2018-08-11 14:35:20 +0800
commit78a1cd3314455d6e4e08839a3eea3ec2868f4f59 (patch)
tree49c31a6b0d41de1d09120d683689b9445a5bceb6 /app
parent5ef80495cfd47a8f5e4caf4b16842155420de62e (diff)
downloadtangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.tar
tangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.tar.gz
tangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.tar.bz2
tangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.tar.lz
tangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.tar.xz
tangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.tar.zst
tangerine-wallet-browser-78a1cd3314455d6e4e08839a3eea3ec2868f4f59.zip
iframe communication working
Diffstat (limited to 'app')
-rw-r--r--app/manifest.json3
-rw-r--r--app/scripts/background.js3
-rw-r--r--app/scripts/contentscript.js2
-rw-r--r--app/scripts/eth-ledger-keyring-listener.js203
-rw-r--r--app/scripts/lib/setupLedgerIframe.js40
-rw-r--r--app/scripts/metamask-controller.js6
-rw-r--r--app/vendor/ledger/content-script.js18
7 files changed, 209 insertions, 66 deletions
diff --git a/app/manifest.json b/app/manifest.json
index 0bdf84ef1..84cedd687 100644
--- a/app/manifest.json
+++ b/app/manifest.json
@@ -48,8 +48,7 @@
"https://*/*"
],
"js": [
- "contentscript.js",
- "vendor/ledger/content-script.js"
+ "contentscript.js"
],
"run_at": "document_start",
"all_frames": true
diff --git a/app/scripts/background.js b/app/scripts/background.js
index 3d3afdd4e..bff559469 100644
--- a/app/scripts/background.js
+++ b/app/scripts/background.js
@@ -68,8 +68,6 @@ initialize().catch(log.error)
// setup metamask mesh testing container
setupMetamaskMeshMetrics()
-
-
/**
* An object representing a transaction, in whatever state it is in.
* @typedef TransactionMeta
@@ -446,3 +444,4 @@ extension.runtime.onInstalled.addListener(function (details) {
extension.tabs.create({url: 'https://metamask.io/#how-it-works'})
}
})
+
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index e0a2b0061..01df9e327 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -200,4 +200,4 @@ function redirectToPhishingWarning () {
console.log('MetaMask - routing to Phishing Warning component')
const extensionURL = extension.runtime.getURL('phishing.html')
window.location.href = extensionURL
-}
+} \ No newline at end of file
diff --git a/app/scripts/eth-ledger-keyring-listener.js b/app/scripts/eth-ledger-keyring-listener.js
index a6db49772..1c02f0610 100644
--- a/app/scripts/eth-ledger-keyring-listener.js
+++ b/app/scripts/eth-ledger-keyring-listener.js
@@ -1,68 +1,182 @@
- const extension = require('extensionizer')
+const extension = require('extensionizer')
const {EventEmitter} = require('events')
// HD path differs from eth-hd-keyring - MEW, Parity, Geth and Official Ledger clients use same unusual derivation for Ledger
const hdPathString = `m/44'/60'/0'`
const type = 'Ledger Hardware Keyring'
+const ORIGIN = 'http://localhost:9000'
class LedgerKeyring extends EventEmitter {
constructor (opts = {}) {
super()
this.type = type
+ this.page = 0
+ this.perPage = 5
+ this.unlockedAccount = 0
+ this.paths = {}
+ this.iframe = null
+ this.setupIframe()
this.deserialize(opts)
}
+ setupIframe(){
+ this.iframe = document.createElement('iframe')
+ this.iframe.src = ORIGIN
+ console.log('Injecting ledger iframe')
+ document.head.appendChild(this.iframe)
+
+
+ /*
+ Passing messages from iframe to background script
+ */
+ console.log('[LEDGER]: LEDGER FROM-IFRAME LISTENER READY')
+
+ }
+
+ sendMessage(msg, cb) {
+ console.log('[LEDGER]: SENDING MESSAGE TO IFRAME', msg)
+ this.iframe.contentWindow.postMessage({...msg, target: 'LEDGER-IFRAME'}, '*')
+ window.addEventListener('message', event => {
+ if(event.origin !== ORIGIN) return false
+ if (event.data && event.data.action && event.data.action.search(name) !== -1) {
+ console.log('[LEDGER]: GOT MESAGE FROM IFRAME', event.data)
+ cb(event.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()
}
- async addAccounts (n = 1) {
+ 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) => {
- extension.runtime.sendMessage({
- action: 'ledger-add-account',
- n,
+ this.sendMessage({
+ action: 'ledger-unlock',
+ params: {
+ hdPath: this.hdPath,
+ },
+ },
+ ({action, success, payload}) => {
+ if (success) {
+ resolve(payload)
+ } else {
+ reject(payload)
+ }
})
+ })
+ }
- extension.runtime.onMessage.addListener(({action, success, payload}) => {
- if (action === 'ledger-sign-transaction') {
+ async addAccounts (n = 1) {
+ return new Promise((resolve, reject) => {
+ this.unlock()
+ .then(_ => {
+ this.sendMessage({
+ action: 'ledger-add-account',
+ params: {
+ n,
+ },
+ },
+ ({action, success, payload}) => {
if (success) {
resolve(payload)
} else {
reject(payload)
- }
- }
+ }
+ })
})
})
}
- async getAccounts () {
- return this.accounts.slice()
+ getFirstPage () {
+ this.page = 0
+ return this.__getPage(1)
}
- // tx is an instance of the ethereumjs-transaction class.
- async signTransaction (address, tx) {
+ 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) => {
- extension.runtime.sendMessage({
- action: 'ledger-sign-transaction',
- address,
- tx,
+ this.unlock()
+ .then(_ => {
+ this.sendMessage({
+ action: 'ledger-get-page',
+ params: {
+ page: this.page,
+ },
+ },
+ ({action, success, payload}) => {
+ if (success) {
+ resolve(payload)
+ } else {
+ reject(payload)
+ }
+ })
})
+ })
+ }
- extension.runtime.onMessage.addListener(({action, success, payload}) => {
- if (action === 'ledger-sign-transaction') {
- if (success) {
- resolve(payload)
- } else {
- reject(payload)
- }
- }
+ 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(_ => {
+ console.log('[LEDGER]: sending message ', 'ledger-sign-transaction')
+ this.sendMessage({
+ action: 'ledger-sign-transaction',
+ params: {
+ address,
+ tx,
+ },
+ },
+ ({action, success, payload}) => {
+ if (success) {
+ resolve(payload)
+ } else {
+ reject(payload)
+ }
+ })
})
})
}
@@ -74,20 +188,23 @@ class LedgerKeyring extends EventEmitter {
// For personal_sign, we need to prefix the message:
async signPersonalMessage (withAccount, message) {
return new Promise((resolve, reject) => {
- extension.runtime.sendMessage({
- action: 'ledger-sign-personal-message',
- withAccount,
- message,
- })
-
- extension.runtime.onMessage.addListener(({action, success, payload}) => {
- if (action === 'ledger-sign-personal-message') {
- if (success) {
- resolve(payload)
- } else {
- reject(payload)
- }
- }
+ this.unlock()
+ .then(_ => {
+ console.log('[LEDGER]: sending message ', 'ledger-sign-personal-message')
+ this.sendMessage({
+ action: 'ledger-sign-personal-message',
+ params: {
+ withAccount,
+ message,
+ },
+ },
+ ({action, success, payload}) => {
+ if (success) {
+ resolve(payload)
+ } else {
+ reject(payload)
+ }
+ })
})
})
}
@@ -99,6 +216,14 @@ class LedgerKeyring extends EventEmitter {
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 = {}
+ }
}
LedgerKeyring.type = type
diff --git a/app/scripts/lib/setupLedgerIframe.js b/app/scripts/lib/setupLedgerIframe.js
new file mode 100644
index 000000000..2831d072e
--- /dev/null
+++ b/app/scripts/lib/setupLedgerIframe.js
@@ -0,0 +1,40 @@
+const extension = require('extensionizer')
+module.exports = setupLedgerIframe
+/**
+ * Injects an iframe into the current document to
+ * enable the interaction with ledger devices
+ */
+function setupLedgerIframe () {
+ const ORIGIN = 'http://localhost:9000'
+ const ledgerIframe = document.createElement('iframe')
+ ledgerIframe.src = ORIGIN
+ console.log('Injecting ledger iframe')
+ document.head.appendChild(ledgerIframe)
+
+ console.log('[LEDGER]: LEDGER BG LISTENER READY')
+ extension.runtime.onMessage.addListener(({action, params}) => {
+ console.log('[LEDGER]: GOT MSG FROM THE KEYRING', action, params)
+ if (action.search('ledger-') !== -1) {
+ //Forward messages from the keyring to the iframe
+ sendMessage({action, params})
+ }
+ })
+
+ function sendMessage(msg) {
+ ledgerIframe.contentWindow.postMessage({...msg, target: 'LEDGER-IFRAME'}, '*')
+ }
+
+ /*
+ Passing messages from iframe to background script
+ */
+ console.log('[LEDGER]: LEDGER FROM-IFRAME LISTENER READY')
+ window.addEventListener('message', event => {
+ if(event.origin !== ORIGIN) return false
+ if (event.data && event.data.action && event.data.action.search('ledger-') !== -1) {
+ // Forward messages from the iframe to the keyring
+ console.log('[LEDGER] : forwarding msg', event.data)
+ extension.runtime.sendMessage(event.data)
+ }
+ })
+
+ } \ No newline at end of file
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index 593b722ff..58bab9789 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -546,12 +546,11 @@ module.exports = class MetamaskController extends EventEmitter {
keyringName = TrezorKeyring.type
break
case 'ledger':
- keyringName = TrezorKeyring.type
+ keyringName = LedgerKeyring.type
break
default:
throw new Error('MetamaskController:connectHardware - Unknown device')
}
-
let keyring = await this.keyringController.getKeyringsByType(keyringName)[0]
if (!keyring) {
keyring = await this.keyringController.addNewKeyring(keyringName)
@@ -568,10 +567,8 @@ module.exports = class MetamaskController extends EventEmitter {
*/
async connectHardware (deviceName, page) {
- const oldAccounts = await this.keyringController.getAccounts()
const keyring = await this.getKeyringForDevice(deviceName)
let accounts = []
-
switch (page) {
case -1:
accounts = await keyring.getPreviousPage()
@@ -585,6 +582,7 @@ module.exports = class MetamaskController extends EventEmitter {
// Merge with existing accounts
// and make sure addresses are not repeated
+ const oldAccounts = await this.keyringController.getAccounts()
const accountsToTrack = [...new Set(oldAccounts.concat(accounts.map(a => a.address.toLowerCase())))]
this.accountTracker.syncWithAddresses(accountsToTrack)
return accounts
diff --git a/app/vendor/ledger/content-script.js b/app/vendor/ledger/content-script.js
deleted file mode 100644
index 425ff07a3..000000000
--- a/app/vendor/ledger/content-script.js
+++ /dev/null
@@ -1,18 +0,0 @@
-/*
-Passing messages from background script to popup
-*/
-let port = chrome.runtime.connect({ name: 'ledger' });
-port.onMessage.addListener(message => {
- window.postMessage(message, window.location.origin);
-});
-port.onDisconnect.addListener(d => {
- port = null;
-});
- /*
-Passing messages from popup to background script
-*/
- window.addEventListener('message', event => {
- if (port && event.source === window && event.data) {
- port.postMessage(event.data);
- }
-}); \ No newline at end of file