From 5a91adf7d802097805938e3d54fe7256b19724d1 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 4 Apr 2017 18:23:46 -0700 Subject: [PATCH 1/5] add platforms to mascara + move buyEther window open to ui --- app/scripts/lib/auto-faucet.js | 8 +++++--- app/scripts/lib/buy-eth-url.js | 19 +++++++++++++++++++ app/scripts/metamask-controller.js | 19 ++----------------- app/scripts/platforms/sw.js | 24 ++++++++++++++++++++++++ app/scripts/platforms/window.js | 22 ++++++++++++++++++++++ mascara/src/background.js | 8 +++++++- mascara/src/popup.js | 5 +++++ ui/app/actions.js | 8 +++++--- ui/app/components/buy-button-subview.js | 13 +++++++------ ui/app/components/coinbase-form.js | 2 +- 10 files changed, 97 insertions(+), 31 deletions(-) create mode 100644 app/scripts/lib/buy-eth-url.js create mode 100644 app/scripts/platforms/sw.js create mode 100644 app/scripts/platforms/window.js diff --git a/app/scripts/lib/auto-faucet.js b/app/scripts/lib/auto-faucet.js index 73b73dfe6..1e059cf73 100644 --- a/app/scripts/lib/auto-faucet.js +++ b/app/scripts/lib/auto-faucet.js @@ -3,9 +3,11 @@ const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' const env = process.env.METAMASK_ENV module.exports = function (address) { - if (METAMASK_DEBUG || env === 'test') return // Don't faucet in development or test - let data = address - let headers = new Headers() + // Don't faucet in development or test + if (METAMASK_DEBUG || env === 'test') return + global.log.info('auto-fauceting:', address) + const data = address + const headers = new Headers() headers.append('Content-type', 'application/rawdata') fetch(uri, { method: 'POST', diff --git a/app/scripts/lib/buy-eth-url.js b/app/scripts/lib/buy-eth-url.js new file mode 100644 index 000000000..91a1ec322 --- /dev/null +++ b/app/scripts/lib/buy-eth-url.js @@ -0,0 +1,19 @@ +module.exports = getBuyEthUrl + +function getBuyEthUrl({ network, amount, address }){ + let url + switch (network) { + case '1': + url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH` + break + + case '3': + url = 'https://faucet.metamask.io/' + break + + case '42': + url = 'https://github.com/kovan-testnet/faucet' + break + } + return url +} \ No newline at end of file diff --git a/app/scripts/metamask-controller.js b/app/scripts/metamask-controller.js index edb9bbbd9..2b8fc9cb8 100644 --- a/app/scripts/metamask-controller.js +++ b/app/scripts/metamask-controller.js @@ -23,6 +23,7 @@ const ConfigManager = require('./lib/config-manager') const autoFaucet = require('./lib/auto-faucet') const nodeify = require('./lib/nodeify') const accountImporter = require('./account-import-strategies') +const getBuyEthUrl = require('./lib/buy-eth-url') const version = require('../manifest.json').version @@ -614,24 +615,8 @@ module.exports = class MetamaskController extends EventEmitter { buyEth (address, amount) { if (!amount) amount = '5' - const network = this.getNetworkState() - let url - - switch (network) { - case '1': - url = `https://buy.coinbase.com/?code=9ec56d01-7e81-5017-930c-513daa27bb6a&amount=${amount}&address=${address}&crypto_currency=ETH` - break - - case '3': - url = 'https://faucet.metamask.io/' - break - - case '42': - url = 'https://github.com/kovan-testnet/faucet' - break - } - + const url = getBuyEthUrl({ network, address, amount }) if (url) this.platform.openWindow({ url }) } diff --git a/app/scripts/platforms/sw.js b/app/scripts/platforms/sw.js new file mode 100644 index 000000000..007d8dc5b --- /dev/null +++ b/app/scripts/platforms/sw.js @@ -0,0 +1,24 @@ + +class SwPlatform { + + // + // Public + // + + reload () { + // you cant actually do this + global.location.reload() + } + + openWindow ({ url }) { + // this doesnt actually work + global.open(url, '_blank') + } + + getVersion () { + return '' + } + +} + +module.exports = SwPlatform diff --git a/app/scripts/platforms/window.js b/app/scripts/platforms/window.js new file mode 100644 index 000000000..1527c008b --- /dev/null +++ b/app/scripts/platforms/window.js @@ -0,0 +1,22 @@ + +class WindowPlatform { + + // + // Public + // + + reload () { + global.location.reload() + } + + openWindow ({ url }) { + global.open(url, '_blank') + } + + getVersion () { + return '' + } + +} + +module.exports = WindowPlatform diff --git a/mascara/src/background.js b/mascara/src/background.js index 6f9fb3d13..957570050 100644 --- a/mascara/src/background.js +++ b/mascara/src/background.js @@ -8,6 +8,7 @@ const PortStream = require('../../app/scripts/lib/port-stream.js') const DbController = require('./lib/index-db-controller') +const SwPlatform = require('../../app/scripts/platforms/sw') const MetamaskController = require('../../app/scripts/metamask-controller') const extension = {} //require('../../app/scripts/lib/extension') @@ -17,7 +18,8 @@ const migrations = require('../../app/scripts/migrations/') const firstTimeState = require('../../app/scripts/first-time-state') const STORAGE_KEY = 'metamask-config' -const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +// const METAMASK_DEBUG = 'GULP_METAMASK_DEBUG' +const METAMASK_DEBUG = true let popupIsOpen = false const log = require('loglevel') @@ -70,7 +72,11 @@ function setupController (initState, client) { // MetaMask Controller // + const platform = new SwPlatform() + const controller = new MetamaskController({ + // platform specific implementation + platform, // User confirmation callbacks: showUnconfirmedMessage: noop, unlockAccountMessage: noop, diff --git a/mascara/src/popup.js b/mascara/src/popup.js index ef7759a81..b740e81a5 100644 --- a/mascara/src/popup.js +++ b/mascara/src/popup.js @@ -4,8 +4,13 @@ const SwStream = require('sw-stream/lib/sw-stream.js') const MetaMaskUiCss = require('../../ui/css') const setupIframe = require('./lib/setup-iframe.js') const MetamaskInpageProvider = require('../../app/scripts/lib/inpage-provider.js') +const MetamascaraPlatform = require('../../app/scripts/platforms/window') const startPopup = require('../../app/scripts/popup-core') +// create platform global +global.platform = new MetamascaraPlatform() + + var css = MetaMaskUiCss() injectCss(css) const container = document.getElementById('app-content') diff --git a/ui/app/actions.js b/ui/app/actions.js index 60b4c6f03..8934299e7 100644 --- a/ui/app/actions.js +++ b/ui/app/actions.js @@ -1,3 +1,5 @@ +const getBuyEthUrl = require('../../app/scripts/lib/buy-eth-url') + var actions = { _setBackgroundConnection: _setBackgroundConnection, @@ -833,10 +835,10 @@ function showSendPage () { } } -function buyEth (address, amount) { +function buyEth (opts) { return (dispatch) => { - log.debug(`background.buyEth`) - background.buyEth(address, amount) + const url = getBuyEthUrl(opts) + global.platform.openWindow({ url }) dispatch({ type: actions.BUY_ETH, }) diff --git a/ui/app/components/buy-button-subview.js b/ui/app/components/buy-button-subview.js index 2b1675b6d..6810303e1 100644 --- a/ui/app/components/buy-button-subview.js +++ b/ui/app/components/buy-button-subview.js @@ -104,7 +104,8 @@ BuyButtonSubview.prototype.render = function () { } BuyButtonSubview.prototype.formVersionSubview = function () { - if (this.props.network === '1') { + const network = this.props.network + if (network === '1') { if (this.props.buyView.formView.coinbase) { return h(CoinbaseForm, this.props) } else if (this.props.buyView.formView.shapeshift) { @@ -123,15 +124,15 @@ BuyButtonSubview.prototype.formVersionSubview = function () { marginBottom: '15px', }, }, 'In order to access this feature, please switch to the Main Network'), - ((this.props.network === '3') || (this.props.network === '42')) ? h('h3.text-transform-uppercase', 'or go to the') : null, - (this.props.network === '3') ? h('button.text-transform-uppercase', { - onClick: () => this.props.dispatch(actions.buyEth()), + ((network === '3') || (network === '42')) ? h('h3.text-transform-uppercase', 'or go to the') : null, + (network === '3') ? h('button.text-transform-uppercase', { + onClick: () => this.props.dispatch(actions.buyEth({ network })), style: { marginTop: '15px', }, }, 'Ropsten Test Faucet') : null, - (this.props.network === '42') ? h('button.text-transform-uppercase', { - onClick: () => this.props.dispatch(actions.buyEth()), + (network === '42') ? h('button.text-transform-uppercase', { + onClick: () => this.props.dispatch(actions.buyEth({ network })), style: { marginTop: '15px', }, diff --git a/ui/app/components/coinbase-form.js b/ui/app/components/coinbase-form.js index 40f5719bb..fd5816a21 100644 --- a/ui/app/components/coinbase-form.js +++ b/ui/app/components/coinbase-form.js @@ -112,7 +112,7 @@ CoinbaseForm.prototype.toCoinbase = function () { var message if (isValidAddress(address) && isValidAmountforCoinBase(amount).valid) { - props.dispatch(actions.buyEth(address, props.buyView.amount)) + props.dispatch(actions.buyEth({ network: '1', address, amount: props.buyView.amount })) } else if (!isValidAmountforCoinBase(amount).valid) { message = isValidAmountforCoinBase(amount).message return props.dispatch(actions.displayWarning(message)) From 9b9570fd2be5a7bdaf37a663628147976d8c94b4 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 4 Apr 2017 18:48:33 -0700 Subject: [PATCH 2/5] auto-faucet - only skip faucet on explicit test environment --- app/scripts/lib/auto-faucet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/scripts/lib/auto-faucet.js b/app/scripts/lib/auto-faucet.js index 1e059cf73..38d54ba5e 100644 --- a/app/scripts/lib/auto-faucet.js +++ b/app/scripts/lib/auto-faucet.js @@ -4,7 +4,7 @@ const env = process.env.METAMASK_ENV module.exports = function (address) { // Don't faucet in development or test - if (METAMASK_DEBUG || env === 'test') return + if (METAMASK_DEBUG === true || env === 'test') return global.log.info('auto-fauceting:', address) const data = address const headers = new Headers() From 8b146663483849cb76219bbf610c9ff6c5add68d Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 4 Apr 2017 22:43:55 -0700 Subject: [PATCH 3/5] clean - remove unused extension ref --- ui/app/components/transaction-list-item.js | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/ui/app/components/transaction-list-item.js b/ui/app/components/transaction-list-item.js index 0052d9c70..9fef52355 100644 --- a/ui/app/components/transaction-list-item.js +++ b/ui/app/components/transaction-list-item.js @@ -7,7 +7,6 @@ const addressSummary = require('../util').addressSummary const explorerLink = require('../../lib/explorer-link') const CopyButton = require('./copyButton') const vreme = new (require('vreme')) -const extension = require('extensionizer') const Tooltip = require('./tooltip') const TransactionIcon = require('./transaction-list-item-icon') @@ -50,7 +49,7 @@ TransactionListItem.prototype.render = function () { event.stopPropagation() if (!transaction.hash || !isLinkable) return var url = explorerLink(transaction.hash, parseInt(network)) - extension.tabs.create({ url }) + global.platform.openWindow({ url }) }, style: { padding: '20px 0', @@ -63,7 +62,7 @@ TransactionListItem.prototype.render = function () { event.stopPropagation() if (!isTx || isPending) return var url = `https://metamask.github.io/eth-tx-viz/?tx=${transaction.hash}` - extension.tabs.create({ url }) + global.platform.openWindow({ url }) }, }, [ h(TransactionIcon, { txParams, transaction, isTx, isMsg }), From 0cfad78f5decbce04a7fa56e8f80e4fcecd12a79 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 4 Apr 2017 22:45:39 -0700 Subject: [PATCH 4/5] mascara - rename things + break out mascara asset server --- mascara/example/{index.js => app.js} | 0 mascara/example/{ => app}/index.html | 4 +- mascara/example/server.js | 31 ++++++ mascara/{server => proxy}/index.html | 2 +- mascara/server.js | 103 ------------------- mascara/server/index.js | 32 ++++++ mascara/server/util.js | 45 ++++++++ mascara/src/lib/setup-provider.js | 4 +- mascara/src/mascara.js | 15 ++- mascara/src/{dapp-connection.js => proxy.js} | 2 +- mascara/ui/index.html | 11 ++ 11 files changed, 135 insertions(+), 114 deletions(-) rename mascara/example/{index.js => app.js} (100%) rename mascara/example/{ => app}/index.html (79%) create mode 100644 mascara/example/server.js rename mascara/{server => proxy}/index.html (88%) delete mode 100644 mascara/server.js create mode 100644 mascara/server/index.js create mode 100644 mascara/server/util.js rename mascara/src/{dapp-connection.js => proxy.js} (94%) create mode 100644 mascara/ui/index.html diff --git a/mascara/example/index.js b/mascara/example/app.js similarity index 100% rename from mascara/example/index.js rename to mascara/example/app.js diff --git a/mascara/example/index.html b/mascara/example/app/index.html similarity index 79% rename from mascara/example/index.html rename to mascara/example/app/index.html index 47d6da34f..02323e5f9 100644 --- a/mascara/example/index.html +++ b/mascara/example/app/index.html @@ -3,15 +3,13 @@ - MetaMask ZeroClient Example - + - \ No newline at end of file diff --git a/mascara/example/server.js b/mascara/example/server.js new file mode 100644 index 000000000..d39c19600 --- /dev/null +++ b/mascara/example/server.js @@ -0,0 +1,31 @@ +const express = require('express') +const createMetamascaraServer = require('../server/') +const createBundle = require('../server/util').createBundle +const serveBundle = require('../server/util').serveBundle + +// +// Iframe Server +// + +const mascaraServer = createMetamascaraServer() + +// start the server +const mascaraPort = 9001 +mascaraServer.listen(mascaraPort) +console.log(`Mascara service listening on port ${mascaraPort}`) + + +// +// Dapp Server +// + +const dappServer = express() + +// serve dapp bundle +serveBundle(dappServer, '/app.js', createBundle(require.resolve('./app.js'))) +dappServer.use(express.static(__dirname + '/app/')) + +// start the server +const dappPort = '9002' +dappServer.listen(dappPort) +console.log(`Dapp listening on port ${dappPort}`) diff --git a/mascara/server/index.html b/mascara/proxy/index.html similarity index 88% rename from mascara/server/index.html rename to mascara/proxy/index.html index 2308dd98b..b83fc41af 100644 --- a/mascara/server/index.html +++ b/mascara/proxy/index.html @@ -15,6 +15,6 @@ Hello! I am the MetaMask iframe. - + \ No newline at end of file diff --git a/mascara/server.js b/mascara/server.js deleted file mode 100644 index 67c89f11b..000000000 --- a/mascara/server.js +++ /dev/null @@ -1,103 +0,0 @@ -const express = require('express') -const browserify = require('browserify') -const watchify = require('watchify') -const babelify = require('babelify') - -const zeroBundle = createBundle('./src/mascara.js') -const controllerBundle = createBundle('./src/dapp-connection.js') -const popupBundle = createBundle('./src/popup.js') -const swBuild = createBundle('./src/background.js') - -const appBundle = createBundle('./example/index.js') - -// -// Iframe Server -// - -const iframeServer = express() - -// serve popup window -iframeServer.get('/popup/scripts/popup.js', function(req, res){ - res.send(popupBundle.latest) -}) -iframeServer.use('/popup', express.static('../dist/chrome')) - -// serve controller bundle -iframeServer.get('/controller.js', function(req, res){ - res.send(controllerBundle.latest) -}) -iframeServer.get('/popup/sw-build.js', function(req, res){ - console.log('/sw-build.js') - res.setHeader('Content-Type', 'application/javascript') - res.send(swBuild.latest) -}) - -// serve background controller -iframeServer.use(express.static('./server')) - -// start the server -const mascaraPort = 9001 -iframeServer.listen(mascaraPort) -console.log(`Mascara service listening on port ${mascaraPort}`) - - -// -// Dapp Server -// - -const dappServer = express() - -// serve metamask-lib bundle -dappServer.get('/zero.js', function(req, res){ - res.send(zeroBundle.latest) -}) - -// serve dapp bundle -dappServer.get('/app.js', function(req, res){ - res.send(appBundle.latest) -}) - -// serve static -dappServer.use(express.static('./example')) - -// start the server -const dappPort = '9002' -dappServer.listen(dappPort) -console.log(`Dapp listening on port ${dappPort}`) - -// -// util -// - -function serveBundle(entryPoint){ - const bundle = createBundle(entryPoint) - return function(req, res){ - res.send(bundle.latest) - } -} - -function createBundle(entryPoint){ - - var bundleContainer = {} - - var bundler = browserify({ - entries: [entryPoint], - cache: {}, - packageCache: {}, - plugin: [watchify], - }) - - bundler.on('update', bundle) - bundle() - - return bundleContainer - - function bundle() { - bundler.bundle(function(err, result){ - if (err) throw err - console.log(`Bundle updated! (${entryPoint})`) - bundleContainer.latest = result.toString() - }) - } - -} diff --git a/mascara/server/index.js b/mascara/server/index.js new file mode 100644 index 000000000..61dc61a02 --- /dev/null +++ b/mascara/server/index.js @@ -0,0 +1,32 @@ +const express = require('express') +const createBundle = require('./util').createBundle +const serveBundle = require('./util').serveBundle + +module.exports = createMetamascaraServer + + +function createMetamascaraServer(){ + + // start bundlers + const metamascaraBundle = createBundle('./src/mascara.js') + const proxyBundle = createBundle('./src/proxy.js') + const uiBundle = createBundle('./src/popup.js') + const backgroundBuild = createBundle('./src/background.js') + + // serve bundles + const server = express() + // ui window + serveBundle(server, '/ui.js', uiBundle) + server.use(express.static(__dirname+'/../ui/')) + server.use(express.static(__dirname+'/../../dist/chrome')) + // metamascara + serveBundle(server, '/metamascara.js', metamascaraBundle) + // proxy + serveBundle(server, '/proxy/proxy.js', proxyBundle) + server.use('/proxy/', express.static(__dirname+'/../proxy')) + // background + serveBundle(server, '/background.js', backgroundBuild) + + return server + +} diff --git a/mascara/server/util.js b/mascara/server/util.js new file mode 100644 index 000000000..6e25b35d8 --- /dev/null +++ b/mascara/server/util.js @@ -0,0 +1,45 @@ +const browserify = require('browserify') +const watchify = require('watchify') + +module.exports = { + serveBundle, + createBundle, +} + + +function serveBundle(server, path, bundle){ + server.get(path, function(req, res){ + res.setHeader('Content-Type', 'application/javascript; charset=UTF-8') + res.send(bundle.latest) + }) +} + +function createBundle(entryPoint){ + + var bundleContainer = {} + + var bundler = browserify({ + entries: [entryPoint], + cache: {}, + packageCache: {}, + plugin: [watchify], + }) + + bundler.on('update', bundle) + bundle() + + return bundleContainer + + function bundle() { + bundler.bundle(function(err, result){ + if (err) { + console.log(`Bundle failed! (${entryPoint})`) + console.error(err) + return + } + console.log(`Bundle updated! (${entryPoint})`) + bundleContainer.latest = result.toString() + }) + } + +} diff --git a/mascara/src/lib/setup-provider.js b/mascara/src/lib/setup-provider.js index 4f2432ae4..62335b18d 100644 --- a/mascara/src/lib/setup-provider.js +++ b/mascara/src/lib/setup-provider.js @@ -4,14 +4,14 @@ const MetamaskInpageProvider = require('../../../app/scripts/lib/inpage-provider module.exports = getProvider -function getProvider(){ +function getProvider(opts){ if (global.web3) { console.log('MetaMask ZeroClient - using environmental web3 provider') return global.web3.currentProvider } console.log('MetaMask ZeroClient - injecting zero-client iframe!') var iframeStream = setupIframe({ - zeroClientProvider: 'http://localhost:9001', + zeroClientProvider: opts.mascaraUrl, sandboxAttributes: ['allow-scripts', 'allow-popups', 'allow-same-origin'], container: document.body, }) diff --git a/mascara/src/mascara.js b/mascara/src/mascara.js index 759353c1b..f9bed7e52 100644 --- a/mascara/src/mascara.js +++ b/mascara/src/mascara.js @@ -1,15 +1,22 @@ const Web3 = require('web3') const setupProvider = require('./lib/setup-provider.js') +const MASACARA_DOMAIN = 'http://localhost:9001' + // // setup web3 // -var provider = setupProvider() -hijackProvider(provider) + +var provider = setupProvider({ + mascaraUrl: MASACARA_DOMAIN + '/proxy/', +}) +instrumentForUserInteractionTriggers(provider) + var web3 = new Web3(provider) web3.setProvider = function(){ console.log('MetaMask - overrode web3.setProvider') } + // // // export web3 @@ -25,12 +32,12 @@ var shouldPop = false window.addEventListener('click', function(){ if (!shouldPop) return shouldPop = false - window.open('http://localhost:9001/popup/popup.html', '', 'width=360 height=500') + window.open(MASACARA_DOMAIN, '', 'width=360 height=500') console.log('opening window...') }) -function hijackProvider(provider){ +function instrumentForUserInteractionTriggers(provider){ var _super = provider.sendAsync.bind(provider) provider.sendAsync = function(payload, cb){ if (payload.method === 'eth_sendTransaction') { diff --git a/mascara/src/dapp-connection.js b/mascara/src/proxy.js similarity index 94% rename from mascara/src/dapp-connection.js rename to mascara/src/proxy.js index 30680c9d7..e580076c1 100644 --- a/mascara/src/dapp-connection.js +++ b/mascara/src/proxy.js @@ -4,7 +4,7 @@ const SwStream = require('sw-stream/lib/sw-stream.js') const SetupUntrustedComunication = ('./lib/setup-untrusted-connection.js') const background = new SWcontroller({ - fileName: '/popup/sw-build.js', + fileName: '/background.js', }) const pageStream = new ParentStream() diff --git a/mascara/ui/index.html b/mascara/ui/index.html new file mode 100644 index 000000000..c5eeb05ef --- /dev/null +++ b/mascara/ui/index.html @@ -0,0 +1,11 @@ + + + + + MetaMask Plugin + + +
+ + + \ No newline at end of file From 1aac162b462424f5b6ce6685f337670368bd10b5 Mon Sep 17 00:00:00 2001 From: kumavis Date: Tue, 4 Apr 2017 23:08:46 -0700 Subject: [PATCH 5/5] mascara - rename popup to ui --- mascara/server/index.js | 2 +- mascara/src/{popup.js => ui.js} | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) rename mascara/src/{popup.js => ui.js} (93%) diff --git a/mascara/server/index.js b/mascara/server/index.js index 61dc61a02..9fd664eee 100644 --- a/mascara/server/index.js +++ b/mascara/server/index.js @@ -10,7 +10,7 @@ function createMetamascaraServer(){ // start bundlers const metamascaraBundle = createBundle('./src/mascara.js') const proxyBundle = createBundle('./src/proxy.js') - const uiBundle = createBundle('./src/popup.js') + const uiBundle = createBundle('./src/ui.js') const backgroundBuild = createBundle('./src/background.js') // serve bundles diff --git a/mascara/src/popup.js b/mascara/src/ui.js similarity index 93% rename from mascara/src/popup.js rename to mascara/src/ui.js index b740e81a5..c4866867b 100644 --- a/mascara/src/popup.js +++ b/mascara/src/ui.js @@ -19,7 +19,7 @@ var name = 'popup' window.METAMASK_UI_TYPE = name const background = new SWcontroller({ - fileName: '/popup/sw-build.js', + fileName: '/background.js', }) // Setup listener for when the service worker is read @@ -38,4 +38,4 @@ background.on('ready', (readSw) => { }) background.startWorker() -console.log('hello from /library/popup.js') +console.log('hello from MetaMascara ui!')