mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-11-22 09:57:02 +01:00
Implement some cross-browser practices (#473)
* Add mozilla plugin key to manifest * Move all chrome references into platform-checking module Addresses #453 * Add chrome global back to linter blacklist * Add tests
This commit is contained in:
parent
cdd7e40545
commit
6658bea8d4
1
.eslintignore
Normal file
1
.eslintignore
Normal file
@ -0,0 +1 @@
|
||||
app/scripts/lib/extension-instance.js
|
@ -23,7 +23,6 @@
|
||||
],
|
||||
|
||||
"globals": {
|
||||
"chrome": true,
|
||||
"document": false,
|
||||
"navigator": false,
|
||||
"web3": true,
|
||||
|
@ -37,6 +37,11 @@
|
||||
"all_frames": false
|
||||
}
|
||||
],
|
||||
"applications": {
|
||||
"gecko": {
|
||||
"id": "MOZILLA_EXTENSION_ID"
|
||||
}
|
||||
},
|
||||
"permissions": [
|
||||
"notifications",
|
||||
"storage",
|
||||
|
@ -9,6 +9,7 @@ const createMsgNotification = require('./lib/notifications.js').createMsgNotific
|
||||
const messageManager = require('./lib/message-manager')
|
||||
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
|
||||
const MetamaskController = require('./metamask-controller')
|
||||
const extension = require('./lib/extension')
|
||||
|
||||
const STORAGE_KEY = 'metamask-config'
|
||||
|
||||
@ -65,7 +66,7 @@ function showUnconfirmedTx (txParams, txData, onTxDoneCb) {
|
||||
// connect to other contexts
|
||||
//
|
||||
|
||||
chrome.runtime.onConnect.addListener(connectRemote)
|
||||
extension.runtime.onConnect.addListener(connectRemote)
|
||||
function connectRemote (remotePort) {
|
||||
var isMetaMaskInternalProcess = (remotePort.name === 'popup')
|
||||
var portStream = new PortStream(remotePort)
|
||||
@ -133,8 +134,8 @@ function updateBadge (state) {
|
||||
if (count) {
|
||||
label = String(count)
|
||||
}
|
||||
chrome.browserAction.setBadgeText({ text: label })
|
||||
chrome.browserAction.setBadgeBackgroundColor({ color: '#506F8B' })
|
||||
extension.browserAction.setBadgeText({ text: label })
|
||||
extension.browserAction.setBadgeBackgroundColor({ color: '#506F8B' })
|
||||
}
|
||||
|
||||
function loadData () {
|
||||
|
@ -25,11 +25,12 @@
|
||||
// if (e.data) {
|
||||
// var data = JSON.parse(e.data);
|
||||
// if (data && data.command === 'reload') {
|
||||
// chrome.runtime.reload();
|
||||
// extension.runtime.reload();
|
||||
// }
|
||||
// }
|
||||
// };
|
||||
|
||||
const extension = require('./lib/extension')
|
||||
window.LiveReloadOptions = { host: 'localhost' };
|
||||
|
||||
(function e (t, n, r) { function s (o, u) { if (!n[o]) { if (!t[o]) { var a = typeof require === 'function' && require; if (!u && a) return a(o, !0); if (i) return i(o, !0); var f = new Error("Cannot find module '" + o + "'"); throw f.code = 'MODULE_NOT_FOUND', f } var l = n[o] = {exports: {}}; t[o][0].call(l.exports, function (e) { var n = t[o][1][e]; return s(n ? n : e) }, l, l.exports, e, t, n, r) } return n[o].exports } var i = typeof require === 'function' && require; for (var o = 0; o < r.length; o++)s(r[o]); return s })({1: [function (require, module, exports) {
|
||||
|
@ -1,6 +1,7 @@
|
||||
const LocalMessageDuplexStream = require('./lib/local-message-stream.js')
|
||||
const PortStream = require('./lib/port-stream.js')
|
||||
const ObjectMultiplex = require('./lib/obj-multiplex')
|
||||
const extension = require('./lib/extension')
|
||||
|
||||
if (shouldInjectWeb3()) {
|
||||
setupInjection()
|
||||
@ -10,7 +11,7 @@ if (shouldInjectWeb3()) {
|
||||
function setupInjection(){
|
||||
// inject in-page script
|
||||
var scriptTag = document.createElement('script')
|
||||
scriptTag.src = chrome.extension.getURL('scripts/inpage.js')
|
||||
scriptTag.src = extension.extension.getURL('scripts/inpage.js')
|
||||
scriptTag.onload = function () { this.parentNode.removeChild(this) }
|
||||
var container = document.head || document.documentElement
|
||||
// append as first child
|
||||
@ -25,7 +26,7 @@ function setupStreams(){
|
||||
target: 'inpage',
|
||||
})
|
||||
pageStream.on('error', console.error.bind(console))
|
||||
var pluginPort = chrome.runtime.connect({name: 'contentscript'})
|
||||
var pluginPort = extension.runtime.connect({name: 'contentscript'})
|
||||
var pluginStream = new PortStream(pluginPort)
|
||||
pluginStream.on('error', console.error.bind(console))
|
||||
|
||||
@ -49,4 +50,4 @@ function setupStreams(){
|
||||
function shouldInjectWeb3(){
|
||||
var shouldInject = (window.location.href.indexOf('.pdf') === -1)
|
||||
return shouldInject
|
||||
}
|
||||
}
|
||||
|
38
app/scripts/lib/extension-instance.js
Normal file
38
app/scripts/lib/extension-instance.js
Normal file
@ -0,0 +1,38 @@
|
||||
const apis = [
|
||||
'alarms',
|
||||
'bookmarks',
|
||||
'browserAction',
|
||||
'commands',
|
||||
'contextMenus',
|
||||
'cookies',
|
||||
'downloads',
|
||||
'events',
|
||||
'extension',
|
||||
'extensionTypes',
|
||||
'history',
|
||||
'i18n',
|
||||
'idle',
|
||||
'notifications',
|
||||
'pageAction',
|
||||
'runtime',
|
||||
'storage',
|
||||
'tabs',
|
||||
'webNavigation',
|
||||
'webRequest',
|
||||
'windows',
|
||||
]
|
||||
|
||||
function Extension () {
|
||||
const _this = this
|
||||
let global = window
|
||||
|
||||
if (window.chrome) {
|
||||
global = window.chrome
|
||||
}
|
||||
|
||||
apis.forEach(function (api) {
|
||||
_this[api] = global[api]
|
||||
})
|
||||
}
|
||||
|
||||
module.exports = Extension
|
14
app/scripts/lib/extension.js
Normal file
14
app/scripts/lib/extension.js
Normal file
@ -0,0 +1,14 @@
|
||||
/* Extension.js
|
||||
*
|
||||
* A module for unifying browser differences in the WebExtension API.
|
||||
*
|
||||
* Initially implemented because Chrome hides all of their WebExtension API
|
||||
* behind a global `chrome` variable, but we'd like to start grooming
|
||||
* the code-base for cross-browser extension support.
|
||||
*
|
||||
* You can read more about the WebExtension API here:
|
||||
* https://developer.mozilla.org/en-US/Add-ons/WebExtensions
|
||||
*/
|
||||
|
||||
const Extension = require('./extension-instance')
|
||||
module.exports = new Extension()
|
@ -7,6 +7,7 @@ const h = require('react-hyperscript')
|
||||
const PendingTxDetails = require('../../../ui/app/components/pending-tx-details')
|
||||
const PendingMsgDetails = require('../../../ui/app/components/pending-msg-details')
|
||||
const MetaMaskUiCss = require('../../../ui/css')
|
||||
const extension = require('./extension')
|
||||
var notificationHandlers = {}
|
||||
|
||||
const notifications = {
|
||||
@ -20,34 +21,34 @@ window.METAMASK_NOTIFIER = notifications
|
||||
setupListeners()
|
||||
|
||||
function setupListeners () {
|
||||
// guard for chrome bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!chrome.notifications) return console.error('Chrome notifications API missing...')
|
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...')
|
||||
|
||||
// notification button press
|
||||
chrome.notifications.onButtonClicked.addListener(function (notificationId, buttonIndex) {
|
||||
extension.notifications.onButtonClicked.addListener(function (notificationId, buttonIndex) {
|
||||
var handlers = notificationHandlers[notificationId]
|
||||
if (buttonIndex === 0) {
|
||||
handlers.confirm()
|
||||
} else {
|
||||
handlers.cancel()
|
||||
}
|
||||
chrome.notifications.clear(notificationId)
|
||||
extension.notifications.clear(notificationId)
|
||||
})
|
||||
|
||||
// notification teardown
|
||||
chrome.notifications.onClosed.addListener(function (notificationId) {
|
||||
extension.notifications.onClosed.addListener(function (notificationId) {
|
||||
delete notificationHandlers[notificationId]
|
||||
})
|
||||
}
|
||||
|
||||
// creation helper
|
||||
function createUnlockRequestNotification (opts) {
|
||||
// guard for chrome bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!chrome.notifications) return console.error('Chrome notifications API missing...')
|
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...')
|
||||
var message = 'An Ethereum app has requested a signature. Please unlock your account.'
|
||||
|
||||
var id = createId()
|
||||
chrome.notifications.create(id, {
|
||||
extension.notifications.create(id, {
|
||||
type: 'basic',
|
||||
iconUrl: '/images/icon-128.png',
|
||||
title: opts.title,
|
||||
@ -56,8 +57,8 @@ function createUnlockRequestNotification (opts) {
|
||||
}
|
||||
|
||||
function createTxNotification (state) {
|
||||
// guard for chrome bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!chrome.notifications) return console.error('Chrome notifications API missing...')
|
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...')
|
||||
|
||||
renderTxNotificationSVG(state, function (err, notificationSvgSource) {
|
||||
if (err) throw err
|
||||
@ -70,8 +71,8 @@ function createTxNotification (state) {
|
||||
}
|
||||
|
||||
function createMsgNotification (state) {
|
||||
// guard for chrome bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!chrome.notifications) return console.error('Chrome notifications API missing...')
|
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...')
|
||||
|
||||
renderMsgNotificationSVG(state, function (err, notificationSvgSource) {
|
||||
if (err) throw err
|
||||
@ -84,11 +85,11 @@ function createMsgNotification (state) {
|
||||
}
|
||||
|
||||
function showNotification (state) {
|
||||
// guard for chrome bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!chrome.notifications) return console.error('Chrome notifications API missing...')
|
||||
// guard for extension bug https://github.com/MetaMask/metamask-plugin/issues/236
|
||||
if (!extension.notifications) return console.error('Chrome notifications API missing...')
|
||||
|
||||
var id = createId()
|
||||
chrome.notifications.create(id, {
|
||||
extension.notifications.create(id, {
|
||||
type: 'image',
|
||||
requireInteraction: true,
|
||||
iconUrl: '/images/icon-128.png',
|
||||
|
@ -6,6 +6,7 @@ const messageManager = require('./lib/message-manager')
|
||||
const HostStore = require('./lib/remote-store.js').HostStore
|
||||
const Web3 = require('web3')
|
||||
const ConfigManager = require('./lib/config-manager')
|
||||
const extension = require('./lib/extension')
|
||||
|
||||
module.exports = class MetamaskController {
|
||||
|
||||
@ -239,19 +240,19 @@ module.exports = class MetamaskController {
|
||||
// called from popup
|
||||
setRpcTarget (rpcTarget) {
|
||||
this.configManager.setRpcTarget(rpcTarget)
|
||||
chrome.runtime.reload()
|
||||
extension.runtime.reload()
|
||||
this.idStore.getNetwork()
|
||||
}
|
||||
|
||||
setProviderType (type) {
|
||||
this.configManager.setProviderType(type)
|
||||
chrome.runtime.reload()
|
||||
extension.runtime.reload()
|
||||
this.idStore.getNetwork()
|
||||
}
|
||||
|
||||
useEtherscanProvider () {
|
||||
this.configManager.useEtherscanProvider()
|
||||
chrome.runtime.reload()
|
||||
extension.runtime.reload()
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,6 +9,7 @@ const injectCss = require('inject-css')
|
||||
const PortStream = require('./lib/port-stream.js')
|
||||
const StreamProvider = require('web3-stream-provider')
|
||||
const setupMultiplex = require('./lib/stream-utils.js').setupMultiplex
|
||||
const extension = require('./lib/extension')
|
||||
|
||||
// setup app
|
||||
var css = MetaMaskUiCss()
|
||||
@ -21,7 +22,7 @@ async.parallel({
|
||||
|
||||
function connectToAccountManager (cb) {
|
||||
// setup communication with background
|
||||
var pluginPort = chrome.runtime.connect({name: 'popup'})
|
||||
var pluginPort = extension.runtime.connect({name: 'popup'})
|
||||
var portStream = new PortStream(pluginPort)
|
||||
// setup multiplexing
|
||||
var mx = setupMultiplex(portStream)
|
||||
@ -55,8 +56,8 @@ function setupControllerConnection (stream, cb) {
|
||||
|
||||
function getCurrentDomain (cb) {
|
||||
const unknown = '<unknown>'
|
||||
if (!chrome.tabs) return cb(null, unknown)
|
||||
chrome.tabs.query({active: true, currentWindow: true}, function (results) {
|
||||
if (!extension.tabs) return cb(null, unknown)
|
||||
extension.tabs.query({active: true, currentWindow: true}, function (results) {
|
||||
var activeTab = results[0]
|
||||
var currentUrl = activeTab && activeTab.url
|
||||
var currentDomain = url.parse(currentUrl).host
|
||||
@ -68,9 +69,9 @@ function getCurrentDomain (cb) {
|
||||
}
|
||||
|
||||
function clearNotifications(){
|
||||
chrome.notifications.getAll(function (object) {
|
||||
extension.notifications.getAll(function (object) {
|
||||
for (let notification in object){
|
||||
chrome.notifications.clear(notification)
|
||||
extension.notifications.clear(notification)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
39
test/unit/extension-test.js
Normal file
39
test/unit/extension-test.js
Normal file
@ -0,0 +1,39 @@
|
||||
var assert = require('assert')
|
||||
var sinon = require('sinon')
|
||||
const ethUtil = require('ethereumjs-util')
|
||||
|
||||
var path = require('path')
|
||||
var Extension = require(path.join(__dirname, '..', '..', 'app', 'scripts', 'lib', 'extension-instance.js'))
|
||||
|
||||
describe('extension', function() {
|
||||
|
||||
describe('with chrome global', function() {
|
||||
let extension
|
||||
|
||||
beforeEach(function() {
|
||||
window.chrome = {
|
||||
alarms: 'foo'
|
||||
}
|
||||
extension = new Extension()
|
||||
})
|
||||
|
||||
it('should use the chrome global apis', function() {
|
||||
assert.equal(extension.alarms, 'foo')
|
||||
})
|
||||
})
|
||||
|
||||
describe('without chrome global', function() {
|
||||
let extension
|
||||
|
||||
beforeEach(function() {
|
||||
window.chrome = undefined
|
||||
window.alarms = 'foo'
|
||||
extension = new Extension()
|
||||
})
|
||||
|
||||
it('should use the global apis', function() {
|
||||
assert.equal(extension.alarms, 'foo')
|
||||
})
|
||||
})
|
||||
|
||||
})
|
@ -7,6 +7,7 @@ const addressSummary = require('../util').addressSummary
|
||||
const explorerLink = require('../../lib/explorer-link')
|
||||
const CopyButton = require('./copyButton')
|
||||
const vreme = new (require('vreme'))
|
||||
const extension = require('../../../app/scripts/lib/extension')
|
||||
|
||||
const TransactionIcon = require('./transaction-list-item-icon')
|
||||
|
||||
@ -49,7 +50,7 @@ TransactionListItem.prototype.render = function () {
|
||||
|
||||
if (!transaction.hash || !isLinkable) return
|
||||
var url = explorerLink(transaction.hash, parseInt(network))
|
||||
chrome.tabs.create({ url })
|
||||
extension.tabs.create({ url })
|
||||
},
|
||||
style: {
|
||||
padding: '20px 0',
|
||||
|
@ -3,6 +3,7 @@ const Component = require('react').Component
|
||||
const h = require('react-hyperscript')
|
||||
const connect = require('react-redux').connect
|
||||
const actions = require('./actions')
|
||||
const extension = require('../../app/scripts/lib/extension')
|
||||
|
||||
module.exports = connect(mapStateToProps)(InfoScreen)
|
||||
|
||||
@ -19,7 +20,7 @@ InfoScreen.prototype.render = function () {
|
||||
var state = this.props
|
||||
var manifest
|
||||
try {
|
||||
manifest = chrome.runtime.getManifest()
|
||||
manifest = extension.runtime.getManifest()
|
||||
} catch (e) {
|
||||
manifest = { version: '2.0.0' }
|
||||
}
|
||||
@ -105,7 +106,7 @@ InfoScreen.prototype.render = function () {
|
||||
h('a.info', {
|
||||
target: '_blank',
|
||||
style: { width: '85vw' },
|
||||
onClick () { chrome.tabs.create({url: 'mailto:help@metamask.io?subject=Feedback'}) },
|
||||
onClick () { extension.tabs.create({url: 'mailto:help@metamask.io?subject=Feedback'}) },
|
||||
}, 'Email us any questions or comments!'),
|
||||
]),
|
||||
|
||||
@ -124,5 +125,5 @@ InfoScreen.prototype.render = function () {
|
||||
}
|
||||
|
||||
InfoScreen.prototype.navigateTo = function (url) {
|
||||
chrome.tabs.create({ url })
|
||||
extension.tabs.create({ url })
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user