mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Remove web3 injection (#9156)
* Remove web3 injection * Implement logWeb3ShimUsage
This commit is contained in:
parent
26272d3557
commit
6795298c65
@ -35,10 +35,6 @@ import log from 'loglevel'
|
||||
import LocalMessageDuplexStream from 'post-message-stream'
|
||||
import { initProvider } from '@metamask/inpage-provider'
|
||||
|
||||
// TODO:deprecate:2020
|
||||
import setupWeb3 from './lib/setupWeb3'
|
||||
/* eslint-enable import/first */
|
||||
|
||||
restoreContextAfterImports()
|
||||
|
||||
log.setDefaultLevel(process.env.METAMASK_DEBUG ? 'debug' : 'warn')
|
||||
@ -56,17 +52,3 @@ const metamaskStream = new LocalMessageDuplexStream({
|
||||
initProvider({
|
||||
connectionStream: metamaskStream,
|
||||
})
|
||||
|
||||
// TODO:deprecate:2020
|
||||
// Setup web3
|
||||
|
||||
if (typeof window.web3 === 'undefined') {
|
||||
// proxy web3, assign to window, and set up site auto reload
|
||||
setupWeb3(log)
|
||||
} else {
|
||||
log.warn(`MetaMask detected another web3.
|
||||
MetaMask will not work reliably with another web3 extension.
|
||||
This usually happens if you have two MetaMasks installed,
|
||||
or MetaMask and another web3 extension. Please remove one
|
||||
and try again.`)
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ const MESSAGE_TYPE = {
|
||||
ETH_GET_ENCRYPTION_PUBLIC_KEY: 'eth_getEncryptionPublicKey',
|
||||
ETH_SIGN: 'eth_sign',
|
||||
ETH_SIGN_TYPED_DATA: 'eth_signTypedData',
|
||||
LOG_WEB3_USAGE: 'metamask_logInjectedWeb3Usage',
|
||||
LOG_WEB3_SHIM_USAGE: 'metamask_logWeb3ShimUsage',
|
||||
PERSONAL_SIGN: 'personal_sign',
|
||||
WATCH_ASSET: 'wallet_watchAsset',
|
||||
WATCH_ASSET_LEGACY: 'metamask_watchAsset',
|
||||
|
@ -21,7 +21,6 @@ const handlerMap = handlers.reduce((map, handler) => {
|
||||
* Eventually, we'll want to extract this middleware into its own package.
|
||||
*
|
||||
* @param {Object} opts - The middleware options
|
||||
* @param {string} opts.origin - The origin for the middleware stack
|
||||
* @param {Function} opts.sendMetrics - A function for sending a metrics event
|
||||
* @returns {(req: Object, res: Object, next: Function, end: Function) => void}
|
||||
*/
|
||||
|
@ -1,5 +1,5 @@
|
||||
import logWeb3Usage from './log-web3-usage'
|
||||
import logWeb3ShimUsage from './log-web3-shim-usage'
|
||||
import watchAsset from './watch-asset'
|
||||
|
||||
const handlers = [logWeb3Usage, watchAsset]
|
||||
const handlers = [logWeb3ShimUsage, watchAsset]
|
||||
export default handlers
|
||||
|
@ -0,0 +1,49 @@
|
||||
import { MESSAGE_TYPE } from '../../enums'
|
||||
|
||||
/**
|
||||
* This RPC method is called by the inpage provider whenever it detects the
|
||||
* accessing of a non-existent property on our window.web3 shim.
|
||||
* We collect this data to understand which sites are breaking due to the
|
||||
* removal of our window.web3.
|
||||
*/
|
||||
|
||||
const logWeb3ShimUsage = {
|
||||
methodNames: [MESSAGE_TYPE.LOG_WEB3_SHIM_USAGE],
|
||||
implementation: logWeb3ShimUsageHandler,
|
||||
}
|
||||
export default logWeb3ShimUsage
|
||||
|
||||
const recordedWeb3ShimUsage = {}
|
||||
|
||||
/**
|
||||
* @typedef {Object} LogWeb3ShimUsageOptions
|
||||
* @property {Function} sendMetrics - A function that registers a metrics event.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import('json-rpc-engine').JsonRpcRequest<unknown>} req - The JSON-RPC request object.
|
||||
* @param {import('json-rpc-engine').JsonRpcResponse<true>} res - The JSON-RPC response object.
|
||||
* @param {Function} _next - The json-rpc-engine 'next' callback.
|
||||
* @param {Function} end - The json-rpc-engine 'end' callback.
|
||||
* @param {LogWeb3ShimUsageOptions} options
|
||||
*/
|
||||
function logWeb3ShimUsageHandler(req, res, _next, end, { sendMetrics }) {
|
||||
const { origin } = req
|
||||
if (!recordedWeb3ShimUsage[origin]) {
|
||||
recordedWeb3ShimUsage[origin] = true
|
||||
|
||||
sendMetrics({
|
||||
event: `Website Accessed window.web3 Shim`,
|
||||
category: 'inpage_provider',
|
||||
eventContext: {
|
||||
referrer: {
|
||||
url: origin,
|
||||
},
|
||||
},
|
||||
excludeMetaMetricsId: true,
|
||||
})
|
||||
}
|
||||
|
||||
res.result = true
|
||||
return end()
|
||||
}
|
@ -1,63 +0,0 @@
|
||||
import { MESSAGE_TYPE } from '../../enums'
|
||||
|
||||
/**
|
||||
* This RPC method is called by our inpage web3 proxy whenever window.web3 is
|
||||
* accessed. We're collecting data on window.web3 usage so that we can warn
|
||||
* website maintainers, and possibly our users, before we remove window.web3
|
||||
* by November 16, 2020.
|
||||
*/
|
||||
|
||||
const logWeb3Usage = {
|
||||
methodNames: [MESSAGE_TYPE.LOG_WEB3_USAGE],
|
||||
implementation: logWeb3UsageHandler,
|
||||
}
|
||||
export default logWeb3Usage
|
||||
|
||||
const recordedWeb3Usage = {}
|
||||
|
||||
/**
|
||||
* @typedef {Object} LogWeb3UsageOptions
|
||||
* @property {string} origin - The origin of the request.
|
||||
* @property {Function} sendMetrics - A function that registers a metrics event.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef {Object} LogWeb3UsageParam
|
||||
* @property {string} action - The action taken (get or set).
|
||||
* @property {string} name - The window.web3 property name subject to the action.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @param {import('json-rpc-engine').JsonRpcRequest<[LogWeb3UsageParam]>} req - The JSON-RPC request object.
|
||||
* @param {import('json-rpc-engine').JsonRpcResponse<true>} res - The JSON-RPC response object.
|
||||
* @param {Function} _next - The json-rpc-engine 'next' callback.
|
||||
* @param {Function} end - The json-rpc-engine 'end' callback.
|
||||
* @param {LogWeb3UsageOptions} options
|
||||
*/
|
||||
function logWeb3UsageHandler(req, res, _next, end, { origin, sendMetrics }) {
|
||||
const { action, path } = req.params[0]
|
||||
|
||||
if (!recordedWeb3Usage[origin]) {
|
||||
recordedWeb3Usage[origin] = {}
|
||||
}
|
||||
if (!recordedWeb3Usage[origin][path]) {
|
||||
recordedWeb3Usage[origin][path] = true
|
||||
|
||||
sendMetrics(
|
||||
{
|
||||
event: `Website Used window.web3`,
|
||||
category: 'inpage_provider',
|
||||
properties: { action, web3Path: path },
|
||||
referrer: {
|
||||
url: origin,
|
||||
},
|
||||
},
|
||||
{
|
||||
excludeMetaMetricsId: true,
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
res.result = true
|
||||
return end()
|
||||
}
|
@ -1,251 +0,0 @@
|
||||
/*global Web3*/
|
||||
|
||||
// TODO:deprecate:2020
|
||||
// Delete this file
|
||||
|
||||
import web3Entitites from './web3-entities.json'
|
||||
import 'web3/dist/web3.min'
|
||||
|
||||
const shouldLogUsage = ![
|
||||
'docs.metamask.io',
|
||||
'metamask.github.io',
|
||||
'metamask.io',
|
||||
].includes(window.location.hostname)
|
||||
|
||||
/**
|
||||
* To understand how we arrived at this implementation, please see:
|
||||
* https://github.com/ethereum/web3.js/blob/0.20.7/DOCUMENTATION.md
|
||||
*/
|
||||
export default function setupWeb3(log) {
|
||||
// export web3 as a global, checking for usage
|
||||
let reloadInProgress = false
|
||||
let lastTimeUsed
|
||||
let lastSeenNetwork
|
||||
let hasBeenWarned = false
|
||||
|
||||
const web3 = new Web3(window.ethereum)
|
||||
web3.setProvider = function () {
|
||||
log.debug('MetaMask - overrode web3.setProvider')
|
||||
}
|
||||
Object.defineProperty(web3, '__isMetaMaskShim__', {
|
||||
value: true,
|
||||
enumerable: false,
|
||||
configurable: false,
|
||||
writable: false,
|
||||
})
|
||||
|
||||
Object.defineProperty(window.ethereum, '_web3Ref', {
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: web3.eth,
|
||||
})
|
||||
|
||||
// Setup logging of nested property usage
|
||||
if (shouldLogUsage) {
|
||||
// web3 namespaces with common and uncommon dapp actions
|
||||
const includedTopKeys = [
|
||||
'eth',
|
||||
'db',
|
||||
'shh',
|
||||
'net',
|
||||
'personal',
|
||||
'bzz',
|
||||
'version',
|
||||
]
|
||||
|
||||
// For each top-level property, create appropriate Proxy traps for all of
|
||||
// their properties
|
||||
includedTopKeys.forEach((topKey) => {
|
||||
const applyTrapKeys = new Map()
|
||||
const getTrapKeys = new Map()
|
||||
|
||||
Object.keys(web3[topKey]).forEach((key) => {
|
||||
const path = `web3.${topKey}.${key}`
|
||||
|
||||
if (web3Entitites[path]) {
|
||||
if (web3Entitites[path] === 'function') {
|
||||
applyTrapKeys.set(key, path)
|
||||
} else {
|
||||
getTrapKeys.set(key, path)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Create apply traps for function properties
|
||||
for (const [key, path] of applyTrapKeys) {
|
||||
web3[topKey][key] = new Proxy(web3[topKey][key], {
|
||||
apply: (...params) => {
|
||||
try {
|
||||
window.ethereum.request({
|
||||
method: 'metamask_logInjectedWeb3Usage',
|
||||
params: [
|
||||
{
|
||||
action: 'apply',
|
||||
path,
|
||||
},
|
||||
],
|
||||
})
|
||||
} catch (error) {
|
||||
log.debug('Failed to log web3 usage.', error)
|
||||
}
|
||||
|
||||
// Call function normally
|
||||
return Reflect.apply(...params)
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Create get trap for non-function properties
|
||||
web3[topKey] = new Proxy(web3[topKey], {
|
||||
get: (web3Prop, key, ...params) => {
|
||||
const name = stringifyKey(key)
|
||||
|
||||
if (getTrapKeys.has(name)) {
|
||||
try {
|
||||
window.ethereum.request({
|
||||
method: 'metamask_logInjectedWeb3Usage',
|
||||
params: [
|
||||
{
|
||||
action: 'get',
|
||||
path: getTrapKeys.get(name),
|
||||
},
|
||||
],
|
||||
})
|
||||
} catch (error) {
|
||||
log.debug('Failed to log web3 usage.', error)
|
||||
}
|
||||
}
|
||||
|
||||
// return value normally
|
||||
return Reflect.get(web3Prop, key, ...params)
|
||||
},
|
||||
})
|
||||
})
|
||||
|
||||
const topLevelFunctions = [
|
||||
'isConnected',
|
||||
'setProvider',
|
||||
'reset',
|
||||
'sha3',
|
||||
'toHex',
|
||||
'toAscii',
|
||||
'fromAscii',
|
||||
'toDecimal',
|
||||
'fromDecimal',
|
||||
'fromWei',
|
||||
'toWei',
|
||||
'toBigNumber',
|
||||
'isAddress',
|
||||
]
|
||||
|
||||
// apply-trap top-level functions
|
||||
topLevelFunctions.forEach((key) => {
|
||||
// This type check is probably redundant, but we've been burned before.
|
||||
if (typeof web3[key] === 'function') {
|
||||
web3[key] = new Proxy(web3[key], {
|
||||
apply: (...params) => {
|
||||
try {
|
||||
window.ethereum.request({
|
||||
method: 'metamask_logInjectedWeb3Usage',
|
||||
params: [
|
||||
{
|
||||
action: 'apply',
|
||||
path: `web3.${key}`,
|
||||
},
|
||||
],
|
||||
})
|
||||
} catch (error) {
|
||||
log.debug('Failed to log web3 usage.', error)
|
||||
}
|
||||
|
||||
// Call function normally
|
||||
return Reflect.apply(...params)
|
||||
},
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
const web3Proxy = new Proxy(web3, {
|
||||
get: (...params) => {
|
||||
// get the time of use
|
||||
lastTimeUsed = Date.now()
|
||||
|
||||
// show warning once on web3 access
|
||||
if (!hasBeenWarned) {
|
||||
console.warn(
|
||||
`MetaMask: We will stop injecting web3 in Q4 2020.\nPlease see this article for more information: https://medium.com/metamask/no-longer-injecting-web3-js-4a899ad6e59e`,
|
||||
)
|
||||
hasBeenWarned = true
|
||||
}
|
||||
|
||||
// return value normally
|
||||
return Reflect.get(...params)
|
||||
},
|
||||
})
|
||||
|
||||
Object.defineProperty(window, 'web3', {
|
||||
enumerable: false,
|
||||
writable: true,
|
||||
configurable: true,
|
||||
value: web3Proxy,
|
||||
})
|
||||
log.debug('MetaMask - injected web3')
|
||||
|
||||
window.ethereum._publicConfigStore.subscribe((state) => {
|
||||
// if the auto refresh on network change is false do not
|
||||
// do anything
|
||||
if (!window.ethereum.autoRefreshOnNetworkChange) {
|
||||
return
|
||||
}
|
||||
|
||||
// if reload in progress, no need to check reload logic
|
||||
if (reloadInProgress) {
|
||||
return
|
||||
}
|
||||
|
||||
const currentNetwork = state.networkVersion
|
||||
|
||||
// set the initial network
|
||||
if (!lastSeenNetwork) {
|
||||
lastSeenNetwork = currentNetwork
|
||||
return
|
||||
}
|
||||
|
||||
// skip reload logic if web3 not used
|
||||
if (!lastTimeUsed) {
|
||||
return
|
||||
}
|
||||
|
||||
// if network did not change, exit
|
||||
if (currentNetwork === lastSeenNetwork) {
|
||||
return
|
||||
}
|
||||
|
||||
// initiate page reload
|
||||
reloadInProgress = true
|
||||
const timeSinceUse = Date.now() - lastTimeUsed
|
||||
// if web3 was recently used then delay the reloading of the page
|
||||
if (timeSinceUse > 500) {
|
||||
triggerReset()
|
||||
} else {
|
||||
setTimeout(triggerReset, 500)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// reload the page
|
||||
function triggerReset() {
|
||||
window.location.reload()
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a "stringified" key. Keys that are already strings are returned
|
||||
* unchanged, and any non-string values are returned as "typeof <type>".
|
||||
*
|
||||
* @param {any} key - The key to stringify
|
||||
*/
|
||||
function stringifyKey(key) {
|
||||
return typeof key === 'string' ? key : `typeof ${typeof key}`
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
{
|
||||
"web3.bzz.blockNetworkRead": "function",
|
||||
"web3.bzz.download": "function",
|
||||
"web3.bzz.get": "function",
|
||||
"web3.bzz.getHive": "function",
|
||||
"web3.bzz.getInfo": "function",
|
||||
"web3.bzz.hive": "TRAP",
|
||||
"web3.bzz.info": "TRAP",
|
||||
"web3.bzz.modify": "function",
|
||||
"web3.bzz.put": "function",
|
||||
"web3.bzz.retrieve": "function",
|
||||
"web3.bzz.store": "function",
|
||||
"web3.bzz.swapEnabled": "function",
|
||||
"web3.bzz.syncEnabled": "function",
|
||||
"web3.bzz.upload": "function",
|
||||
"web3.db.getHex": "function",
|
||||
"web3.db.getString": "function",
|
||||
"web3.db.putHex": "function",
|
||||
"web3.db.putString": "function",
|
||||
"web3.eth.accounts": "object",
|
||||
"web3.eth.blockNumber": "TRAP",
|
||||
"web3.eth.call": "function",
|
||||
"web3.eth.coinbase": "object",
|
||||
"web3.eth.compile": "object",
|
||||
"web3.eth.estimateGas": "function",
|
||||
"web3.eth.gasPrice": "TRAP",
|
||||
"web3.eth.getAccounts": "function",
|
||||
"web3.eth.getBalance": "function",
|
||||
"web3.eth.getBlock": "function",
|
||||
"web3.eth.getBlockNumber": "function",
|
||||
"web3.eth.getBlockTransactionCount": "function",
|
||||
"web3.eth.getBlockUncleCount": "function",
|
||||
"web3.eth.getCode": "function",
|
||||
"web3.eth.getCoinbase": "function",
|
||||
"web3.eth.getCompilers": "function",
|
||||
"web3.eth.getGasPrice": "function",
|
||||
"web3.eth.getHashrate": "function",
|
||||
"web3.eth.getMining": "function",
|
||||
"web3.eth.getProtocolVersion": "function",
|
||||
"web3.eth.getStorageAt": "function",
|
||||
"web3.eth.getSyncing": "function",
|
||||
"web3.eth.getTransaction": "function",
|
||||
"web3.eth.getTransactionCount": "function",
|
||||
"web3.eth.getTransactionFromBlock": "function",
|
||||
"web3.eth.getTransactionReceipt": "function",
|
||||
"web3.eth.getUncle": "function",
|
||||
"web3.eth.getWork": "function",
|
||||
"web3.eth.hashrate": "TRAP",
|
||||
"web3.eth.iban": "function",
|
||||
"web3.eth.mining": "TRAP",
|
||||
"web3.eth.protocolVersion": "TRAP",
|
||||
"web3.eth.sendIBANTransaction": "function",
|
||||
"web3.eth.sendRawTransaction": "function",
|
||||
"web3.eth.sendTransaction": "function",
|
||||
"web3.eth.sign": "function",
|
||||
"web3.eth.signTransaction": "function",
|
||||
"web3.eth.submitWork": "function",
|
||||
"web3.eth.syncing": "TRAP",
|
||||
"web3.net.getListening": "function",
|
||||
"web3.net.getPeerCount": "function",
|
||||
"web3.net.listening": "TRAP",
|
||||
"web3.net.peerCount": "TRAP",
|
||||
"web3.personal.ecRecover": "function",
|
||||
"web3.personal.getListAccounts": "function",
|
||||
"web3.personal.importRawKey": "function",
|
||||
"web3.personal.listAccounts": "TRAP",
|
||||
"web3.personal.lockAccount": "function",
|
||||
"web3.personal.newAccount": "function",
|
||||
"web3.personal.sendTransaction": "function",
|
||||
"web3.personal.sign": "function",
|
||||
"web3.personal.unlockAccount": "function",
|
||||
"web3.providers.HttpProvider": "function",
|
||||
"web3.providers.IpcProvider": "function",
|
||||
"web3.shh.addPrivateKey": "function",
|
||||
"web3.shh.addSymKey": "function",
|
||||
"web3.shh.deleteKeyPair": "function",
|
||||
"web3.shh.deleteSymKey": "function",
|
||||
"web3.shh.generateSymKeyFromPassword": "function",
|
||||
"web3.shh.getPrivateKey": "function",
|
||||
"web3.shh.getPublicKey": "function",
|
||||
"web3.shh.getSymKey": "function",
|
||||
"web3.shh.hasKeyPair": "function",
|
||||
"web3.shh.hasSymKey": "function",
|
||||
"web3.shh.info": "function",
|
||||
"web3.shh.markTrustedPeer": "function",
|
||||
"web3.shh.newKeyPair": "function",
|
||||
"web3.shh.newSymKey": "function",
|
||||
"web3.shh.post": "function",
|
||||
"web3.shh.setMaxMessageSize": "function",
|
||||
"web3.shh.setMinPoW": "function",
|
||||
"web3.shh.version": "function",
|
||||
"web3.version.api": "string",
|
||||
"web3.version.ethereum": "TRAP",
|
||||
"web3.version.getEthereum": "function",
|
||||
"web3.version.getNetwork": "function",
|
||||
"web3.version.getNode": "function",
|
||||
"web3.version.getWhisper": "function",
|
||||
"web3.version.network": "string",
|
||||
"web3.version.node": "TRAP",
|
||||
"web3.version.whisper": "TRAP"
|
||||
}
|
Loading…
Reference in New Issue
Block a user