@metamask/snaps-controllers 9.9.0 → 9.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/CHANGELOG.md +9 -1
  2. package/dist/cronjob/CronjobController.cjs +34 -21
  3. package/dist/cronjob/CronjobController.cjs.map +1 -1
  4. package/dist/cronjob/CronjobController.mjs +34 -21
  5. package/dist/cronjob/CronjobController.mjs.map +1 -1
  6. package/dist/insights/SnapInsightsController.cjs +144 -194
  7. package/dist/insights/SnapInsightsController.cjs.map +1 -1
  8. package/dist/insights/SnapInsightsController.mjs +143 -193
  9. package/dist/insights/SnapInsightsController.mjs.map +1 -1
  10. package/dist/interface/SnapInterfaceController.cjs +65 -90
  11. package/dist/interface/SnapInterfaceController.cjs.map +1 -1
  12. package/dist/interface/SnapInterfaceController.mjs +65 -90
  13. package/dist/interface/SnapInterfaceController.mjs.map +1 -1
  14. package/dist/interface/utils.cjs +6 -2
  15. package/dist/interface/utils.cjs.map +1 -1
  16. package/dist/interface/utils.d.cts.map +1 -1
  17. package/dist/interface/utils.d.mts.map +1 -1
  18. package/dist/interface/utils.mjs +6 -2
  19. package/dist/interface/utils.mjs.map +1 -1
  20. package/dist/services/AbstractExecutionService.cjs +77 -71
  21. package/dist/services/AbstractExecutionService.cjs.map +1 -1
  22. package/dist/services/AbstractExecutionService.mjs +77 -71
  23. package/dist/services/AbstractExecutionService.mjs.map +1 -1
  24. package/dist/services/ProxyPostMessageStream.cjs +26 -19
  25. package/dist/services/ProxyPostMessageStream.cjs.map +1 -1
  26. package/dist/services/ProxyPostMessageStream.mjs +26 -19
  27. package/dist/services/ProxyPostMessageStream.mjs.map +1 -1
  28. package/dist/services/iframe/IframeExecutionService.cjs +4 -2
  29. package/dist/services/iframe/IframeExecutionService.cjs.map +1 -1
  30. package/dist/services/iframe/IframeExecutionService.d.cts.map +1 -1
  31. package/dist/services/iframe/IframeExecutionService.d.mts.map +1 -1
  32. package/dist/services/iframe/IframeExecutionService.mjs +4 -2
  33. package/dist/services/iframe/IframeExecutionService.mjs.map +1 -1
  34. package/dist/services/offscreen/OffscreenExecutionService.cjs +16 -3
  35. package/dist/services/offscreen/OffscreenExecutionService.cjs.map +1 -1
  36. package/dist/services/offscreen/OffscreenExecutionService.mjs +16 -3
  37. package/dist/services/offscreen/OffscreenExecutionService.mjs.map +1 -1
  38. package/dist/services/proxy/ProxyExecutionService.cjs +17 -4
  39. package/dist/services/proxy/ProxyExecutionService.cjs.map +1 -1
  40. package/dist/services/proxy/ProxyExecutionService.mjs +17 -4
  41. package/dist/services/proxy/ProxyExecutionService.mjs.map +1 -1
  42. package/dist/services/webview/WebViewExecutionService.cjs +23 -9
  43. package/dist/services/webview/WebViewExecutionService.cjs.map +1 -1
  44. package/dist/services/webview/WebViewExecutionService.mjs +23 -9
  45. package/dist/services/webview/WebViewExecutionService.mjs.map +1 -1
  46. package/dist/services/webview/WebViewMessageStream.cjs +25 -12
  47. package/dist/services/webview/WebViewMessageStream.cjs.map +1 -1
  48. package/dist/services/webview/WebViewMessageStream.mjs +25 -12
  49. package/dist/services/webview/WebViewMessageStream.mjs.map +1 -1
  50. package/dist/services/webworker/WebWorkerExecutionService.cjs +27 -10
  51. package/dist/services/webworker/WebWorkerExecutionService.cjs.map +1 -1
  52. package/dist/services/webworker/WebWorkerExecutionService.mjs +27 -10
  53. package/dist/services/webworker/WebWorkerExecutionService.mjs.map +1 -1
  54. package/dist/snaps/RequestQueue.cjs +0 -2
  55. package/dist/snaps/RequestQueue.cjs.map +1 -1
  56. package/dist/snaps/RequestQueue.mjs +0 -2
  57. package/dist/snaps/RequestQueue.mjs.map +1 -1
  58. package/dist/snaps/SnapController.cjs +1001 -1141
  59. package/dist/snaps/SnapController.cjs.map +1 -1
  60. package/dist/snaps/SnapController.mjs +1000 -1140
  61. package/dist/snaps/SnapController.mjs.map +1 -1
  62. package/dist/snaps/Timer.cjs +0 -1
  63. package/dist/snaps/Timer.cjs.map +1 -1
  64. package/dist/snaps/Timer.mjs +0 -1
  65. package/dist/snaps/Timer.mjs.map +1 -1
  66. package/dist/snaps/location/http.cjs +7 -11
  67. package/dist/snaps/location/http.cjs.map +1 -1
  68. package/dist/snaps/location/http.mjs +7 -11
  69. package/dist/snaps/location/http.mjs.map +1 -1
  70. package/dist/snaps/location/local.cjs +17 -4
  71. package/dist/snaps/location/local.cjs.map +1 -1
  72. package/dist/snaps/location/local.mjs +17 -4
  73. package/dist/snaps/location/local.mjs.map +1 -1
  74. package/dist/snaps/location/npm.cjs +37 -25
  75. package/dist/snaps/location/npm.cjs.map +1 -1
  76. package/dist/snaps/location/npm.mjs +37 -25
  77. package/dist/snaps/location/npm.mjs.map +1 -1
  78. package/dist/snaps/registry/json.cjs +173 -172
  79. package/dist/snaps/registry/json.cjs.map +1 -1
  80. package/dist/snaps/registry/json.mjs +172 -171
  81. package/dist/snaps/registry/json.mjs.map +1 -1
  82. package/package.json +5 -5
