mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
1282ed774e
During the initialization of the full-screen or popup UI, we attempted to close the notification popup (if it was open). This never worked (or at least hasn't in a long time). The method used to attempt closing the notification popup was `closePopup` from the `notificationManager`, which keeps track internally of the id of the notification popup window, and can close the window by using this id. However, this id is only set in the first place if the popup is opened with this specific instance of the `notificationManager`. The popup is never opened from the UI in practice; it's only opened from the background (which has its own instance of `notificationManager`). The popup id is never set for this `notificationManager` instance in the UI. It's not entirely clear that we'd always want to close the notification popup in this circumstance anyway. The user might want to open MetaMask alongside the popup to check something else.
167 lines
5.1 KiB
JavaScript
167 lines
5.1 KiB
JavaScript
|
|
// this must run before anything else
|
|
import './lib/freezeGlobals'
|
|
|
|
// polyfills
|
|
import 'abortcontroller-polyfill/dist/polyfill-patch-fetch'
|
|
|
|
import PortStream from 'extension-port-stream'
|
|
import { getEnvironmentType } from './lib/util'
|
|
|
|
import {
|
|
ENVIRONMENT_TYPE_FULLSCREEN,
|
|
ENVIRONMENT_TYPE_POPUP,
|
|
} from './lib/enums'
|
|
|
|
import extension from 'extensionizer'
|
|
import ExtensionPlatform from './platforms/extension'
|
|
|
|
import setupSentry from './lib/setupSentry'
|
|
import { EventEmitter } from 'events'
|
|
import Dnode from 'dnode'
|
|
import Eth from 'ethjs'
|
|
import EthQuery from 'eth-query'
|
|
import urlUtil from 'url'
|
|
import launchMetaMaskUi from '../../ui'
|
|
import StreamProvider from 'web3-stream-provider'
|
|
import { setupMultiplex } from './lib/stream-utils.js'
|
|
import log from 'loglevel'
|
|
|
|
start().catch(log.error)
|
|
|
|
async function start () {
|
|
|
|
// create platform global
|
|
global.platform = new ExtensionPlatform()
|
|
|
|
// setup sentry error reporting
|
|
const release = global.platform.getVersion()
|
|
setupSentry({ release, getState })
|
|
// provide app state to append to error logs
|
|
function getState () {
|
|
// get app state
|
|
const state = window.getCleanAppState
|
|
? window.getCleanAppState()
|
|
: {}
|
|
// remove unnecessary data
|
|
delete state.localeMessages
|
|
delete state.metamask.recentBlocks
|
|
// return state to be added to request
|
|
return state
|
|
}
|
|
|
|
// identify window type (popup, notification)
|
|
const windowType = getEnvironmentType()
|
|
|
|
// setup stream to background
|
|
const extensionPort = extension.runtime.connect({ name: windowType })
|
|
const connectionStream = new PortStream(extensionPort)
|
|
|
|
const activeTab = await queryCurrentActiveTab(windowType)
|
|
initializeUiWithTab(activeTab)
|
|
|
|
function displayCriticalError (container, err) {
|
|
container.innerHTML = '<div class="critical-error">The MetaMask app failed to load: please open and close MetaMask again to restart.</div>'
|
|
container.style.height = '80px'
|
|
log.error(err.stack)
|
|
throw err
|
|
}
|
|
|
|
function initializeUiWithTab (tab) {
|
|
const container = document.getElementById('app-content')
|
|
initializeUi(tab, container, connectionStream, (err, store) => {
|
|
if (err) {
|
|
return displayCriticalError(container, err)
|
|
}
|
|
|
|
const state = store.getState()
|
|
const { metamask: { completedOnboarding } = {} } = state
|
|
|
|
if (!completedOnboarding && windowType !== ENVIRONMENT_TYPE_FULLSCREEN) {
|
|
global.platform.openExtensionInBrowser()
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
async function queryCurrentActiveTab (windowType) {
|
|
return new Promise((resolve) => {
|
|
// At the time of writing we only have the `activeTab` permission which means
|
|
// that this query will only succeed in the popup context (i.e. after a "browserAction")
|
|
if (windowType !== ENVIRONMENT_TYPE_POPUP) {
|
|
resolve({})
|
|
return
|
|
}
|
|
|
|
extension.tabs.query({ active: true, currentWindow: true }, (tabs) => {
|
|
const [activeTab] = tabs
|
|
const { title, url } = activeTab
|
|
const { hostname: origin, protocol } = url ? urlUtil.parse(url) : {}
|
|
resolve({
|
|
title, origin, protocol, url,
|
|
})
|
|
})
|
|
})
|
|
}
|
|
|
|
function initializeUi (activeTab, container, connectionStream, cb) {
|
|
connectToAccountManager(connectionStream, (err, backgroundConnection) => {
|
|
if (err) {
|
|
return cb(err)
|
|
}
|
|
|
|
launchMetaMaskUi({
|
|
activeTab,
|
|
container,
|
|
backgroundConnection,
|
|
}, cb)
|
|
})
|
|
}
|
|
|
|
/**
|
|
* Establishes a connection to the background and a Web3 provider
|
|
*
|
|
* @param {PortDuplexStream} connectionStream - PortStream instance establishing a background connection
|
|
* @param {Function} cb - Called when controller connection is established
|
|
*/
|
|
function connectToAccountManager (connectionStream, cb) {
|
|
const mx = setupMultiplex(connectionStream)
|
|
setupControllerConnection(mx.createStream('controller'), cb)
|
|
setupWeb3Connection(mx.createStream('provider'))
|
|
}
|
|
|
|
/**
|
|
* Establishes a streamed connection to a Web3 provider
|
|
*
|
|
* @param {PortDuplexStream} connectionStream - PortStream instance establishing a background connection
|
|
*/
|
|
function setupWeb3Connection (connectionStream) {
|
|
const providerStream = new StreamProvider()
|
|
providerStream.pipe(connectionStream).pipe(providerStream)
|
|
connectionStream.on('error', console.error.bind(console))
|
|
providerStream.on('error', console.error.bind(console))
|
|
global.ethereumProvider = providerStream
|
|
global.ethQuery = new EthQuery(providerStream)
|
|
global.eth = new Eth(providerStream)
|
|
}
|
|
|
|
/**
|
|
* Establishes a streamed connection to the background account manager
|
|
*
|
|
* @param {PortDuplexStream} connectionStream - PortStream instance establishing a background connection
|
|
* @param {Function} cb - Called when the remote account manager connection is established
|
|
*/
|
|
function setupControllerConnection (connectionStream, cb) {
|
|
const eventEmitter = new EventEmitter()
|
|
const backgroundDnode = Dnode({
|
|
sendUpdate: function (state) {
|
|
eventEmitter.emit('update', state)
|
|
},
|
|
})
|
|
connectionStream.pipe(backgroundDnode).pipe(connectionStream)
|
|
backgroundDnode.once('remote', function (backgroundConnection) {
|
|
backgroundConnection.on = eventEmitter.on.bind(eventEmitter)
|
|
cb(null, backgroundConnection)
|
|
})
|
|
}
|