1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-12-23 09:52:26 +01:00

working without injection

This commit is contained in:
brunobar79 2018-07-24 20:32:20 -04:00
parent d5929e5c42
commit 74fd6d1d12
13 changed files with 231 additions and 87 deletions

View File

@ -76,5 +76,6 @@
"ids": [
"*"
]
}
},
"content_security_policy": "script-src 'self' 'unsafe-eval'; object-src 'self'"
}

View File

@ -6,7 +6,6 @@ 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'
@ -201,43 +200,3 @@ function redirectToPhishingWarning () {
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:fixed; 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) {
scanner.stop().then(_ => {
extension.runtime.sendMessage({
action: 'qr-code-scanner-data',
data: 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 }) => {
initQrCodeScanner()
})

View File

@ -380,9 +380,6 @@ 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),
@ -658,21 +655,6 @@ module.exports = class MetamaskController extends EventEmitter {
return { ...keyState, identities }
}
scanQrCode () {
return new Promise((resolve, reject) => {
// Tell contentscript to inject the QR reader
this.platform.sendMessageToActiveTab('qr-code-scanner-init')
// Wait for the scanner to send something back
this.platform.addMessageListener(({ action, data }) => {
if (action && action === 'qr-code-scanner-data') {
const normalizedAddress = data.replace('ethereum:', '')
resolve(normalizedAddress)
}
})
})
}
//
// Account Management
//

View File

@ -36,12 +36,6 @@ class ExtensionPlatform {
extension.runtime.onMessage.addListener(cb)
}
sendMessageToActiveTab (message, query = {}) {
extension.tabs.query(query, tabs => {
const activeTab = tabs.filter(tab => tab.active)[0]
extension.tabs.sendMessage(activeTab.id, message)
})
}
}
module.exports = ExtensionPlatform

View File

@ -31,6 +31,12 @@ var actions = {
ALERT_CLOSE: 'UI_ALERT_CLOSE',
showAlert: showAlert,
hideAlert: hideAlert,
QR_SCANNER_OPEN: 'UI_QR_SCANNER_OPEN',
QR_SCANNER_CLOSE: 'UI_QR_SCANNER_CLOSE',
QR_CODE_DETECTED: 'UI_QR_CODE_DETECTED',
showQrScanner,
hideQrScanner,
qrCodeDetected,
// network dropdown open
NETWORK_DROPDOWN_OPEN: 'UI_NETWORK_DROPDOWN_OPEN',
NETWORK_DROPDOWN_CLOSE: 'UI_NETWORK_DROPDOWN_CLOSE',
@ -1752,6 +1758,25 @@ function hideAlert () {
}
}
function showQrScanner () {
return {
type: actions.QR_SCANNER_OPEN,
}
}
function qrCodeDetected (qrCodeData) {
return {
type: actions.QR_CODE_DETECTED,
value: qrCodeData,
}
}
function hideQrScanner () {
return {
type: actions.QR_SCANNER_CLOSE,
}
}
function showLoadingIndication (message) {
return {
@ -2197,21 +2222,7 @@ function clearPendingTokens () {
}
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)
})
})
dispatch(actions.showQrScanner())
}
}

View File