@@ -1 +1 @@
1
- {"version":3,"file":"json.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/json.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { SnapsRegistryDatabase } from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type {\n SnapsRegistry,\n SnapsRegistryInfo,\n SnapsRegistryMetadata,\n SnapsRegistryRequest,\n SnapsRegistryResult,\n} from './registry';\nimport { SnapsRegistryStatus } from './registry';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type JsonSnapsRegistryArgs = {\n messenger: SnapsRegistryMessenger;\n state?: SnapsRegistryState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n};\n\nexport type GetResult = {\n type: `${typeof controllerName}:get`;\n handler: SnapsRegistry['get'];\n};\n\nexport type ResolveVersion = {\n type: `${typeof controllerName}:resolveVersion`;\n handler: SnapsRegistry['resolveVersion'];\n};\n\nexport type GetMetadata = {\n type: `${typeof controllerName}:getMetadata`;\n handler: SnapsRegistry['getMetadata'];\n};\n\nexport type Update = {\n type: `${typeof controllerName}:update`;\n handler: SnapsRegistry['update'];\n};\n\nexport type SnapsRegistryGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryActions =\n | SnapsRegistryGetStateAction\n | GetResult\n | GetMetadata\n | Update\n | ResolveVersion;\n\nexport type SnapsRegistryStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryEvents = SnapsRegistryStateChangeEvent;\n\nexport type SnapsRegistryMessenger = RestrictedControllerMessenger<\n 'SnapsRegistry',\n SnapsRegistryActions,\n SnapsRegistryEvents,\n SnapsRegistryActions['type'],\n SnapsRegistryEvents['type']\n>;\n\nexport type SnapsRegistryState = {\n database: SnapsRegistryDatabase | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapsRegistry';\n\nconst defaultState = {\n database: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class JsonSnapsRegistry extends BaseController<\n typeof controllerName,\n SnapsRegistryState,\n SnapsRegistryMessenger\n> {\n #url: JsonSnapsRegistryUrl;\n\n #publicKey: Hex;\n\n #fetchFunction: typeof fetch;\n\n #recentFetchThreshold: number;\n\n #refetchOnAllowlistMiss: boolean;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n refetchOnAllowlistMiss = true,\n }: JsonSnapsRegistryArgs) {\n super({\n messenger,\n metadata: {\n database: { persist: true, anonymous: false },\n lastUpdated: { persist: true, anonymous: false },\n databaseUnavailable: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:get',\n async (...args) => this.#get(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:getMetadata',\n async (...args) => this.#getMetadata(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:resolveVersion',\n async (...args) => this.#resolveVersion(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:update',\n async () => this.#triggerUpdate(),\n );\n }\n\n #wasRecentlyFetched() {\n return (\n this.state.lastUpdated &&\n Date.now() - this.state.lastUpdated < this.#recentFetchThreshold\n );\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async #triggerUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n return;\n }\n\n try {\n const database = await this.#safeFetch(this.#url.registry);\n\n const signature = await this.#safeFetch(this.#url.signature);\n this.#verifySignature(database, signature);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.#triggerUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapsRegistryInfo,\n refetch = false,\n ): Promise<SnapsRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapsRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n if (version && version.checksum === snapInfo.checksum) {\n return { status: SnapsRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapsRegistryStatus.Unavailable\n : SnapsRegistryStatus.Unverified,\n };\n }\n\n async #get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<string, SnapsRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapsRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async #resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const targetVersion = getTargetVersion(\n Object.keys(versions) as SemVerVersion[],\n versionRange,\n );\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n async #getMetadata(snapId: string): Promise<SnapsRegistryMetadata | null> {\n const database = await this.#getDatabase();\n return database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n * @private\n */\n #verifySignature(database: string, signature: string) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = verify({\n registry: database,\n signature: JSON.parse(signature),\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
1
+ {"version":3,"file":"json.cjs","sourceRoot":"","sources":["../../../src/snaps/registry/json.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { SnapsRegistryDatabase } from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type {\n SnapsRegistry,\n SnapsRegistryInfo,\n SnapsRegistryMetadata,\n SnapsRegistryRequest,\n SnapsRegistryResult,\n} from './registry';\nimport { SnapsRegistryStatus } from './registry';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type JsonSnapsRegistryArgs = {\n messenger: SnapsRegistryMessenger;\n state?: SnapsRegistryState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n};\n\nexport type GetResult = {\n type: `${typeof controllerName}:get`;\n handler: SnapsRegistry['get'];\n};\n\nexport type ResolveVersion = {\n type: `${typeof controllerName}:resolveVersion`;\n handler: SnapsRegistry['resolveVersion'];\n};\n\nexport type GetMetadata = {\n type: `${typeof controllerName}:getMetadata`;\n handler: SnapsRegistry['getMetadata'];\n};\n\nexport type Update = {\n type: `${typeof controllerName}:update`;\n handler: SnapsRegistry['update'];\n};\n\nexport type SnapsRegistryGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryActions =\n | SnapsRegistryGetStateAction\n | GetResult\n | GetMetadata\n | Update\n | ResolveVersion;\n\nexport type SnapsRegistryStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryEvents = SnapsRegistryStateChangeEvent;\n\nexport type SnapsRegistryMessenger = RestrictedControllerMessenger<\n 'SnapsRegistry',\n SnapsRegistryActions,\n SnapsRegistryEvents,\n SnapsRegistryActions['type'],\n SnapsRegistryEvents['type']\n>;\n\nexport type SnapsRegistryState = {\n database: SnapsRegistryDatabase | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapsRegistry';\n\nconst defaultState = {\n database: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class JsonSnapsRegistry extends BaseController<\n typeof controllerName,\n SnapsRegistryState,\n SnapsRegistryMessenger\n> {\n #url: JsonSnapsRegistryUrl;\n\n #publicKey: Hex;\n\n #fetchFunction: typeof fetch;\n\n #recentFetchThreshold: number;\n\n #refetchOnAllowlistMiss: boolean;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n refetchOnAllowlistMiss = true,\n }: JsonSnapsRegistryArgs) {\n super({\n messenger,\n metadata: {\n database: { persist: true, anonymous: false },\n lastUpdated: { persist: true, anonymous: false },\n databaseUnavailable: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:get',\n async (...args) => this.#get(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:getMetadata',\n async (...args) => this.#getMetadata(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:resolveVersion',\n async (...args) => this.#resolveVersion(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:update',\n async () => this.#triggerUpdate(),\n );\n }\n\n #wasRecentlyFetched() {\n return (\n this.state.lastUpdated &&\n Date.now() - this.state.lastUpdated < this.#recentFetchThreshold\n );\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async #triggerUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n return;\n }\n\n try {\n const database = await this.#safeFetch(this.#url.registry);\n\n const signature = await this.#safeFetch(this.#url.signature);\n this.#verifySignature(database, signature);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.#triggerUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapsRegistryInfo,\n refetch = false,\n ): Promise<SnapsRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapsRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n if (version && version.checksum === snapInfo.checksum) {\n return { status: SnapsRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapsRegistryStatus.Unavailable\n : SnapsRegistryStatus.Unverified,\n };\n }\n\n async #get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<string, SnapsRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapsRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async #resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const targetVersion = getTargetVersion(\n Object.keys(versions) as SemVerVersion[],\n versionRange,\n );\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n async #getMetadata(snapId: string): Promise<SnapsRegistryMetadata | null> {\n const database = await this.#getDatabase();\n return database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n * @private\n */\n #verifySignature(database: string, signature: string) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = verify({\n registry: database,\n signature: JSON.parse(signature),\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
@@ -1,3 +1,15 @@
1
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
2
+ if (kind === "m") throw new TypeError("Private method is not writable");
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
5
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
6
+ };
7
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
8
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
9
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
10
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
11
+ };
12
+ var _JsonSnapsRegistry_instances, _JsonSnapsRegistry_url, _JsonSnapsRegistry_publicKey, _JsonSnapsRegistry_fetchFunction, _JsonSnapsRegistry_recentFetchThreshold, _JsonSnapsRegistry_refetchOnAllowlistMiss, _JsonSnapsRegistry_currentUpdate, _JsonSnapsRegistry_wasRecentlyFetched, _JsonSnapsRegistry_triggerUpdate, _JsonSnapsRegistry_update, _JsonSnapsRegistry_getDatabase, _JsonSnapsRegistry_getSingle, _JsonSnapsRegistry_get, _JsonSnapsRegistry_resolveVersion, _JsonSnapsRegistry_getMetadata, _JsonSnapsRegistry_verifySignature, _JsonSnapsRegistry_safeFetch;
1
13
  import { BaseController } from "@metamask/base-controller";
2
14
  import $metamasksnapsregistry from "@metamask/snaps-registry";
3
15
  const { verify } = $metamasksnapsregistry;
@@ -14,12 +26,6 @@ const defaultState = {
14
26
  databaseUnavailable: false,
15
27
  };
16
28
  export class JsonSnapsRegistry extends BaseController {
17
- #url;
18
- #publicKey;
19
- #fetchFunction;
20
- #recentFetchThreshold;
21
- #refetchOnAllowlistMiss;
22
- #currentUpdate;
23
29
  constructor({ messenger, state, url = {
24
30
  registry: SNAP_REGISTRY_URL,
25
31
  signature: SNAP_REGISTRY_SIGNATURE_URL,
@@ -37,184 +43,179 @@ export class JsonSnapsRegistry extends BaseController {
37
43
  ...state,
38
44
  },
39
45
  });
40
- this.#url = url;
41
- this.#publicKey = publicKey;
42
- this.#fetchFunction = fetchFunction;
43
- this.#recentFetchThreshold = recentFetchThreshold;
44
- this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;
45
- this.#currentUpdate = null;
46
- this.messagingSystem.registerActionHandler('SnapsRegistry:get', async (...args) => this.#get(...args));
47
- this.messagingSystem.registerActionHandler('SnapsRegistry:getMetadata', async (...args) => this.#getMetadata(...args));
48
- this.messagingSystem.registerActionHandler('SnapsRegistry:resolveVersion', async (...args) => this.#resolveVersion(...args));
49
- this.messagingSystem.registerActionHandler('SnapsRegistry:update', async () => this.#triggerUpdate());
46
+ _JsonSnapsRegistry_instances.add(this);
47
+ _JsonSnapsRegistry_url.set(this, void 0);
48
+ _JsonSnapsRegistry_publicKey.set(this, void 0);
49
+ _JsonSnapsRegistry_fetchFunction.set(this, void 0);
50
+ _JsonSnapsRegistry_recentFetchThreshold.set(this, void 0);
51
+ _JsonSnapsRegistry_refetchOnAllowlistMiss.set(this, void 0);
52
+ _JsonSnapsRegistry_currentUpdate.set(this, void 0);
53
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_url, url, "f");
54
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_publicKey, publicKey, "f");
55
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_fetchFunction, fetchFunction, "f");
56
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_recentFetchThreshold, recentFetchThreshold, "f");
57
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_refetchOnAllowlistMiss, refetchOnAllowlistMiss, "f");
58
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_currentUpdate, null, "f");
59
+ this.messagingSystem.registerActionHandler('SnapsRegistry:get', async (...args) => __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_get).call(this, ...args));
60
+ this.messagingSystem.registerActionHandler('SnapsRegistry:getMetadata', async (...args) => __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_getMetadata).call(this, ...args));
61
+ this.messagingSystem.registerActionHandler('SnapsRegistry:resolveVersion', async (...args) => __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_resolveVersion).call(this, ...args));
62
+ this.messagingSystem.registerActionHandler('SnapsRegistry:update', async () => __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_triggerUpdate).call(this));
50
63
  }
