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>
feature/default_network_editable
Erik Marks 4 years ago committed by GitHub
parent b1b78ff5a5
commit 6426816411
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 11
      app/scripts/lib/rpc-method-middleware/handlers/log-web3-usage.js
  2. 143
      app/scripts/lib/setupWeb3.js
  3. 101
      app/scripts/lib/web3-entities.json

@ -35,18 +35,19 @@ const recordedWeb3Usage = {}
* @param {LogWeb3UsageOptions} options
*/
function logWeb3UsageHandler(req, res, _next, end, { origin, sendMetrics }) {
const { action, name } = req.params[0]
const { action, path } = req.params[0]
if (!recordedWeb3Usage[origin]) {
recordedWeb3Usage[origin] = {}
}
if (!recordedWeb3Usage[origin][name]) {
recordedWeb3Usage[origin][name] = true
if (!recordedWeb3Usage[origin][path]) {
recordedWeb3Usage[origin][path] = true
sendMetrics({
event: `Website Accessed window.web3`,
matomo: true,
event: `Website Used window.web3`,
category: 'inpage_provider',
properties: { action, web3Property: name },
properties: { action, web3Path: path },
eventContext: {
referrer: {
url: origin,

@ -3,6 +3,7 @@
// TODO:deprecate:2020
// Delete this file
import web3Entitites from './web3-entities.json'
import 'web3/dist/web3.min'
const shouldLogUsage = ![
@ -11,6 +12,10 @@ const shouldLogUsage = ![
'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
@ -31,8 +36,122 @@ export default function setupWeb3(log) {
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, {
get: (_web3, key) => {
get: (...params) => {
// get the time of use
lastTimeUsed = Date.now()
@ -44,28 +163,8 @@ export default function setupWeb3(log) {
hasBeenWarned = true
}
if (shouldLogUsage) {
const name = stringifyKey(key)
window.ethereum.request({
method: 'metamask_logInjectedWeb3Usage',
params: [{ action: 'get', name }],
})
}
// return value normally
return _web3[key]
},
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
return Reflect.get(...params)
},
})

@ -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…
Cancel
Save