mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-23 09:52:26 +01:00
Add RPC method handler hook selection (#12664)
Adds a property, `hookNames`, to each RPC method handler export in `app/scripts/lib/rpc-method-middleware` and a function, `selectHooks`, to select from them. `createMethodMiddleware` receives a giant `opts` object that includes a bunch of different methods from `MetaMaskController` and its subcontrollers. Each method implementation only requires a subset of these methods to do its work. Because they need some kind of name, we call these methods "hooks". With this change, whenever an RPC method is called, `selectHooks` will be called to ensure that each method only receives the hooks that it needs in order to do its job. This implementation is based on [work in `snaps-skunkworks`](https://github.com/MetaMask/snaps-skunkworks/blob/a3e1248/packages/rpc-methods/src/utils.ts#L17-L34) that will be merged in the near future.
This commit is contained in:
parent
d4c71b8683
commit
05fae3fa1e
@ -4,7 +4,7 @@ import handlers from './handlers';
|
|||||||
|
|
||||||
const handlerMap = handlers.reduce((map, handler) => {
|
const handlerMap = handlers.reduce((map, handler) => {
|
||||||
for (const methodName of handler.methodNames) {
|
for (const methodName of handler.methodNames) {
|
||||||
map.set(methodName, handler.implementation);
|
map.set(methodName, handler);
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
}, new Map());
|
}, new Map());
|
||||||
@ -23,7 +23,6 @@ const handlerMap = handlers.reduce((map, handler) => {
|
|||||||
* Eventually, we'll want to extract this middleware into its own package.
|
* Eventually, we'll want to extract this middleware into its own package.
|
||||||
*
|
*
|
||||||
* @param {Object} opts - The middleware options
|
* @param {Object} opts - The middleware options
|
||||||
* @param {Function} opts.sendMetrics - A function for sending a metrics event
|
|
||||||
* @returns {(req: Object, res: Object, next: Function, end: Function) => void}
|
* @returns {(req: Object, res: Object, next: Function, end: Function) => void}
|
||||||
*/
|
*/
|
||||||
export default function createMethodMiddleware(opts) {
|
export default function createMethodMiddleware(opts) {
|
||||||
@ -33,9 +32,32 @@ export default function createMethodMiddleware(opts) {
|
|||||||
return end(ethErrors.rpc.methodNotSupported());
|
return end(ethErrors.rpc.methodNotSupported());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (handlerMap.has(req.method)) {
|
const handler = handlerMap.get(req.method);
|
||||||
return handlerMap.get(req.method)(req, res, next, end, opts);
|
if (handler) {
|
||||||
|
const { implementation, hookNames } = handler;
|
||||||
|
return implementation(req, res, next, end, selectHooks(opts, hookNames));
|
||||||
}
|
}
|
||||||
|
|
||||||
return next();
|
return next();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the subset of the specified `hooks` that are included in the
|
||||||
|
* `hookNames` object. This is a Principle of Least Authority (POLA) measure
|
||||||
|
* to ensure that each RPC method implementation only has access to the
|
||||||
|
* API "hooks" it needs to do its job.
|
||||||
|
*
|
||||||
|
* @param {Record<string, unknown>} hooks - The hooks to select from.
|
||||||
|
* @param {Record<string, true>} hookNames - The names of the hooks to select.
|
||||||
|
* @returns {Record<string, unknown> | undefined} The selected hooks.
|
||||||
|
*/
|
||||||
|
function selectHooks(hooks, hookNames) {
|
||||||
|
if (hookNames) {
|
||||||
|
return Object.keys(hookNames).reduce((hookSubset, hookName) => {
|
||||||
|
hookSubset[hookName] = hooks[hookName];
|
||||||
|
return hookSubset;
|
||||||
|
}, {});
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
@ -12,6 +12,14 @@ import { CHAIN_ID_TO_NETWORK_ID_MAP } from '../../../../../shared/constants/netw
|
|||||||
const addEthereumChain = {
|
const addEthereumChain = {
|
||||||
methodNames: [MESSAGE_TYPE.ADD_ETHEREUM_CHAIN],
|
methodNames: [MESSAGE_TYPE.ADD_ETHEREUM_CHAIN],
|
||||||
implementation: addEthereumChainHandler,
|
implementation: addEthereumChainHandler,
|
||||||
|
hookNames: {
|
||||||
|
addCustomRpc: true,
|
||||||
|
getCurrentChainId: true,
|
||||||
|
findCustomRpcBy: true,
|
||||||
|
updateRpcTarget: true,
|
||||||
|
requestUserApproval: true,
|
||||||
|
sendMetrics: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default addEthereumChain;
|
export default addEthereumChain;
|
||||||
|
|
||||||
|
@ -9,6 +9,9 @@ import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
|
|||||||
const getProviderState = {
|
const getProviderState = {
|
||||||
methodNames: [MESSAGE_TYPE.GET_PROVIDER_STATE],
|
methodNames: [MESSAGE_TYPE.GET_PROVIDER_STATE],
|
||||||
implementation: getProviderStateHandler,
|
implementation: getProviderStateHandler,
|
||||||
|
hookNames: {
|
||||||
|
getProviderState: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default getProviderState;
|
export default getProviderState;
|
||||||
|
|
||||||
|
@ -10,6 +10,11 @@ import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
|
|||||||
const logWeb3ShimUsage = {
|
const logWeb3ShimUsage = {
|
||||||
methodNames: [MESSAGE_TYPE.LOG_WEB3_SHIM_USAGE],
|
methodNames: [MESSAGE_TYPE.LOG_WEB3_SHIM_USAGE],
|
||||||
implementation: logWeb3ShimUsageHandler,
|
implementation: logWeb3ShimUsageHandler,
|
||||||
|
hookNames: {
|
||||||
|
sendMetrics: true,
|
||||||
|
getWeb3ShimUsageState: true,
|
||||||
|
setWeb3ShimUsageRecorded: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default logWeb3ShimUsage;
|
export default logWeb3ShimUsage;
|
||||||
|
|
||||||
|
@ -15,6 +15,13 @@ import {
|
|||||||
const switchEthereumChain = {
|
const switchEthereumChain = {
|
||||||
methodNames: [MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN],
|
methodNames: [MESSAGE_TYPE.SWITCH_ETHEREUM_CHAIN],
|
||||||
implementation: switchEthereumChainHandler,
|
implementation: switchEthereumChainHandler,
|
||||||
|
hookNames: {
|
||||||
|
getCurrentChainId: true,
|
||||||
|
findCustomRpcBy: true,
|
||||||
|
setProviderType: true,
|
||||||
|
updateRpcTarget: true,
|
||||||
|
requestUserApproval: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default switchEthereumChain;
|
export default switchEthereumChain;
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@ import { MESSAGE_TYPE } from '../../../../../shared/constants/app';
|
|||||||
const watchAsset = {
|
const watchAsset = {
|
||||||
methodNames: [MESSAGE_TYPE.WATCH_ASSET, MESSAGE_TYPE.WATCH_ASSET_LEGACY],
|
methodNames: [MESSAGE_TYPE.WATCH_ASSET, MESSAGE_TYPE.WATCH_ASSET_LEGACY],
|
||||||
implementation: watchAssetHandler,
|
implementation: watchAssetHandler,
|
||||||
|
hookNames: {
|
||||||
|
handleWatchAssetRequest: true,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
export default watchAsset;
|
export default watchAsset;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user