51
- #wasRecentlyFetched() {
52
- return (this.state.lastUpdated &&
53
- Date.now() - this.state.lastUpdated < this.#recentFetchThreshold);
64
+ }
65
+ _JsonSnapsRegistry_url = new WeakMap(), _JsonSnapsRegistry_publicKey = new WeakMap(), _JsonSnapsRegistry_fetchFunction = new WeakMap(), _JsonSnapsRegistry_recentFetchThreshold = new WeakMap(), _JsonSnapsRegistry_refetchOnAllowlistMiss = new WeakMap(), _JsonSnapsRegistry_currentUpdate = new WeakMap(), _JsonSnapsRegistry_instances = new WeakSet(), _JsonSnapsRegistry_wasRecentlyFetched = function _JsonSnapsRegistry_wasRecentlyFetched() {
66
+ return (this.state.lastUpdated &&
67
+ Date.now() - this.state.lastUpdated < __classPrivateFieldGet(this, _JsonSnapsRegistry_recentFetchThreshold, "f"));
68
+ }, _JsonSnapsRegistry_triggerUpdate =
69
+ /**
70
+ * Triggers an update of the registry database.
71
+ *
72
+ * If an existing update is in progress this function will await that update.
73
+ */
74
+ async function _JsonSnapsRegistry_triggerUpdate() {
75
+ // If an update is ongoing, wait for that.
76
+ if (__classPrivateFieldGet(this, _JsonSnapsRegistry_currentUpdate, "f")) {
77
+ await __classPrivateFieldGet(this, _JsonSnapsRegistry_currentUpdate, "f");
78
+ return;
54
79
  }
55
- /**
56
- * Triggers an update of the registry database.
57
- *
58
- * If an existing update is in progress this function will await that update.
59
- */
60
- async #triggerUpdate() {
61
- // If an update is ongoing, wait for that.
62
- if (this.#currentUpdate) {
63
- await this.#currentUpdate;
64
- return;
65
- }
66
- // If no update exists, create promise and store globally.
67
- if (this.#currentUpdate === null) {
68
- this.#currentUpdate = this.#update();
69
- }
70
- await this.#currentUpdate;
71
- this.#currentUpdate = null;
80
+ // If no update exists, create promise and store globally.
81
+ if (__classPrivateFieldGet(this, _JsonSnapsRegistry_currentUpdate, "f") === null) {
82
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_currentUpdate, __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_update).call(this), "f");
72
83
  }