@ -39,6 +39,8 @@ const Modal = require('./components/modals/index').Modal
// Global Alert
const Alert = require('./components/alert')
const QrScanner = require('./components/qr-scanner')
const AppHeader = require('./components/app-header')
import UnlockPage from './components/pages/unlock-page'
@ -132,6 +134,8 @@ class App extends Component {
// global alert
h(Alert, {visible: this.props.alertOpen, msg: alertMessage}),
h(QrScanner, {visible: this.props.qrScannerOpen}),
h(AppHeader),
// sidebar
@ -270,6 +274,7 @@ App.propTypes = {
currentView: PropTypes.object,
sidebarOpen: PropTypes.bool,
alertOpen: PropTypes.bool,
qrScannerOpen: PropTypes.bool,
hideSidebar: PropTypes.func,
isMascara: PropTypes.bool,
isOnboarding: PropTypes.bool,
@ -306,6 +311,7 @@ function mapStateToProps (state) {
networkDropdownOpen,
sidebarOpen,
alertOpen,
qrScannerOpen,
alertMessage,
isLoading,
loadingMessage,
@ -333,6 +339,7 @@ function mapStateToProps (state) {
networkDropdownOpen,
sidebarOpen,
alertOpen,
qrScannerOpen,
alertMessage,
isLoading,
loadingMessage,

View File

@ -0,0 +1,2 @@
import QrScanner from './qr-scanner.component'
module.exports = QrScanner

View File

@ -0,0 +1,152 @@
import React, { Component } from 'react'
import PropTypes from 'prop-types'
import {connect} from 'react-redux'
import { hideQrScanner, qrCodeDetected} from '../../actions'
import Instascan from 'instascan'
class QrScanner extends Component {
static propTypes = {
visible: PropTypes.bool,
hideQrScanner: PropTypes.func,
qrCodeDetected: PropTypes.func,
}
constructor (props) {
super(props)
this.state = {
msg: 'Place the QR code in front of your camera so we can read it...',
}
this.scanning = false
}
parseContent (content) {
let type = 'unknown'
let values = {}
// Here we could add more cases
// To parse other codes (transactions for ex.)
if (content.split('ethereum:').length > 1) {
type = 'address'
values = {'address': content.split('ethereum:')[1] }
}
return {type, values}
}
componentDidUpdate () {
if (this.props.visible && this.camera && !this.scanning) {
const scanner = new Instascan.Scanner({
video: this.camera,
backgroundScan: false,
continuous: true,
})
scanner.addListener('scan', (content) => {
scanner.stop().then(_ => {
const result = this.parseContent(content)
if (result.type !== 'unknown') {
console.log('QR-SCANNER: CODE DETECTED', result)
this.props.qrCodeDetected(result)
this.props.hideQrScanner()
} else {
this.setState({msg: 'Error: We couldn\'t identify that QR code'})
}
})
})
Instascan.Camera.getCameras().then((cameras) => {
if (cameras.length > 0) {
scanner.start(cameras[0])
console.log('QR-SCANNER: started scanning with camera', cameras[0])
} else {
console.log('QR-SCANNER: no cameras found')
}
}).catch(function (e) {
console.error(e)
})
this.scanning = true
}
}
render () {
const { visible } = this.props
if (!visible) {
return null
}
return (
<div className={'qr-code-modal-wrapper'}>
<div className={'qr-scanner'}
style={{
position: 'fixed',
top: '50%',
left: '50%',
zIndex: 1050,
minWidth: '320px',
minHeight: '400px',
maxWidth: '300px',
maxHeight: '300px',
transform: 'translate(-50%, -50%)',
backgroundColor: '#ffffff',
padding: '15px',
}}
>
<h3 style={{
textAlign: 'center',
marginBottom: '20px',
}}>
Scan QR code
</h3>
<div
className={'qr-code-video-wrapper'}
style={{
overflow: 'hidden',
width: '100%',
height: '275px',
}}>
<video
style={{
width: 'auto',
height: '275px',
marginLeft: '-15%',
}}
ref={(cam) => {
this.camera = cam
}}
/>
</div>
<div className={'qr-code-help'} style={{textAlign: 'center', fontSize: '12px', padding: '15px'}}>
{this.state.msg}
</div>
</div>
<div
className={'qr-code-modal-overlay'}
style={{
position: 'fixed',
top: '0',
right: '0',
bottom: '0',
left: '0',
zIndex: '1040',
backgroundColor: 'rgba(0, 0, 0, 0.5)',
animationFillMode: 'forwards',
animationDuration: '0.3s',
animationName: 'anim_171532470906313',
animationTimingFunction: 'ease-out',
}}
onClick={_ => this.props.hideQrScanner() }
/>
</div>
)
}
}
function mapDispatchToProps (dispatch) {
return {
hideQrScanner: () => dispatch(hideQrScanner()),
qrCodeDetected: (data) => dispatch(qrCodeDetected(data)),
}
}
function mapStateToProps (state) {
return {}
}
export default connect(mapStateToProps, mapDispatchToProps)(QrScanner)

View File

@ -39,16 +39,26 @@ export default class SendTransactionScreen extends PersistentForm {
updateSendErrors: PropTypes.func,
updateSendTokenBalance: PropTypes.func,
scanQrCode: PropTypes.func,
qrCodeData: PropTypes.object,
};
static contextTypes = {
t: PropTypes.func,
};
scanQrCode = async () => {
const scannedAddress = await this.props.scanQrCode()
this.props.updateSendTo(scannedAddress)
this.updateGas({ to: scannedAddress })
componentWillReceiveProps (nextProps) {
if (nextProps.qrCodeData) {
if (nextProps.qrCodeData.type === 'address') {
const scannedAddress = nextProps.qrCodeData.values.address.toLowerCase()
const currentAddress = this.props.to && this.props.to.toLowerCase()
if (currentAddress !== scannedAddress) {
this.props.updateSendTo(scannedAddress)
this.updateGas({ to: scannedAddress })
// Here we should clear props.qrCodeData
}
}
}
}
updateGas ({ to: updatedToAddress, amount: value } = {}) {
@ -179,7 +189,7 @@ export default class SendTransactionScreen extends PersistentForm {
<SendHeader history={history}/>
<SendContent
updateGas={(updateData) => this.updateGas(updateData)}
scanQrCode={_ => this.scanQrCode()}
scanQrCode={_ => this.props.scanQrCode()}
/>
<SendFooter history={history}/>
</div>

View File

@ -21,6 +21,7 @@ import {
getSendFromObject,
getSendTo,
getTokenBalance,
getQrCodeData,
} from './send.selectors'
import {
updateSendTo,
@ -62,6 +63,7 @@ function mapStateToProps (state) {
tokenBalance: getTokenBalance(state),
tokenContract: getSelectedTokenContract(state),
tokenToFiatRate: getSelectedTokenToFiatRate(state),
qrCodeData: getQrCodeData(state),
}
}

View File

@ -46,6 +46,7 @@ const selectors = {
getTokenExchangeRate,
getUnapprovedTxs,
transactionsSelector,
getQrCodeData,
}
module.exports = selectors
@ -282,3 +283,7 @@ function transactionsSelector (state) {
: txsToRender
.sort((a, b) => b.time - a.time)
}
function getQrCodeData (state) {
return state.appState.qrCodeData
}

View File

@ -50,7 +50,9 @@ function reduceApp (state, action) {
},
sidebarOpen: false,
alertOpen: false,
qrScannerOpen: false,
alertMessage: null,
qrCodeData: null,
networkDropdownOpen: false,
currentView: seedWords ? seedConfView : defaultView,
accountDetail: {
@ -90,7 +92,7 @@ function reduceApp (state, action) {
sidebarOpen: false,
})
// sidebar methods
// alert methods
case actions.ALERT_OPEN:
return extend(appState, {
alertOpen: true,
@ -102,6 +104,22 @@ function reduceApp (state, action) {
alertOpen: false,
alertMessage: null,
})
// qr scanner methods
case actions.QR_SCANNER_OPEN:
return extend(appState, {
qrScannerOpen: true,
})
case actions.QR_SCANNER_CLOSE:
return extend(appState, {
qrScannerOpen: false,
})
case actions.QR_CODE_DETECTED:
return extend(appState, {
qrCodeData: action.value,
})
// modal methods:
case actions.MODAL_OPEN:

View File

@ -194,3 +194,4 @@ function getTotalUnapprovedCount ({ metamask }) {
return Object.keys(unapprovedTxs).length + unapprovedMsgCount + unapprovedPersonalMsgCount +
unapprovedTypedMessagesCount
}