mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Log web3 usage for functions and nested properties only (#9797)
* Log web3 usage for functions and nested properties only * Change web3 metrics source to legacy * Update web3 metrics properties and event name Co-authored-by: Mark Stacey <markjstacey@gmail.com>
This commit is contained in:
parent
b1b78ff5a5
commit
6426816411
@ -35,18 +35,19 @@ const recordedWeb3Usage = {}
|
|||||||
* @param {LogWeb3UsageOptions} options
|
* @param {LogWeb3UsageOptions} options
|
||||||
*/
|
*/
|
||||||
function logWeb3UsageHandler(req, res, _next, end, { origin, sendMetrics }) {
|
function logWeb3UsageHandler(req, res, _next, end, { origin, sendMetrics }) {
|
||||||
const { action, name } = req.params[0]
|
const { action, path } = req.params[0]
|
||||||
|
|
||||||
if (!recordedWeb3Usage[origin]) {
|
if (!recordedWeb3Usage[origin]) {
|
||||||
recordedWeb3Usage[origin] = {}
|
recordedWeb3Usage[origin] = {}
|
||||||
}
|
}
|
||||||
if (!recordedWeb3Usage[origin][name]) {
|
if (!recordedWeb3Usage[origin][path]) {
|
||||||
recordedWeb3Usage[origin][name] = true
|
recordedWeb3Usage[origin][path] = true
|
||||||
|
|
||||||
sendMetrics({
|
sendMetrics({
|
||||||
event: `Website Accessed window.web3`,
|
matomo: true,
|
||||||
|
event: `Website Used window.web3`,
|
||||||
category: 'inpage_provider',
|
category: 'inpage_provider',
|
||||||
properties: { action, web3Property: name },
|
properties: { action, web3Path: path },
|
||||||
eventContext: {
|
eventContext: {
|
||||||
referrer: {
|
referrer: {
|
||||||
url: origin,
|
url: origin,
|
||||||
|
@ -3,6 +3,7 @@
|
|||||||
// TODO:deprecate:2020
|
// TODO:deprecate:2020
|
||||||
// Delete this file
|
// Delete this file
|
||||||
|
|
||||||
|
import web3Entitites from './web3-entities.json'
|
||||||
import 'web3/dist/web3.min'
|
import 'web3/dist/web3.min'
|
||||||
|
|
||||||
const shouldLogUsage = ![
|
const shouldLogUsage = ![
|
||||||
@ -11,6 +12,10 @@ const shouldLogUsage = ![
|
|||||||
'metamask.io',
|
'metamask.io',
|
||||||
].includes(window.location.hostname)
|
].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 default function setupWeb3(log) {
|
||||||
// export web3 as a global, checking for usage
|
// export web3 as a global, checking for usage
|
||||||
let reloadInProgress = false
|
let reloadInProgress = false
|
||||||
@ -31,8 +36,122 @@ export default function setupWeb3(log) {
|
|||||||
value: web3.eth,
|
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) => {
|
||||||
|
window.ethereum.request({
|
||||||
|
method: 'metamask_logInjectedWeb3Usage',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
action: 'apply',
|
||||||
|
path,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// 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)) {
|
||||||
|
window.ethereum.request({
|
||||||
|
method: 'metamask_logInjectedWeb3Usage',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
action: 'get',
|
||||||
|
path: getTrapKeys.get(name),
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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) => {
|
||||||
|
window.ethereum.request({
|
||||||
|
method: 'metamask_logInjectedWeb3Usage',
|
||||||
|
params: [
|
||||||
|
{
|
||||||
|
action: 'apply',
|
||||||
|
path: `web3.${key}`,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
})
|
||||||
|
|
||||||
|
// Call function normally
|
||||||
|
return Reflect.apply(...params)
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
const web3Proxy = new Proxy(web3, {
|
const web3Proxy = new Proxy(web3, {
|
||||||
get: (_web3, key) => {
|
get: (...params) => {
|
||||||
// get the time of use
|
// get the time of use
|
||||||
lastTimeUsed = Date.now()
|
lastTimeUsed = Date.now()
|
||||||
|
|
||||||
@ -44,28 +163,8 @@ export default function setupWeb3(log) {
|
|||||||
hasBeenWarned = true
|
hasBeenWarned = true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (shouldLogUsage) {
|
|
||||||
const name = stringifyKey(key)
|
|
||||||
window.ethereum.request({
|
|
||||||
method: 'metamask_logInjectedWeb3Usage',
|
|
||||||
params: [{ action: 'get', name }],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// return value normally
|
// return value normally
|
||||||
return _web3[key]
|
return Reflect.get(...params)
|
||||||
},
|
|
||||||
set: (_web3, key, value) => {
|
|
||||||
const name = stringifyKey(key)
|
|
||||||
if (shouldLogUsage) {
|
|
||||||
window.ethereum.request({
|
|
||||||
method: 'metamask_logInjectedWeb3Usage',
|
|
||||||
params: [{ action: 'set', name }],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
// set value normally
|
|
||||||
_web3[key] = value
|
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
|
101
app/scripts/lib/web3-entities.json
Normal file
101
app/scripts/lib/web3-entities.json
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"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…
x
Reference in New Issue
Block a user