73
- /**
74
- * Updates the registry database if the registry hasn't been updated recently.
75
- *
76
- * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.
77
- */
78
- async #update() {
79
- // No-op if we recently fetched the registry.
80
- if (this.#wasRecentlyFetched()) {
81
- return;
82
- }
83
- try {
84
- const database = await this.#safeFetch(this.#url.registry);
85
- const signature = await this.#safeFetch(this.#url.signature);
86
- this.#verifySignature(database, signature);
87
- this.update((state) => {
88
- state.database = JSON.parse(database);
89
- state.lastUpdated = Date.now();
90
- state.databaseUnavailable = false;
91
- });
92
- }
93
- catch {
94
- // Ignore
95
- this.update((state) => {
96
- state.databaseUnavailable = true;
97
- });
98
- }
84
+ await __classPrivateFieldGet(this, _JsonSnapsRegistry_currentUpdate, "f");
85
+ __classPrivateFieldSet(this, _JsonSnapsRegistry_currentUpdate, null, "f");
86
+ }, _JsonSnapsRegistry_update =
87
+ /**
88
+ * Updates the registry database if the registry hasn't been updated recently.
89
+ *
90
+ * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.
91
+ */
92
+ async function _JsonSnapsRegistry_update() {
93
+ // No-op if we recently fetched the registry.
94
+ if (__classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_wasRecentlyFetched).call(this)) {
95
+ return;
99
96
  }
100
- async #getDatabase() {
101
- if (this.state.database === null) {
102
- await this.#triggerUpdate();
103
- }
104
- return this.state.database;
97
+ try {
98
+ const database = await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_safeFetch).call(this, __classPrivateFieldGet(this, _JsonSnapsRegistry_url, "f").registry);
99
+ const signature = await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_safeFetch).call(this, __classPrivateFieldGet(this, _JsonSnapsRegistry_url, "f").signature);
100
+ __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_verifySignature).call(this, database, signature);
101
+ this.update((state) => {
102
+ state.database = JSON.parse(database);
103
+ state.lastUpdated = Date.now();
104
+ state.databaseUnavailable = false;
105
+ });
105
106
  }
