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

Restore support for @metamask/inpage provider@"< 8.0.0" (#10179)

This restores support for versions of the inpage provider prior to v8.
This is intended to support dapps and extensions that directly
instantiated their own provider rather than using the injected
provider.

* Forward traffic between old and new provider streams

* Ignore publicConfig stream for non-legacy muxes

* Transform accountsChanged notification for legacy streams

* Convert publicConfigStore to singleton

Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This commit is contained in:
Erik Marks 2021-01-12 17:43:45 -08:00 committed by GitHub
parent 849a47afba
commit 0dfdd44ae7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 140 additions and 0 deletions

View File

@ -4,6 +4,7 @@ import LocalMessageDuplexStream from 'post-message-stream'
import ObjectMultiplex from 'obj-multiplex'
import extension from 'extensionizer'
import PortStream from 'extension-port-stream'
import { obj as createThoughStream } from 'through2'
// These require calls need to use require to be statically recognized by browserify
const fs = require('fs')
@ -20,6 +21,12 @@ const CONTENT_SCRIPT = 'metamask-contentscript'
const INPAGE = 'metamask-inpage'
const PROVIDER = 'metamask-provider'
// TODO:LegacyProvider: Delete
const LEGACY_CONTENT_SCRIPT = 'contentscript'
const LEGACY_INPAGE = 'inpage'
const LEGACY_PROVIDER = 'provider'
const LEGACY_PUBLIC_CONFIG = 'publicConfig'
if (shouldInjectProvider()) {
injectScript(inpageBundle)
setupStreams()
@ -63,6 +70,7 @@ async function setupStreams() {
pageMux.setMaxListeners(25)
const extensionMux = new ObjectMultiplex()
extensionMux.setMaxListeners(25)
extensionMux.ignoreStream(LEGACY_PUBLIC_CONFIG) // TODO:LegacyProvider: Delete
pump(pageMux, pageStream, pageMux, (err) =>
logStreamDisconnectWarning('MetaMask Inpage Multiplex', err),
@ -78,6 +86,44 @@ async function setupStreams() {
// connect "phishing" channel to warning system
const phishingStream = extensionMux.createStream('phishing')
phishingStream.once('data', redirectToPhishingWarning)
// TODO:LegacyProvider: Delete
// handle legacy provider
const legacyPageStream = new LocalMessageDuplexStream({
name: LEGACY_CONTENT_SCRIPT,
target: LEGACY_INPAGE,
})
const legacyPageMux = new ObjectMultiplex()
legacyPageMux.setMaxListeners(25)
const legacyExtensionMux = new ObjectMultiplex()
legacyExtensionMux.setMaxListeners(25)
pump(legacyPageMux, legacyPageStream, legacyPageMux, (err) =>
logStreamDisconnectWarning('MetaMask Legacy Inpage Multiplex', err),
)
pump(
legacyExtensionMux,
extensionStream,
getNotificationTransformStream(),
legacyExtensionMux,
(err) => {
logStreamDisconnectWarning('MetaMask Background Legacy Multiplex', err)
notifyInpageOfStreamFailure()
},
)
forwardNamedTrafficBetweenMuxes(
LEGACY_PROVIDER,
PROVIDER,
legacyPageMux,
legacyExtensionMux,
)
forwardTrafficBetweenMuxes(
LEGACY_PUBLIC_CONFIG,
legacyPageMux,
legacyExtensionMux,
)
}
function forwardTrafficBetweenMuxes(channelName, muxA, muxB) {
@ -91,6 +137,37 @@ function forwardTrafficBetweenMuxes(channelName, muxA, muxB) {
)
}
// TODO:LegacyProvider: Delete
function forwardNamedTrafficBetweenMuxes(
channelAName,
channelBName,
muxA,
muxB,
) {
const channelA = muxA.createStream(channelAName)
const channelB = muxB.createStream(channelBName)
pump(channelA, channelB, channelA, (error) =>
console.debug(
`MetaMask: Muxed traffic between channels "${channelAName}" and "${channelBName}" failed.`,
error,
),
)
}
// TODO:LegacyProvider: Delete
function getNotificationTransformStream() {
return createThoughStream((chunk, _, cb) => {
if (chunk?.name === PROVIDER) {
if (chunk.data?.method === 'metamask_accountsChanged') {
chunk.data.method = 'wallet_accountsChanged'
chunk.data.result = chunk.data.params
delete chunk.data.params
}
}
cb(null, chunk)
})
}
/**
* Error handler for page to extension stream disconnections
*

View File

@ -1,6 +1,8 @@
import EventEmitter from 'events'
import pump from 'pump'
import Dnode from 'dnode'
import { ObservableStore } from '@metamask/obs-store'
import { storeAsStream } from '@metamask/obs-store/dist/asStream'
import { JsonRpcEngine } from 'json-rpc-engine'
import { debounce } from 'lodash'
import createEngineStream from 'json-rpc-middleware-stream/engineStream'
@ -413,6 +415,9 @@ export default class MetamaskController extends EventEmitter {
) {
this.submitPassword(password)
}
// TODO:LegacyProvider: Delete
this.publicConfigStore = this.createPublicConfigStore()
}
/**
@ -459,6 +464,38 @@ export default class MetamaskController extends EventEmitter {
return providerProxy
}
/**
* TODO:LegacyProvider: Delete
* Constructor helper: initialize a public config store.
* This store is used to make some config info available to Dapps synchronously.
*/
createPublicConfigStore() {
// subset of state for metamask inpage provider
const publicConfigStore = new ObservableStore()
const { networkController } = this
// setup memStore subscription hooks
this.on('update', updatePublicConfigStore)
updatePublicConfigStore(this.getState())
function updatePublicConfigStore(memState) {
const chainId = networkController.getCurrentChainId()
if (memState.network !== 'loading') {
publicConfigStore.putState(selectPublicState(chainId, memState))
}
}
function selectPublicState(chainId, { isUnlocked, network }) {
return {
isUnlocked,
chainId,
networkVersion: network,
}
}
return publicConfigStore
}
/**
* Gets relevant state for the provider of an external origin.
*
@ -1831,6 +1868,10 @@ export default class MetamaskController extends EventEmitter {
// messages between inpage and background
this.setupProviderConnection(mux.createStream('metamask-provider'), sender)
// TODO:LegacyProvider: Delete
// legacy streams
this.setupPublicConfig(mux.createStream('publicConfig'))
}
/**
@ -2016,6 +2057,28 @@ export default class MetamaskController extends EventEmitter {
return engine
}
/**
* TODO:LegacyProvider: Delete
* A method for providing our public config info over a stream.
* This includes info we like to be synchronous if possible, like
* the current selected account, and network ID.
*
* Since synchronous methods have been deprecated in web3,
* this is a good candidate for deprecation.
*
* @param {*} outStream - The stream to provide public config over.
*/
setupPublicConfig(outStream) {
const configStream = storeAsStream(this.publicConfigStore)
pump(configStream, outStream, (err) => {
configStream.destroy()
if (err) {
log.error(err)
}
})
}
/**
* Adds a reference to a connection by origin. Ignores the 'metamask' origin.
* Caller must ensure that the returned id is stored such that the reference