aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/scripts/contentscript.js47
-rw-r--r--app/scripts/inpage.js38
-rw-r--r--app/scripts/metamask-controller.js24
-rw-r--r--app/scripts/platforms/extension.js65
-rw-r--r--ui/app/actions.js21
-rw-r--r--ui/app/components/send/send-content/send-content.component.js2
-rw-r--r--ui/app/components/send/send.component.js12
-rw-r--r--ui/app/components/send/send.container.js2
8 files changed, 116 insertions, 95 deletions
diff --git a/app/scripts/contentscript.js b/app/scripts/contentscript.js
index 7c775fb04..87f7c63ef 100644
--- a/app/scripts/contentscript.js
+++ b/app/scripts/contentscript.js
@@ -6,6 +6,7 @@ const PongStream = require('ping-pong-stream/pong')
const ObjectMultiplex = require('obj-multiplex')
const extension = require('extensionizer')
const PortStream = require('./lib/port-stream.js')
+const Instascan = require('instascan')
const inpageContent = fs.readFileSync(path.join(__dirname, '..', '..', 'dist', 'chrome', 'inpage.js')).toString()
const inpageSuffix = '//# sourceURL=' + extension.extension.getURL('inpage.js') + '\n'
@@ -199,3 +200,49 @@ function redirectToPhishingWarning () {
console.log('MetaMask - redirecting to phishing warning')
window.location.href = 'https://metamask.io/phishing.html'
}
+
+function initQrCodeScanner () {
+ // Append preview div
+ const preview = document.createElement('div')
+ preview.id = 'metamask-preview-wrapper'
+ preview.style = 'position:absolute; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;'
+ const previewVideo = document.createElement('video')
+ previewVideo.id = 'metamask-preview-video'
+ previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;'
+ preview.appendChild(previewVideo)
+ document.body.appendChild(preview)
+ console.log('injected')
+ const scanner = new Instascan.Scanner({
+ video: document.getElementById('metamask-preview-video'),
+ backgroundScan: false,
+ continuous: true,
+ })
+ scanner.addListener('scan', function (content) {
+ console.log('QR-SCANNER: got code (IN-PAGE)', content)
+ scanner.stop().then(_ => {
+ console.log('QR-SCANNER: stopped scanner and sending msg (IN-PAGE)', content)
+ extension.runtime.sendMessage({
+ action: 'qr-code-scanner-data',
+ data: content,
+ })
+ console.log('QR-SCANNER: message sent (IN-PAGE)', content)
+ document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper'))
+ })
+ })
+ Instascan.Camera.getCameras().then(function (cameras) {
+ if (cameras.length > 0) {
+ scanner.start(cameras[0])
+ } else {
+ console.error('No cameras found.')
+ }
+ }).catch(function (e) {
+ console.error(e)
+ })
+}
+
+extension.runtime.onMessage.addListener(({ action }) => {
+ console.log('QR-SCANNER: message received (IN-PAGE)', action)
+ initQrCodeScanner()
+})
+console.log('QR-SCANNER: now listening (IN-PAGE)')
+
diff --git a/app/scripts/inpage.js b/app/scripts/inpage.js
index 1a7bea7c0..20621b73f 100644
--- a/app/scripts/inpage.js
+++ b/app/scripts/inpage.js
@@ -5,7 +5,6 @@ const log = require('loglevel')
const LocalMessageDuplexStream = require('post-message-stream')
const setupDappAutoReload = require('./lib/auto-reload.js')
const MetamaskInpageProvider = require('./lib/inpage-provider.js')
-const Instascan = require('instascan')
restoreContextAfterImports()
log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn')
@@ -98,40 +97,3 @@ function restoreContextAfterImports () {
}
}
-function initCameraScanner () {
- // Append preview div
- const preview = document.createElement('div')
- preview.id = 'metamask-preview-wrapper'
- preview.style = 'position:absolute; top: 20px; left: 20px; width: 300px; height: 300px; overflow: hidden; z-index: 999999999;'
- const previewVideo = document.createElement('video')
- previewVideo.id = 'metamask-preview-video'
- previewVideo.style = 'width: 100%; height: 100%; object-fit: none; margin-left: -10%; margin-top: 10%;'
- preview.appendChild(previewVideo)
- document.body.appendChild(preview)
- console.log('injected')
- const scanner = new Instascan.Scanner({
- video: document.getElementById('metamask-preview-video'),
- backgroundScan: false,
- continuous: true,
- })
- scanner.addListener('scan', function (content) {
- alert(content)
- scanner.stop().then(_ => {
- document.getElementById('metamask-preview-wrapper').parentElement.removeChild(document.getElementById('metamask-preview-wrapper'))
- })
- })
- Instascan.Camera.getCameras().then(function (cameras) {
- if (cameras.length > 0) {
- scanner.start(cameras[0])
- } else {
- console.error('No cameras found.')
- }
- }).catch(function (e) {
- console.error(e)
- })
-}
-
-setTimeout(_ => {
- console.log('injecting...')
- initCameraScanner()
-}, 3000)
diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js
index bcc7075c2..62d707432 100644
--- a/app/scripts/metamask-controller.js
+++ b/app/scripts/metamask-controller.js
@@ -380,6 +380,9 @@ module.exports = class MetamaskController extends EventEmitter {
// TREZOR
unlockTrezorAccount: nodeify(this.unlockTrezorAccount, this),
+ // QR code scanner
+ scanQrCode: nodeify(this.scanQrCode, this),
+
// vault management
submitPassword: nodeify(this.submitPassword, this),
@@ -653,7 +656,26 @@ module.exports = class MetamaskController extends EventEmitter {
const { identities } = this.preferencesController.store.getState()
return { ...keyState, identities }
- }
+ }
+
+ scanQrCode () {
+ return new Promise((resolve, reject) => {
+ console.log('QR-SCANNER: intializing QR code scanner feature (MM controller)')
+ // Tell contentscript to inject the QR reader
+ this.platform.sendMessage('qr-code-scanner-init')
+ console.log('QR-SCANNER: message to initialize has been sent (MM controller)')
+ // Wait for the scanner to send something back
+ this.platform.addMessageListener(({ action, data }) => {
+ console.log('QR-SCANNER: message received (MM controller)', action, data)
+ if (action && action === 'qr-code-scanner-data') {
+ const normalizedAddress = data.replace('ethereum:', '')
+ console.log('QR-SCANNER: resolving promise!', normalizedAddress)
+ return Promise.resolve(normalizedAddress)
+ }
+ })
+ console.log('QR-SCANNER: now listening (MM controller)')
+ })
+ }
//
diff --git a/app/scripts/platforms/extension.js b/app/scripts/platforms/extension.js
index 901c26cab..182df23b1 100644
--- a/app/scripts/platforms/extension.js
+++ b/app/scripts/platforms/extension.js
@@ -1,5 +1,4 @@
const extension = require('extensionizer')
-const explorerLink = require('etherscan-link').createExplorerLink
class ExtensionPlatform {
@@ -18,11 +17,8 @@ class ExtensionPlatform {
return extension.runtime.getManifest().version
}
- openExtensionInBrowser (route = null) {
- let extensionURL = extension.runtime.getURL('home.html')
- if (route) {
- extensionURL += `#${route}`
- }
+ openExtensionInBrowser () {
+ const extensionURL = extension.runtime.getURL('home.html')
this.openWindow({ url: extensionURL })
}
@@ -36,57 +32,16 @@ class ExtensionPlatform {
}
}
- showTransactionNotification (txMeta) {
-
- const status = txMeta.status
- if (status === 'confirmed') {
- this._showConfirmedTransaction(txMeta)
- } else if (status === 'failed') {
- this._showFailedTransaction(txMeta)
- }
- }
-
- _showConfirmedTransaction (txMeta) {
-
- this._subscribeToNotificationClicked()
-
- const url = explorerLink(txMeta.hash, parseInt(txMeta.metamaskNetworkId))
- const nonce = parseInt(txMeta.txParams.nonce, 16)
-
- const title = 'Confirmed transaction'
- const message = `Transaction ${nonce} confirmed! View on EtherScan`
- this._showNotification(title, message, url)
- }
-
- _showFailedTransaction (txMeta) {
-
- const nonce = parseInt(txMeta.txParams.nonce, 16)
- const title = 'Failed transaction'
- const message = `Transaction ${nonce} failed! ${txMeta.err.message}`
- this._showNotification(title, message)
- }
-
- _showNotification (title, message, url) {
- extension.notifications.create(
- url,
- {
- 'type': 'basic',
- 'title': title,
- 'iconUrl': extension.extension.getURL('../../images/icon-64.png'),
- 'message': message,
- })
+ addMessageListener (cb) {
+ extension.runtime.onMessage.addListener(cb)
}
- _subscribeToNotificationClicked () {
- if (!extension.notifications.onClicked.hasListener(this._viewOnEtherScan)) {
- extension.notifications.onClicked.addListener(this._viewOnEtherScan)
- }
- }
-
- _viewOnEtherScan (txId) {
- if (txId.startsWith('http://')) {
- global.metamaskController.platform.openWindow({ url: txId })
- }
+ sendMessage (message, query = {}) {
+ extension.tabs.query(query, tabs => {
+ const activeTab = tabs.filter(tab => tab.active)[0]
+ extension.tabs.sendMessage(activeTab.id, message)
+ console.log('QR-SCANNER: message sent to tab', message, activeTab)
+ })
}
}
diff --git a/ui/app/actions.js b/ui/app/actions.js
index 6c947fc35..9aba6853d 100644
--- a/ui/app/actions.js
+++ b/ui/app/actions.js
@@ -302,6 +302,7 @@ var actions = {
CLEAR_PENDING_TOKENS: 'CLEAR_PENDING_TOKENS',
setPendingTokens,
clearPendingTokens,
+ scanQrCode,
}
module.exports = actions
@@ -2194,3 +2195,23 @@ function clearPendingTokens () {
type: actions.CLEAR_PENDING_TOKENS,
}
}
+
+function scanQrCode () {
+ log.debug(`background.scanQrCode`)
+ return (dispatch, getState) => {
+ dispatch(actions.showLoadingIndication())
+ return new Promise((resolve, reject) => {
+ background.scanQrCode((err, data) => {
+ log.debug(`background.scanQrCode resolved!`, err, data)
+ if (err) {
+ log.error(err)
+ dispatch(actions.displayWarning(err.message))
+ return reject(err)
+ }
+
+ dispatch(actions.hideLoadingIndication())
+ return resolve(data)
+ })
+ })
+ }
+}
diff --git a/ui/app/components/send/send-content/send-content.component.js b/ui/app/components/send/send-content/send-content.component.js
index 7a0b1a18e..566ee1c7f 100644
--- a/ui/app/components/send/send-content/send-content.component.js
+++ b/ui/app/components/send/send-content/send-content.component.js
@@ -11,6 +11,7 @@ export default class SendContent extends Component {
static propTypes = {
updateGas: PropTypes.func,
+ scanQrCode: PropTypes.func,
};
render () {
@@ -19,6 +20,7 @@ export default class SendContent extends Component {
<div className="send-v2__form">
<SendFromRow />
<SendToRow updateGas={(updateData) => this.props.updateGas(updateData)} />
+ <button onClick={_ => this.props.scanQrCode() }>or scan a QR code</button>
<SendAmountRow updateGas={(updateData) => this.props.updateGas(updateData)} />
<SendGasRow />
<SendHexDataRow />
diff --git a/ui/app/components/send/send.component.js b/ui/app/components/send/send.component.js
index 6f1b20c55..5e967251d 100644
--- a/ui/app/components/send/send.component.js
+++ b/ui/app/components/send/send.component.js
@@ -38,12 +38,19 @@ export default class SendTransactionScreen extends PersistentForm {
updateAndSetGasTotal: PropTypes.func,
updateSendErrors: PropTypes.func,
updateSendTokenBalance: PropTypes.func,
+ scanQrCode: PropTypes.func,
};
static contextTypes = {
t: PropTypes.func,
};
+ scanQrCode = async () => {
+ const scannedAddress = await this.props.scanQrCode()
+ console.log('QR-SCANNER: Got address (UI)', scannedAddress)
+ this.updateGas({ to: scannedAddress })
+ }
+
updateGas ({ to: updatedToAddress, amount: value } = {}) {
const {
amount,
@@ -170,7 +177,10 @@ export default class SendTransactionScreen extends PersistentForm {
return (
<div className="page-container">
<SendHeader history={history}/>
- <SendContent updateGas={(updateData) => this.updateGas(updateData)}/>
+ <SendContent
+ updateGas={(updateData) => this.updateGas(updateData)}
+ scanQrCode={_ => this.scanQrCode()}
+ />
<SendFooter history={history}/>
</div>
)
diff --git a/ui/app/components/send/send.container.js b/ui/app/components/send/send.container.js
index 44ebd2792..c3240be67 100644
--- a/ui/app/components/send/send.container.js
+++ b/ui/app/components/send/send.container.js
@@ -26,6 +26,7 @@ import {
updateSendTokenBalance,
updateGasData,
setGasTotal,
+ scanQrCode,
} from '../../actions'
import {
resetSendState,
@@ -89,5 +90,6 @@ function mapDispatchToProps (dispatch) {
},
updateSendErrors: newError => dispatch(updateSendErrors(newError)),
resetSendState: () => dispatch(resetSendState()),
+ scanQrCode: () => dispatch(scanQrCode()),
}
}