106
- async #getSingle(snapId, snapInfo, refetch = false) {
107
- const database = await this.#getDatabase();
108
- const blockedEntry = database?.blockedSnaps.find((blocked) => {
109
- if ('id' in blocked) {
110
- return (blocked.id === snapId &&
111
- satisfiesVersionRange(snapInfo.version, blocked.versionRange));
112
- }
113
- return blocked.checksum === snapInfo.checksum;
107
+ catch {
108
+ // Ignore
109
+ this.update((state) => {
110
+ state.databaseUnavailable = true;
114
111
  });
115
- if (blockedEntry) {
116
- return {
117
- status: SnapsRegistryStatus.Blocked,
118
- reason: blockedEntry.reason,
119
- };
120
- }
121
- const verified = database?.verifiedSnaps[snapId];
122
- const version = verified?.versions?.[snapInfo.version];
123
- if (version && version.checksum === snapInfo.checksum) {
124
- return { status: SnapsRegistryStatus.Verified };
125
- }
126
- // For now, if we have an allowlist miss, we can refetch once and try again.
127
- if (this.#refetchOnAllowlistMiss && !refetch) {
128
- await this.#triggerUpdate();
129
- return this.#getSingle(snapId, snapInfo, true);
112
+ }
113
+ }, _JsonSnapsRegistry_getDatabase = async function _JsonSnapsRegistry_getDatabase() {
114
+ if (this.state.database === null) {
115
+ await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_triggerUpdate).call(this);
116
+ }
117
+ return this.state.database;
118
+ }, _JsonSnapsRegistry_getSingle = async function _JsonSnapsRegistry_getSingle(snapId, snapInfo, refetch = false) {
119
+ const database = await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_getDatabase).call(this);
120
+ const blockedEntry = database?.blockedSnaps.find((blocked) => {
121
+ if ('id' in blocked) {
122
+ return (blocked.id === snapId &&
123
+ satisfiesVersionRange(snapInfo.version, blocked.versionRange));
130
124
  }
125
+ return blocked.checksum === snapInfo.checksum;
126
+ });
127
+ if (blockedEntry) {
131
128
  return {
132
- status: this.state.databaseUnavailable
133
- ? SnapsRegistryStatus.Unavailable
134
- : SnapsRegistryStatus.Unverified,
129
+ status: SnapsRegistryStatus.Blocked,
130
+ reason: blockedEntry.reason,
135
131
  };
136
132
  }
137
- async #get(snaps) {
138
- return Object.entries(snaps).reduce(async (previousPromise, [snapId, snapInfo]) => {
139
- const result = await this.#getSingle(snapId, snapInfo);
140
- const acc = await previousPromise;
141
- acc[snapId] = result;
142
- return acc;
143
- }, Promise.resolve({}));
133
+ const verified = database?.verifiedSnaps[snapId];
134
+ const version = verified?.versions?.[snapInfo.version];
135
+ if (version && version.checksum === snapInfo.checksum) {
136
+ return { status: SnapsRegistryStatus.Verified };
144
137
  }
145
- /**
146
- * Find an allowlisted version within a specified version range. Otherwise return the version range itself.
147
- *
148
- * @param snapId - The ID of the snap we are trying to resolve a version for.
149
- * @param versionRange - The version range.
150
- * @param refetch - An optional flag used to determine if we are refetching the registry.
151
- * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.
152
- */
153
- async #resolveVersion(snapId, versionRange, refetch = false) {
154
- const database = await this.#getDatabase();
155
- const versions = database?.verifiedSnaps[snapId]?.versions ?? null;
156
- if (!versions && this.#refetchOnAllowlistMiss && !refetch) {
157
- await this.#triggerUpdate();
158
- return this.#resolveVersion(snapId, versionRange, true);
159
- }
160
- // If we cannot narrow down the version range we return the unaltered version range.
161
- if (!versions) {
162
- return versionRange;
163
- }
164
- const targetVersion = getTargetVersion(Object.keys(versions), versionRange);
165
- if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {
166
- await this.#triggerUpdate();
167
- return this.#resolveVersion(snapId, versionRange, true);
168
- }
169
- // If we cannot narrow down the version range we return the unaltered version range.
170
- if (!targetVersion) {
171
- return versionRange;
172
- }
173
- // A semver version is technically also a valid semver range.
174
- assertIsSemVerRange(targetVersion);
175
- return targetVersion;
138
+ // For now, if we have an allowlist miss, we can refetch once and try again.
139
+ if (__classPrivateFieldGet(this, _JsonSnapsRegistry_refetchOnAllowlistMiss, "f") && !refetch) {
140
+ await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_triggerUpdate).call(this);
141
+ return __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_getSingle).call(this, snapId, snapInfo, true);
176
142
  }
177
- /**
178
- * Get metadata for the given snap ID.
179
- *
180
- * @param snapId - The ID of the snap to get metadata for.
181
- * @returns The metadata for the given snap ID, or `null` if the snap is not
182
- * verified.
183
- */
184
- async #getMetadata(snapId) {
185
- const database = await this.#getDatabase();
186
- return database?.verifiedSnaps[snapId]?.metadata ?? null;
143
+ return {
144
+ status: this.state.databaseUnavailable
145
+ ? SnapsRegistryStatus.Unavailable
146
+ : SnapsRegistryStatus.Unverified,
147
+ };
148
+ }, _JsonSnapsRegistry_get = async function _JsonSnapsRegistry_get(snaps) {
149
+ return Object.entries(snaps).reduce(async (previousPromise, [snapId, snapInfo]) => {
150
+ const result = await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_getSingle).call(this, snapId, snapInfo);
151
+ const acc = await previousPromise;
152
+ acc[snapId] = result;
153
+ return acc;
154
+ }, Promise.resolve({}));
155
+ }, _JsonSnapsRegistry_resolveVersion =
156
+ /**
157
+ * Find an allowlisted version within a specified version range. Otherwise return the version range itself.
158
+ *
159
+ * @param snapId - The ID of the snap we are trying to resolve a version for.
160
+ * @param versionRange - The version range.
161
+ * @param refetch - An optional flag used to determine if we are refetching the registry.
162
+ * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.
163
+ */
164
+ async function _JsonSnapsRegistry_resolveVersion(snapId, versionRange, refetch = false) {
165
+ const database = await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_getDatabase).call(this);
166
+ const versions = database?.verifiedSnaps[snapId]?.versions ?? null;
167
+ if (!versions && __classPrivateFieldGet(this, _JsonSnapsRegistry_refetchOnAllowlistMiss, "f") && !refetch) {
168
+ await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_triggerUpdate).call(this);
169
+ return __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_resolveVersion).call(this, snapId, versionRange, true);
187
170
  }
188
- /**
189
- * Verify the signature of the registry.
190
- *
191
- * @param database - The registry database.
192
- * @param signature - The signature of the registry.
193
- * @throws If the signature is invalid.
194
- * @private
195
- */
196
- #verifySignature(database, signature) {
197
- assert(this.#publicKey, 'No public key provided.');
198
- const valid = verify({
199
- registry: database,
200
- signature: JSON.parse(signature),
201
- publicKey: this.#publicKey,
202
- });
203
- assert(valid, 'Invalid registry signature.');
171
+ // If we cannot narrow down the version range we return the unaltered version range.
172
+ if (!versions) {
173
+ return versionRange;
204
174
  }
205
- /**
206
- * Fetch the given URL, throwing if the response is not OK.
207
- *
208
- * @param url - The URL to fetch.
209
- * @returns The response body.
210
- * @private
211
- */
212
- async #safeFetch(url) {
213
- const response = await this.#fetchFunction(url);
214
- if (!response.ok) {
215
- throw new Error(`Failed to fetch ${url}.`);
216
- }
217
- return await response.text();
175
+ const targetVersion = getTargetVersion(Object.keys(versions), versionRange);
176
+ if (!targetVersion && __classPrivateFieldGet(this, _JsonSnapsRegistry_refetchOnAllowlistMiss, "f") && !refetch) {
177
+ await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_triggerUpdate).call(this);
178
+ return __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_resolveVersion).call(this, snapId, versionRange, true);
218
179
  }
