{"version":3,"file":"utils.mjs","sourceRoot":"","sources":["../../src/common/utils.ts"],"names":[],"mappings":"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","sourcesContent":["import type { RequestArguments } from '@metamask/providers';\nimport { rpcErrors } from '@metamask/rpc-errors';\nimport { getJsonSizeUnsafe } from '@metamask/snaps-utils';\nimport type { Json } from '@metamask/utils';\nimport { assert, getSafeJson, isObject } from '@metamask/utils';\n\nimport { log } from '../logging';\n\n// 64 MB - we chose this number because it is the size limit for postMessage\n// between the extension and the dapp enforced by Chrome.\nconst MAX_RESPONSE_JSON_SIZE = 64_000_000;\n\n/**\n * Make proxy for Promise and handle the teardown process properly.\n * If the teardown is called in the meanwhile, Promise result will not be\n * exposed to the snap anymore and warning will be logged to the console.\n *\n * @param originalPromise - Original promise.\n * @param teardownRef - Reference containing teardown count.\n * @param teardownRef.lastTeardown - Number of the last teardown.\n * @returns New proxy promise.\n */\nexport async function withTeardown<Type>(\n  originalPromise: Promise<Type>,\n  teardownRef: { lastTeardown: number },\n): Promise<Type> {\n  const myTeardown = teardownRef.lastTeardown;\n  return new Promise<Type>((resolve, reject) => {\n    originalPromise\n      .then((value) => {\n        if (teardownRef.lastTeardown === myTeardown) {\n          resolve(value);\n        } else {\n          log(\n            'Late promise received after Snap finished execution. Promise will be dropped.',\n          );\n        }\n      })\n      .catch((reason) => {\n        if (teardownRef.lastTeardown === myTeardown) {\n          reject(reason);\n        } else {\n          log(\n            'Late promise received after Snap finished execution. Promise will be dropped.',\n          );\n        }\n      });\n  });\n}\n\n// We're blocking these RPC methods for v1, will revisit later.\nexport const BLOCKED_RPC_METHODS = Object.freeze([\n  'wallet_requestPermissions',\n  'wallet_revokePermissions',\n  // We disallow all of these confirmations for now, since the screens are not ready for Snaps.\n  'eth_sendTransaction',\n  'eth_decrypt',\n  'eth_getEncryptionPublicKey',\n  'metamask_sendDomainMetadata',\n  'wallet_addEthereumChain',\n  'wallet_watchAsset',\n  'wallet_registerOnboarding',\n  'wallet_scanQRCode',\n]);\n\nexport const MULTICHAIN_API_METHODS = Object.freeze([\n  'wallet_createSession',\n  'wallet_invokeMethod',\n  'wallet_getSession',\n  'wallet_revokeSession',\n]);\n\n// Subset of BLOCKED_RPC_METHODS\nexport const BLOCKED_MULTICHAIN_RPC_METHODS = Object.freeze([\n  'wallet_requestPermissions',\n  'wallet_revokePermissions',\n  'eth_decrypt',\n  'eth_getEncryptionPublicKey',\n  'metamask_sendDomainMetadata',\n  'wallet_addEthereumChain',\n  'wallet_watchAsset',\n  'wallet_registerOnboarding',\n  'wallet_scanQRCode',\n]);\n\n/**\n * Check whether a validated request should be routed to the multichain API.\n *\n * @param args - The request arguments.\n * @returns True if the request is a multichain request, otherwise false.\n */\nexport function isMultichainRequest(args: RequestArguments) {\n  return MULTICHAIN_API_METHODS.includes(args.method);\n}\n\n/**\n * Asserts the validity of request arguments for a multichain outbound request using the `snap.request` API.\n *\n * @param args - The arguments to validate.\n */\nexport function assertMultichainOutboundRequest(args: RequestArguments) {\n  if (args.method !== 'wallet_invokeMethod') {\n    return;\n  }\n\n  // For `wallet_invokeMethod`, we need to inspect the parameters to determine\n  // if the Snap is requesting a blocked RPC method.\n  assert(\n    isObject(args.params) &&\n      isObject(args.params.request) &&\n      typeof args.params.request.method === 'string',\n    rpcErrors.invalidParams(),\n  );\n\n  const innerMethod = args.params.request.method;\n\n  assert(\n    !String.prototype.startsWith.call(innerMethod, 'snap_'),\n    rpcErrors.methodNotFound({\n      data: {\n        method: innerMethod,\n      },\n    }),\n  );\n  assert(\n    !BLOCKED_MULTICHAIN_RPC_METHODS.includes(innerMethod),\n    rpcErrors.methodNotFound({\n      data: {\n        method: innerMethod,\n      },\n    }),\n  );\n}\n\n/**\n * Asserts the validity of request arguments for a snap outbound request using the `snap.request` API.\n *\n * @param args - The arguments to validate.\n */\nexport function assertSnapOutboundRequest(args: RequestArguments) {\n  // Disallow any non `wallet_` or `snap_` methods for separation of concerns.\n  assert(\n    String.prototype.startsWith.call(args.method, 'wallet_') ||\n      String.prototype.startsWith.call(args.method, 'snap_'),\n    'The global Snap API only allows RPC methods starting with `wallet_*` and `snap_*`.',\n    rpcErrors.methodNotSupported,\n  );\n  assert(\n    !BLOCKED_RPC_METHODS.includes(args.method),\n    rpcErrors.methodNotFound({\n      data: {\n        method: args.method,\n      },\n    }),\n  );\n}\n\n/**\n * Asserts the validity of request arguments for an ethereum outbound request using the `ethereum.request` API.\n *\n * @param args - The arguments to validate.\n */\nexport function assertEthereumOutboundRequest(args: RequestArguments) {\n  // Disallow snaps methods for separation of concerns.\n  assert(\n    !String.prototype.startsWith.call(args.method, 'snap_'),\n    rpcErrors.methodNotFound({\n      data: {\n        method: args.method,\n      },\n    }),\n  );\n  assert(\n    !BLOCKED_RPC_METHODS.includes(args.method),\n    rpcErrors.methodNotFound({\n      data: {\n        method: args.method,\n      },\n    }),\n  );\n}\n\n/**\n * Gets a sanitized value to be used for passing to the underlying MetaMask provider.\n *\n * @param value - An unsanitized value from a snap.\n * @returns A sanitized value ready to be passed to a MetaMask provider.\n */\nexport function sanitizeRequestArguments(value: unknown): RequestArguments {\n  // Before passing to getSafeJson we run the value through JSON serialization.\n  // This lets request arguments contain undefined which is normally disallowed.\n  const json = JSON.parse(JSON.stringify(value));\n  return getSafeJson(json) as RequestArguments;\n}\n\n/**\n * Check if the input is a valid response.\n *\n * @param response - The response.\n * @returns True if the response is valid, otherwise false.\n */\nexport function isValidResponse(response: Record<string, Json>) {\n  if (!isObject(response)) {\n    return false;\n  }\n\n  // We know that the response is valid JSON already and we don't\n  // need the size to be exact.\n  const size = getJsonSizeUnsafe(response);\n  return size < MAX_RESPONSE_JSON_SIZE;\n}\n"]}