219
- }
180
+ // If we cannot narrow down the version range we return the unaltered version range.
181
+ if (!targetVersion) {
182
+ return versionRange;
183
+ }
184
+ // A semver version is technically also a valid semver range.
185
+ assertIsSemVerRange(targetVersion);
186
+ return targetVersion;
187
+ }, _JsonSnapsRegistry_getMetadata =
188
+ /**
189
+ * Get metadata for the given snap ID.
190
+ *
191
+ * @param snapId - The ID of the snap to get metadata for.
192
+ * @returns The metadata for the given snap ID, or `null` if the snap is not
193
+ * verified.
194
+ */
195
+ async function _JsonSnapsRegistry_getMetadata(snapId) {
196
+ const database = await __classPrivateFieldGet(this, _JsonSnapsRegistry_instances, "m", _JsonSnapsRegistry_getDatabase).call(this);
197
+ return database?.verifiedSnaps[snapId]?.metadata ?? null;
198
+ }, _JsonSnapsRegistry_verifySignature = function _JsonSnapsRegistry_verifySignature(database, signature) {
199
+ assert(__classPrivateFieldGet(this, _JsonSnapsRegistry_publicKey, "f"), 'No public key provided.');
200
+ const valid = verify({
201
+ registry: database,
202
+ signature: JSON.parse(signature),
203
+ publicKey: __classPrivateFieldGet(this, _JsonSnapsRegistry_publicKey, "f"),
204
+ });
205
+ assert(valid, 'Invalid registry signature.');
206
+ }, _JsonSnapsRegistry_safeFetch =
207
+ /**
208
+ * Fetch the given URL, throwing if the response is not OK.
209
+ *
210
+ * @param url - The URL to fetch.
211
+ * @returns The response body.
212
+ * @private
213
+ */
214
+ async function _JsonSnapsRegistry_safeFetch(url) {
215
+ const response = await __classPrivateFieldGet(this, _JsonSnapsRegistry_fetchFunction, "f").call(this, url);
216
+ if (!response.ok) {
217
+ throw new Error(`Failed to fetch ${url}.`);
218
+ }
219
+ return await response.text();
220
+ };
220
221
  //# sourceMappingURL=json.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"json.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/json.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { SnapsRegistryDatabase } from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type {\n SnapsRegistry,\n SnapsRegistryInfo,\n SnapsRegistryMetadata,\n SnapsRegistryRequest,\n SnapsRegistryResult,\n} from './registry';\nimport { SnapsRegistryStatus } from './registry';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type JsonSnapsRegistryArgs = {\n messenger: SnapsRegistryMessenger;\n state?: SnapsRegistryState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n};\n\nexport type GetResult = {\n type: `${typeof controllerName}:get`;\n handler: SnapsRegistry['get'];\n};\n\nexport type ResolveVersion = {\n type: `${typeof controllerName}:resolveVersion`;\n handler: SnapsRegistry['resolveVersion'];\n};\n\nexport type GetMetadata = {\n type: `${typeof controllerName}:getMetadata`;\n handler: SnapsRegistry['getMetadata'];\n};\n\nexport type Update = {\n type: `${typeof controllerName}:update`;\n handler: SnapsRegistry['update'];\n};\n\nexport type SnapsRegistryGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryActions =\n | SnapsRegistryGetStateAction\n | GetResult\n | GetMetadata\n | Update\n | ResolveVersion;\n\nexport type SnapsRegistryStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryEvents = SnapsRegistryStateChangeEvent;\n\nexport type SnapsRegistryMessenger = RestrictedControllerMessenger<\n 'SnapsRegistry',\n SnapsRegistryActions,\n SnapsRegistryEvents,\n SnapsRegistryActions['type'],\n SnapsRegistryEvents['type']\n>;\n\nexport type SnapsRegistryState = {\n database: SnapsRegistryDatabase | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapsRegistry';\n\nconst defaultState = {\n database: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class JsonSnapsRegistry extends BaseController<\n typeof controllerName,\n SnapsRegistryState,\n SnapsRegistryMessenger\n> {\n #url: JsonSnapsRegistryUrl;\n\n #publicKey: Hex;\n\n #fetchFunction: typeof fetch;\n\n #recentFetchThreshold: number;\n\n #refetchOnAllowlistMiss: boolean;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n refetchOnAllowlistMiss = true,\n }: JsonSnapsRegistryArgs) {\n super({\n messenger,\n metadata: {\n database: { persist: true, anonymous: false },\n lastUpdated: { persist: true, anonymous: false },\n databaseUnavailable: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:get',\n async (...args) => this.#get(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:getMetadata',\n async (...args) => this.#getMetadata(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:resolveVersion',\n async (...args) => this.#resolveVersion(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:update',\n async () => this.#triggerUpdate(),\n );\n }\n\n #wasRecentlyFetched() {\n return (\n this.state.lastUpdated &&\n Date.now() - this.state.lastUpdated < this.#recentFetchThreshold\n );\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async #triggerUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n return;\n }\n\n try {\n const database = await this.#safeFetch(this.#url.registry);\n\n const signature = await this.#safeFetch(this.#url.signature);\n this.#verifySignature(database, signature);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.#triggerUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapsRegistryInfo,\n refetch = false,\n ): Promise<SnapsRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapsRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n if (version && version.checksum === snapInfo.checksum) {\n return { status: SnapsRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapsRegistryStatus.Unavailable\n : SnapsRegistryStatus.Unverified,\n };\n }\n\n async #get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<string, SnapsRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapsRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async #resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const targetVersion = getTargetVersion(\n Object.keys(versions) as SemVerVersion[],\n versionRange,\n );\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n async #getMetadata(snapId: string): Promise<SnapsRegistryMetadata | null> {\n const database = await this.#getDatabase();\n return database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n * @private\n */\n #verifySignature(database: string, signature: string) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = verify({\n registry: database,\n signature: JSON.parse(signature),\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
1
+ {"version":3,"file":"json.mjs","sourceRoot":"","sources":["../../../src/snaps/registry/json.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n RestrictedControllerMessenger,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { SnapsRegistryDatabase } from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion } from '@metamask/snaps-utils';\nimport type { Hex, SemVerRange, SemVerVersion } from '@metamask/utils';\nimport {\n assert,\n assertIsSemVerRange,\n Duration,\n inMilliseconds,\n satisfiesVersionRange,\n} from '@metamask/utils';\n\nimport type {\n SnapsRegistry,\n SnapsRegistryInfo,\n SnapsRegistryMetadata,\n SnapsRegistryRequest,\n SnapsRegistryResult,\n} from './registry';\nimport { SnapsRegistryStatus } from './registry';\n\nconst SNAP_REGISTRY_URL =\n 'https://acl.execution.metamask.io/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://acl.execution.metamask.io/latest/signature.json';\n\nconst DEFAULT_PUBLIC_KEY =\n '0x025b65308f0f0fb8bc7f7ff87bfc296e0330eee5d3c1d1ee4a048b2fd6a86fa0a6';\n\ntype JsonSnapsRegistryUrl = {\n registry: string;\n signature: string;\n};\n\nexport type JsonSnapsRegistryArgs = {\n messenger: SnapsRegistryMessenger;\n state?: SnapsRegistryState;\n fetchFunction?: typeof fetch;\n url?: JsonSnapsRegistryUrl;\n recentFetchThreshold?: number;\n refetchOnAllowlistMiss?: boolean;\n publicKey?: Hex;\n};\n\nexport type GetResult = {\n type: `${typeof controllerName}:get`;\n handler: SnapsRegistry['get'];\n};\n\nexport type ResolveVersion = {\n type: `${typeof controllerName}:resolveVersion`;\n handler: SnapsRegistry['resolveVersion'];\n};\n\nexport type GetMetadata = {\n type: `${typeof controllerName}:getMetadata`;\n handler: SnapsRegistry['getMetadata'];\n};\n\nexport type Update = {\n type: `${typeof controllerName}:update`;\n handler: SnapsRegistry['update'];\n};\n\nexport type SnapsRegistryGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryActions =\n | SnapsRegistryGetStateAction\n | GetResult\n | GetMetadata\n | Update\n | ResolveVersion;\n\nexport type SnapsRegistryStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SnapsRegistryState\n>;\n\nexport type SnapsRegistryEvents = SnapsRegistryStateChangeEvent;\n\nexport type SnapsRegistryMessenger = RestrictedControllerMessenger<\n 'SnapsRegistry',\n SnapsRegistryActions,\n SnapsRegistryEvents,\n SnapsRegistryActions['type'],\n SnapsRegistryEvents['type']\n>;\n\nexport type SnapsRegistryState = {\n database: SnapsRegistryDatabase | null;\n lastUpdated: number | null;\n databaseUnavailable: boolean;\n};\n\nconst controllerName = 'SnapsRegistry';\n\nconst defaultState = {\n database: null,\n lastUpdated: null,\n databaseUnavailable: false,\n};\n\nexport class JsonSnapsRegistry extends BaseController<\n typeof controllerName,\n SnapsRegistryState,\n SnapsRegistryMessenger\n> {\n #url: JsonSnapsRegistryUrl;\n\n #publicKey: Hex;\n\n #fetchFunction: typeof fetch;\n\n #recentFetchThreshold: number;\n\n #refetchOnAllowlistMiss: boolean;\n\n #currentUpdate: Promise<void> | null;\n\n constructor({\n messenger,\n state,\n url = {\n registry: SNAP_REGISTRY_URL,\n signature: SNAP_REGISTRY_SIGNATURE_URL,\n },\n publicKey = DEFAULT_PUBLIC_KEY,\n fetchFunction = globalThis.fetch.bind(undefined),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n refetchOnAllowlistMiss = true,\n }: JsonSnapsRegistryArgs) {\n super({\n messenger,\n metadata: {\n database: { persist: true, anonymous: false },\n lastUpdated: { persist: true, anonymous: false },\n databaseUnavailable: { persist: true, anonymous: false },\n },\n name: controllerName,\n state: {\n ...defaultState,\n ...state,\n },\n });\n this.#url = url;\n this.#publicKey = publicKey;\n this.#fetchFunction = fetchFunction;\n this.#recentFetchThreshold = recentFetchThreshold;\n this.#refetchOnAllowlistMiss = refetchOnAllowlistMiss;\n this.#currentUpdate = null;\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:get',\n async (...args) => this.#get(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:getMetadata',\n async (...args) => this.#getMetadata(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:resolveVersion',\n async (...args) => this.#resolveVersion(...args),\n );\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:update',\n async () => this.#triggerUpdate(),\n );\n }\n\n #wasRecentlyFetched() {\n return (\n this.state.lastUpdated &&\n Date.now() - this.state.lastUpdated < this.#recentFetchThreshold\n );\n }\n\n /**\n * Triggers an update of the registry database.\n *\n * If an existing update is in progress this function will await that update.\n */\n async #triggerUpdate() {\n // If an update is ongoing, wait for that.\n if (this.#currentUpdate) {\n await this.#currentUpdate;\n return;\n }\n // If no update exists, create promise and store globally.\n if (this.#currentUpdate === null) {\n this.#currentUpdate = this.#update();\n }\n await this.#currentUpdate;\n this.#currentUpdate = null;\n }\n\n /**\n * Updates the registry database if the registry hasn't been updated recently.\n *\n * NOTE: SHOULD NOT be called directly, instead `triggerUpdate` should be used.\n */\n async #update() {\n // No-op if we recently fetched the registry.\n if (this.#wasRecentlyFetched()) {\n return;\n }\n\n try {\n const database = await this.#safeFetch(this.#url.registry);\n\n const signature = await this.#safeFetch(this.#url.signature);\n this.#verifySignature(database, signature);\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n state.databaseUnavailable = false;\n });\n } catch {\n // Ignore\n this.update((state) => {\n state.databaseUnavailable = true;\n });\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.#triggerUpdate();\n }\n\n return this.state.database;\n }\n\n async #getSingle(\n snapId: string,\n snapInfo: SnapsRegistryInfo,\n refetch = false,\n ): Promise<SnapsRegistryResult> {\n const database = await this.#getDatabase();\n\n const blockedEntry = database?.blockedSnaps.find((blocked) => {\n if ('id' in blocked) {\n return (\n blocked.id === snapId &&\n satisfiesVersionRange(snapInfo.version, blocked.versionRange)\n );\n }\n\n return blocked.checksum === snapInfo.checksum;\n });\n\n if (blockedEntry) {\n return {\n status: SnapsRegistryStatus.Blocked,\n reason: blockedEntry.reason,\n };\n }\n\n const verified = database?.verifiedSnaps[snapId];\n const version = verified?.versions?.[snapInfo.version];\n if (version && version.checksum === snapInfo.checksum) {\n return { status: SnapsRegistryStatus.Verified };\n }\n // For now, if we have an allowlist miss, we can refetch once and try again.\n if (this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#getSingle(snapId, snapInfo, true);\n }\n return {\n status: this.state.databaseUnavailable\n ? SnapsRegistryStatus.Unavailable\n : SnapsRegistryStatus.Unverified,\n };\n }\n\n async #get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<string, SnapsRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<string, SnapsRegistryResult>>\n >(async (previousPromise, [snapId, snapInfo]) => {\n const result = await this.#getSingle(snapId, snapInfo);\n const acc = await previousPromise;\n acc[snapId] = result;\n return acc;\n }, Promise.resolve({}));\n }\n\n /**\n * Find an allowlisted version within a specified version range. Otherwise return the version range itself.\n *\n * @param snapId - The ID of the snap we are trying to resolve a version for.\n * @param versionRange - The version range.\n * @param refetch - An optional flag used to determine if we are refetching the registry.\n * @returns An allowlisted version within the specified version range if available otherwise returns the input version range.\n */\n async #resolveVersion(\n snapId: string,\n versionRange: SemVerRange,\n refetch = false,\n ): Promise<SemVerRange> {\n const database = await this.#getDatabase();\n const versions = database?.verifiedSnaps[snapId]?.versions ?? null;\n\n if (!versions && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!versions) {\n return versionRange;\n }\n\n const targetVersion = getTargetVersion(\n Object.keys(versions) as SemVerVersion[],\n versionRange,\n );\n\n if (!targetVersion && this.#refetchOnAllowlistMiss && !refetch) {\n await this.#triggerUpdate();\n return this.#resolveVersion(snapId, versionRange, true);\n }\n\n // If we cannot narrow down the version range we return the unaltered version range.\n if (!targetVersion) {\n return versionRange;\n }\n\n // A semver version is technically also a valid semver range.\n assertIsSemVerRange(targetVersion);\n return targetVersion;\n }\n\n /**\n * Get metadata for the given snap ID.\n *\n * @param snapId - The ID of the snap to get metadata for.\n * @returns The metadata for the given snap ID, or `null` if the snap is not\n * verified.\n */\n async #getMetadata(snapId: string): Promise<SnapsRegistryMetadata | null> {\n const database = await this.#getDatabase();\n return database?.verifiedSnaps[snapId]?.metadata ?? null;\n }\n\n /**\n * Verify the signature of the registry.\n *\n * @param database - The registry database.\n * @param signature - The signature of the registry.\n * @throws If the signature is invalid.\n * @private\n */\n #verifySignature(database: string, signature: string) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = verify({\n registry: database,\n signature: JSON.parse(signature),\n publicKey: this.#publicKey,\n });\n\n assert(valid, 'Invalid registry signature.');\n }\n\n /**\n * Fetch the given URL, throwing if the response is not OK.\n *\n * @param url - The URL to fetch.\n * @returns The response body.\n * @private\n */\n async #safeFetch(url: string) {\n const response = await this.#fetchFunction(url);\n if (!response.ok) {\n throw new Error(`Failed to fetch ${url}.`);\n }\n\n return await response.text();\n }\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@metamask/snaps-controllers",
3
- "version": "9.9.0",
3
+ "version": "9.10.0",
4
4
  "description": "Controllers for MetaMask Snaps",
5
5
  "keywords": [
6
6
  "MetaMask",
@@ -89,9 +89,9 @@
89
89
  "@metamask/post-message-stream": "^8.1.1",
90
90
  "@metamask/rpc-errors": "^6.3.1",
91
91
  "@metamask/snaps-registry": "^3.2.1",
92
- "@metamask/snaps-rpc-methods": "^11.2.0",
93
- "@metamask/snaps-sdk": "^6.6.0",
94
- "@metamask/snaps-utils": "^8.2.0",
92
+ "@metamask/snaps-rpc-methods": "^11.3.0",
93
+ "@metamask/snaps-sdk": "^6.7.0",
94
+ "@metamask/snaps-utils": "^8.3.0",
95
95
  "@metamask/utils": "^9.2.1",
96
96
  "@xstate/fsm": "^2.0.0",
97
97
  "browserify-zlib": "^0.2.0",
@@ -165,7 +165,7 @@
165
165
  "webdriverio": "^8.19.0"
166
166
  },
167
167
  "peerDependencies": {
168
- "@metamask/snaps-execution-environments": "^6.8.0"
168
+ "@metamask/snaps-execution-environments": "^6.9.0"
169
169
  },
170
170
  "peerDependenciesMeta": {
171
171
  "@metamask/snaps-execution-environments": {