@metamask/snaps-controllers 3.0.0 → 3.1.1
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.
- package/CHANGELOG.md +25 -1
- package/dist/cjs/cronjob/CronjobController.js +1 -1
- package/dist/cjs/cronjob/CronjobController.js.map +1 -1
- package/dist/cjs/services/AbstractExecutionService.js +6 -7
- package/dist/cjs/services/AbstractExecutionService.js.map +1 -1
- package/dist/cjs/snaps/SnapController.js +72 -82
- package/dist/cjs/snaps/SnapController.js.map +1 -1
- package/dist/cjs/snaps/endowments/cronjob.js +4 -4
- package/dist/cjs/snaps/endowments/cronjob.js.map +1 -1
- package/dist/cjs/snaps/endowments/keyring.js +4 -4
- package/dist/cjs/snaps/endowments/keyring.js.map +1 -1
- package/dist/cjs/snaps/endowments/name-lookup.js +3 -3
- package/dist/cjs/snaps/endowments/name-lookup.js.map +1 -1
- package/dist/cjs/snaps/endowments/rpc.js +4 -4
- package/dist/cjs/snaps/endowments/rpc.js.map +1 -1
- package/dist/cjs/snaps/endowments/transaction-insight.js +3 -3
- package/dist/cjs/snaps/endowments/transaction-insight.js.map +1 -1
- package/dist/cjs/snaps/location/location.js.map +1 -1
- package/dist/cjs/snaps/location/npm.js +47 -16
- package/dist/cjs/snaps/location/npm.js.map +1 -1
- package/dist/cjs/snaps/permissions.js +5 -5
- package/dist/cjs/snaps/permissions.js.map +1 -1
- package/dist/cjs/snaps/registry/json.js +30 -1
- package/dist/cjs/snaps/registry/json.js.map +1 -1
- package/dist/cjs/snaps/registry/registry.js.map +1 -1
- package/dist/esm/cronjob/CronjobController.js +1 -1
- package/dist/esm/cronjob/CronjobController.js.map +1 -1
- package/dist/esm/services/AbstractExecutionService.js +6 -7
- package/dist/esm/services/AbstractExecutionService.js.map +1 -1
- package/dist/esm/snaps/SnapController.js +69 -79
- package/dist/esm/snaps/SnapController.js.map +1 -1
- package/dist/esm/snaps/endowments/cronjob.js +4 -4
- package/dist/esm/snaps/endowments/cronjob.js.map +1 -1
- package/dist/esm/snaps/endowments/keyring.js +4 -4
- package/dist/esm/snaps/endowments/keyring.js.map +1 -1
- package/dist/esm/snaps/endowments/name-lookup.js +3 -3
- package/dist/esm/snaps/endowments/name-lookup.js.map +1 -1
- package/dist/esm/snaps/endowments/rpc.js +4 -4
- package/dist/esm/snaps/endowments/rpc.js.map +1 -1
- package/dist/esm/snaps/endowments/transaction-insight.js +3 -3
- package/dist/esm/snaps/endowments/transaction-insight.js.map +1 -1
- package/dist/esm/snaps/location/location.js.map +1 -1
- package/dist/esm/snaps/location/npm.js +48 -17
- package/dist/esm/snaps/location/npm.js.map +1 -1
- package/dist/esm/snaps/permissions.js +1 -1
- package/dist/esm/snaps/permissions.js.map +1 -1
- package/dist/esm/snaps/registry/json.js +31 -2
- package/dist/esm/snaps/registry/json.js.map +1 -1
- package/dist/esm/snaps/registry/registry.js.map +1 -1
- package/dist/types/cronjob/CronjobController.d.ts +1 -1
- package/dist/types/services/AbstractExecutionService.d.ts +1 -1
- package/dist/types/snaps/SnapController.d.ts +20 -32
- package/dist/types/snaps/location/location.d.ts +2 -0
- package/dist/types/snaps/location/npm.d.ts +1 -1
- package/dist/types/snaps/registry/json.d.ts +5 -1
- package/dist/types/snaps/registry/registry.d.ts +11 -1
- package/package.json +29 -22
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { caveatMappers, restrictedMethodPermissionBuilders, selectHooks } from '@metamask/rpc-methods';
|
|
1
|
+
import { caveatMappers, restrictedMethodPermissionBuilders, selectHooks } from '@metamask/snaps-rpc-methods';
|
|
2
2
|
import { hasProperty } from '@metamask/utils';
|
|
3
3
|
import { endowmentCaveatMappers, endowmentPermissionBuilders } from './endowments';
|
|
4
4
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/snaps/permissions.ts"],"sourcesContent":["import type {\n PermissionConstraint,\n PermissionSpecificationConstraint,\n} from '@metamask/permission-controller';\nimport {\n caveatMappers,\n restrictedMethodPermissionBuilders,\n selectHooks,\n} from '@metamask/rpc-methods';\nimport type { SnapPermissions } from '@metamask/snaps-utils';\nimport { hasProperty } from '@metamask/utils';\n\nimport {\n endowmentCaveatMappers,\n endowmentPermissionBuilders,\n} from './endowments';\n\n/**\n * Map initial permissions as defined in a Snap manifest to something that can\n * be processed by the PermissionsController. Each caveat mapping function\n * should return a valid permission caveat value.\n *\n * This function does not validate the caveat values, since that is done by\n * the PermissionsController itself, upon requesting the permissions.\n *\n * @param initialPermissions - The initial permissions to process.\n * @returns The processed permissions.\n */\nexport function processSnapPermissions(\n initialPermissions: SnapPermissions,\n): Record<string, Pick<PermissionConstraint, 'caveats'>> {\n return Object.fromEntries(\n Object.entries(initialPermissions).map(([initialPermission, value]) => {\n if (hasProperty(caveatMappers, initialPermission)) {\n return [initialPermission, caveatMappers[initialPermission](value)];\n } else if (hasProperty(endowmentCaveatMappers, initialPermission)) {\n return [\n initialPermission,\n endowmentCaveatMappers[initialPermission](value),\n ];\n }\n\n // If we have no mapping, this may be a non-snap permission, return as-is\n return [\n initialPermission,\n value as Pick<PermissionConstraint, 'caveats'>,\n ];\n }),\n );\n}\n\nexport const buildSnapEndowmentSpecifications = (\n excludedEndowments: string[],\n) =>\n Object.values(endowmentPermissionBuilders).reduce<\n Record<string, PermissionSpecificationConstraint>\n >((allSpecifications, { targetName, specificationBuilder }) => {\n if (!excludedEndowments.includes(targetName)) {\n allSpecifications[targetName] = specificationBuilder({});\n }\n return allSpecifications;\n }, {});\n\nexport const buildSnapRestrictedMethodSpecifications = (\n excludedPermissions: string[],\n hooks: Record<string, unknown>,\n) =>\n Object.values(restrictedMethodPermissionBuilders).reduce<\n Record<string, PermissionSpecificationConstraint>\n >((specifications, { targetName, specificationBuilder, methodHooks }) => {\n if (!excludedPermissions.includes(targetName)) {\n specifications[targetName] = specificationBuilder({\n // @ts-expect-error The selectHooks type is wonky\n methodHooks: selectHooks<typeof hooks, keyof typeof methodHooks>(\n hooks,\n methodHooks,\n ) as Pick<typeof hooks, keyof typeof methodHooks>,\n });\n }\n return specifications;\n }, {});\n"],"names":["caveatMappers","restrictedMethodPermissionBuilders","selectHooks","hasProperty","endowmentCaveatMappers","endowmentPermissionBuilders","processSnapPermissions","initialPermissions","Object","fromEntries","entries","map","initialPermission","value","buildSnapEndowmentSpecifications","excludedEndowments","values","reduce","allSpecifications","targetName","specificationBuilder","includes","buildSnapRestrictedMethodSpecifications","excludedPermissions","hooks","specifications","methodHooks"],"mappings":"AAIA,SACEA,aAAa,EACbC,kCAAkC,EAClCC,WAAW,QACN,
|
|
1
|
+
{"version":3,"sources":["../../../src/snaps/permissions.ts"],"sourcesContent":["import type {\n PermissionConstraint,\n PermissionSpecificationConstraint,\n} from '@metamask/permission-controller';\nimport {\n caveatMappers,\n restrictedMethodPermissionBuilders,\n selectHooks,\n} from '@metamask/snaps-rpc-methods';\nimport type { SnapPermissions } from '@metamask/snaps-utils';\nimport { hasProperty } from '@metamask/utils';\n\nimport {\n endowmentCaveatMappers,\n endowmentPermissionBuilders,\n} from './endowments';\n\n/**\n * Map initial permissions as defined in a Snap manifest to something that can\n * be processed by the PermissionsController. Each caveat mapping function\n * should return a valid permission caveat value.\n *\n * This function does not validate the caveat values, since that is done by\n * the PermissionsController itself, upon requesting the permissions.\n *\n * @param initialPermissions - The initial permissions to process.\n * @returns The processed permissions.\n */\nexport function processSnapPermissions(\n initialPermissions: SnapPermissions,\n): Record<string, Pick<PermissionConstraint, 'caveats'>> {\n return Object.fromEntries(\n Object.entries(initialPermissions).map(([initialPermission, value]) => {\n if (hasProperty(caveatMappers, initialPermission)) {\n return [initialPermission, caveatMappers[initialPermission](value)];\n } else if (hasProperty(endowmentCaveatMappers, initialPermission)) {\n return [\n initialPermission,\n endowmentCaveatMappers[initialPermission](value),\n ];\n }\n\n // If we have no mapping, this may be a non-snap permission, return as-is\n return [\n initialPermission,\n value as Pick<PermissionConstraint, 'caveats'>,\n ];\n }),\n );\n}\n\nexport const buildSnapEndowmentSpecifications = (\n excludedEndowments: string[],\n) =>\n Object.values(endowmentPermissionBuilders).reduce<\n Record<string, PermissionSpecificationConstraint>\n >((allSpecifications, { targetName, specificationBuilder }) => {\n if (!excludedEndowments.includes(targetName)) {\n allSpecifications[targetName] = specificationBuilder({});\n }\n return allSpecifications;\n }, {});\n\nexport const buildSnapRestrictedMethodSpecifications = (\n excludedPermissions: string[],\n hooks: Record<string, unknown>,\n) =>\n Object.values(restrictedMethodPermissionBuilders).reduce<\n Record<string, PermissionSpecificationConstraint>\n >((specifications, { targetName, specificationBuilder, methodHooks }) => {\n if (!excludedPermissions.includes(targetName)) {\n specifications[targetName] = specificationBuilder({\n // @ts-expect-error The selectHooks type is wonky\n methodHooks: selectHooks<typeof hooks, keyof typeof methodHooks>(\n hooks,\n methodHooks,\n ) as Pick<typeof hooks, keyof typeof methodHooks>,\n });\n }\n return specifications;\n }, {});\n"],"names":["caveatMappers","restrictedMethodPermissionBuilders","selectHooks","hasProperty","endowmentCaveatMappers","endowmentPermissionBuilders","processSnapPermissions","initialPermissions","Object","fromEntries","entries","map","initialPermission","value","buildSnapEndowmentSpecifications","excludedEndowments","values","reduce","allSpecifications","targetName","specificationBuilder","includes","buildSnapRestrictedMethodSpecifications","excludedPermissions","hooks","specifications","methodHooks"],"mappings":"AAIA,SACEA,aAAa,EACbC,kCAAkC,EAClCC,WAAW,QACN,8BAA8B;AAErC,SAASC,WAAW,QAAQ,kBAAkB;AAE9C,SACEC,sBAAsB,EACtBC,2BAA2B,QACtB,eAAe;AAEtB;;;;;;;;;;CAUC,GACD,OAAO,SAASC,uBACdC,kBAAmC;IAEnC,OAAOC,OAAOC,WAAW,CACvBD,OAAOE,OAAO,CAACH,oBAAoBI,GAAG,CAAC,CAAC,CAACC,mBAAmBC,MAAM;QAChE,IAAIV,YAAYH,eAAeY,oBAAoB;YACjD,OAAO;gBAACA;gBAAmBZ,aAAa,CAACY,kBAAkB,CAACC;aAAO;QACrE,OAAO,IAAIV,YAAYC,wBAAwBQ,oBAAoB;YACjE,OAAO;gBACLA;gBACAR,sBAAsB,CAACQ,kBAAkB,CAACC;aAC3C;QACH;QAEA,yEAAyE;QACzE,OAAO;YACLD;YACAC;SACD;IACH;AAEJ;AAEA,OAAO,MAAMC,mCAAmC,CAC9CC,qBAEAP,OAAOQ,MAAM,CAACX,6BAA6BY,MAAM,CAE/C,CAACC,mBAAmB,EAAEC,UAAU,EAAEC,oBAAoB,EAAE;QACxD,IAAI,CAACL,mBAAmBM,QAAQ,CAACF,aAAa;YAC5CD,iBAAiB,CAACC,WAAW,GAAGC,qBAAqB,CAAC;QACxD;QACA,OAAOF;IACT,GAAG,CAAC,GAAG;AAET,OAAO,MAAMI,0CAA0C,CACrDC,qBACAC,QAEAhB,OAAOQ,MAAM,CAACf,oCAAoCgB,MAAM,CAEtD,CAACQ,gBAAgB,EAAEN,UAAU,EAAEC,oBAAoB,EAAEM,WAAW,EAAE;QAClE,IAAI,CAACH,oBAAoBF,QAAQ,CAACF,aAAa;YAC7CM,cAAc,CAACN,WAAW,GAAGC,qBAAqB;gBAChD,iDAAiD;gBACjDM,aAAaxB,YACXsB,OACAE;YAEJ;QACF;QACA,OAAOD;IACT,GAAG,CAAC,GAAG"}
|
|
@@ -50,7 +50,8 @@ function _class_private_method_init(obj, privateSet) {
|
|
|
50
50
|
}
|
|
51
51
|
import { BaseControllerV2 as BaseController } from '@metamask/base-controller';
|
|
52
52
|
import { verify } from '@metamask/snaps-registry';
|
|
53
|
-
import {
|
|
53
|
+
import { getTargetVersion } from '@metamask/snaps-utils';
|
|
54
|
+
import { assert, assertIsSemVerRange, Duration, inMilliseconds, satisfiesVersionRange } from '@metamask/utils';
|
|
54
55
|
import { SnapsRegistryStatus } from './registry';
|
|
55
56
|
// TODO: Replace with a Codefi URL
|
|
56
57
|
const SNAP_REGISTRY_URL = 'https://cdn.jsdelivr.net/gh/MetaMask/snaps-registry@gh-pages/latest/registry.json';
|
|
@@ -60,7 +61,7 @@ const defaultState = {
|
|
|
60
61
|
database: null,
|
|
61
62
|
lastUpdated: null
|
|
62
63
|
};
|
|
63
|
-
var _url = /*#__PURE__*/ new WeakMap(), _publicKey = /*#__PURE__*/ new WeakMap(), _fetchFunction = /*#__PURE__*/ new WeakMap(), _recentFetchThreshold = /*#__PURE__*/ new WeakMap(), _refetchOnAllowlistMiss = /*#__PURE__*/ new WeakMap(), _failOnUnavailableRegistry = /*#__PURE__*/ new WeakMap(), _currentUpdate = /*#__PURE__*/ new WeakMap(), _wasRecentlyFetched = /*#__PURE__*/ new WeakSet(), _triggerUpdate = /*#__PURE__*/ new WeakSet(), _update = /*#__PURE__*/ new WeakSet(), _getDatabase = /*#__PURE__*/ new WeakSet(), _getSingle = /*#__PURE__*/ new WeakSet(), _get = /*#__PURE__*/ new WeakSet(), _getMetadata = /*#__PURE__*/ new WeakSet(), _verifySignature = /*#__PURE__*/ new WeakSet(), _safeFetch = /*#__PURE__*/ new WeakSet();
|
|
64
|
+
var _url = /*#__PURE__*/ new WeakMap(), _publicKey = /*#__PURE__*/ new WeakMap(), _fetchFunction = /*#__PURE__*/ new WeakMap(), _recentFetchThreshold = /*#__PURE__*/ new WeakMap(), _refetchOnAllowlistMiss = /*#__PURE__*/ new WeakMap(), _failOnUnavailableRegistry = /*#__PURE__*/ new WeakMap(), _currentUpdate = /*#__PURE__*/ new WeakMap(), _wasRecentlyFetched = /*#__PURE__*/ new WeakSet(), _triggerUpdate = /*#__PURE__*/ new WeakSet(), _update = /*#__PURE__*/ new WeakSet(), _getDatabase = /*#__PURE__*/ new WeakSet(), _getSingle = /*#__PURE__*/ new WeakSet(), _get = /*#__PURE__*/ new WeakSet(), _resolveVersion = /*#__PURE__*/ new WeakSet(), _getMetadata = /*#__PURE__*/ new WeakSet(), _verifySignature = /*#__PURE__*/ new WeakSet(), _safeFetch = /*#__PURE__*/ new WeakSet();
|
|
64
65
|
export class JsonSnapsRegistry extends BaseController {
|
|
65
66
|
constructor({ messenger, state, url = {
|
|
66
67
|
registry: SNAP_REGISTRY_URL,
|
|
@@ -99,6 +100,15 @@ export class JsonSnapsRegistry extends BaseController {
|
|
|
99
100
|
_class_private_method_init(this, _getSingle);
|
|
100
101
|
_class_private_method_init(this, _get);
|
|
101
102
|
/**
|
|
103
|
+
* Find an allowlisted version within a specified version range.
|
|
104
|
+
*
|
|
105
|
+
* @param snapId - The ID of the snap we are trying to resolve a version for.
|
|
106
|
+
* @param versionRange - The version range.
|
|
107
|
+
* @param refetch - An optional flag used to determine if we are refetching the registry.
|
|
108
|
+
* @returns An allowlisted version within the specified version range.
|
|
109
|
+
* @throws If an allowlisted version does not exist within the version range.
|
|
110
|
+
*/ _class_private_method_init(this, _resolveVersion);
|
|
111
|
+
/**
|
|
102
112
|
* Get metadata for the given snap ID.
|
|
103
113
|
*
|
|
104
114
|
* @param snapId - The ID of the snap to get metadata for.
|
|
@@ -157,6 +167,7 @@ export class JsonSnapsRegistry extends BaseController {
|
|
|
157
167
|
_class_private_field_set(this, _currentUpdate, null);
|
|
158
168
|
this.messagingSystem.registerActionHandler('SnapsRegistry:get', async (...args)=>_class_private_method_get(this, _get, get).call(this, ...args));
|
|
159
169
|
this.messagingSystem.registerActionHandler('SnapsRegistry:getMetadata', async (...args)=>_class_private_method_get(this, _getMetadata, getMetadata).call(this, ...args));
|
|
170
|
+
this.messagingSystem.registerActionHandler('SnapsRegistry:resolveVersion', async (...args)=>_class_private_method_get(this, _resolveVersion, resolveVersion).call(this, ...args));
|
|
160
171
|
this.messagingSystem.registerActionHandler('SnapsRegistry:update', async ()=>_class_private_method_get(this, _triggerUpdate, triggerUpdate).call(this));
|
|
161
172
|
}
|
|
162
173
|
}
|
|
@@ -243,6 +254,24 @@ async function get(snaps) {
|
|
|
243
254
|
return acc;
|
|
244
255
|
}, Promise.resolve({}));
|
|
245
256
|
}
|
|
257
|
+
async function resolveVersion(snapId, versionRange, refetch = false) {
|
|
258
|
+
const database = await _class_private_method_get(this, _getDatabase, getDatabase).call(this);
|
|
259
|
+
const versions = database?.verifiedSnaps[snapId]?.versions ?? null;
|
|
260
|
+
if (!versions && _class_private_field_get(this, _refetchOnAllowlistMiss) && !refetch) {
|
|
261
|
+
await _class_private_method_get(this, _triggerUpdate, triggerUpdate).call(this);
|
|
262
|
+
return _class_private_method_get(this, _resolveVersion, resolveVersion).call(this, snapId, versionRange, true);
|
|
263
|
+
}
|
|
264
|
+
assert(versions, 'The snap is not on the allowlist');
|
|
265
|
+
const targetVersion = getTargetVersion(Object.keys(versions), versionRange);
|
|
266
|
+
if (!targetVersion && _class_private_field_get(this, _refetchOnAllowlistMiss) && !refetch) {
|
|
267
|
+
await _class_private_method_get(this, _triggerUpdate, triggerUpdate).call(this);
|
|
268
|
+
return _class_private_method_get(this, _resolveVersion, resolveVersion).call(this, snapId, versionRange, true);
|
|
269
|
+
}
|
|
270
|
+
assert(targetVersion, 'No matching versions of the snap are on the allowlist');
|
|
271
|
+
// A semver version is technically also a valid semver range.
|
|
272
|
+
assertIsSemVerRange(targetVersion);
|
|
273
|
+
return targetVersion;
|
|
274
|
+
}
|
|
246
275
|
async function getMetadata(snapId) {
|
|
247
276
|
const database = await _class_private_method_get(this, _getDatabase, getDatabase).call(this);
|
|
248
277
|
return database?.verifiedSnaps[snapId]?.metadata ?? null;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/snaps/registry/json.ts"],"sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseControllerV2 as BaseController } from '@metamask/base-controller';\nimport type { SnapsRegistryDatabase } from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport type { SnapId } from '@metamask/snaps-utils';\nimport type { Hex } from '@metamask/utils';\nimport {\n assert,\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\n// TODO: Replace with a Codefi URL\nconst SNAP_REGISTRY_URL =\n 'https://cdn.jsdelivr.net/gh/MetaMask/snaps-registry@gh-pages/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://cdn.jsdelivr.net/gh/MetaMask/snaps-registry@gh-pages/latest/signature.json';\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 failOnUnavailableRegistry?: boolean;\n publicKey?: Hex;\n};\n\nexport type GetResult = {\n type: `${typeof controllerName}:get`;\n handler: SnapsRegistry['get'];\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 SnapsRegistryActions = GetResult | GetMetadata | Update;\n\nexport type SnapsRegistryEvents = never;\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};\n\nconst controllerName = 'SnapsRegistry';\n\nconst defaultState = {\n database: null,\n lastUpdated: null,\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 #failOnUnavailableRegistry: 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,\n fetchFunction = globalThis.fetch.bind(globalThis),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n failOnUnavailableRegistry = true,\n refetchOnAllowlistMiss = true,\n }: JsonSnapsRegistryArgs) {\n super({\n messenger,\n metadata: {\n database: { persist: true, anonymous: false },\n lastUpdated: { 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.#failOnUnavailableRegistry = failOnUnavailableRegistry;\n this.#currentUpdate = null;\n\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:get',\n async (...args) => this.#get(...args),\n );\n this.messagingSystem.registerActionHandler(\n 'SnapsRegistry:getMetadata',\n async (...args) => this.#getMetadata(...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 if (this.#publicKey) {\n const signature = await this.#safeFetch(this.#url.signature);\n await this.#verifySignature(database, signature);\n }\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n });\n } catch {\n // Ignore\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.#triggerUpdate();\n }\n\n // If the database is still null and we require it, throw.\n if (this.#failOnUnavailableRegistry && this.state.database === null) {\n throw new Error('Snaps registry is unavailable, installation blocked.');\n }\n return this.state.database;\n }\n\n async #getSingle(\n snapId: SnapId,\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 { status: SnapsRegistryStatus.Unverified };\n }\n\n async #get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<SnapId, SnapsRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<SnapId, 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 * 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: SnapId): 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 async #verifySignature(database: string, signature: string) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = await 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"],"names":["BaseControllerV2","BaseController","verify","assert","Duration","inMilliseconds","satisfiesVersionRange","SnapsRegistryStatus","SNAP_REGISTRY_URL","SNAP_REGISTRY_SIGNATURE_URL","controllerName","defaultState","database","lastUpdated","JsonSnapsRegistry","constructor","messenger","state","url","registry","signature","publicKey","fetchFunction","globalThis","fetch","bind","recentFetchThreshold","Minute","failOnUnavailableRegistry","refetchOnAllowlistMiss","metadata","persist","anonymous","name","currentUpdate","messagingSystem","registerActionHandler","args","get","getMetadata","triggerUpdate","Date","now","update","wasRecentlyFetched","safeFetch","verifySignature","JSON","parse","Error","snapId","snapInfo","refetch","getDatabase","blockedEntry","blockedSnaps","find","blocked","id","version","versionRange","checksum","status","Blocked","reason","verified","verifiedSnaps","versions","Verified","getSingle","Unverified","snaps","Object","entries","reduce","previousPromise","result","acc","Promise","resolve","valid","response","ok","text"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/snaps/registry/json.ts"],"sourcesContent":["import type { RestrictedControllerMessenger } from '@metamask/base-controller';\nimport { BaseControllerV2 as BaseController } from '@metamask/base-controller';\nimport type { SnapsRegistryDatabase } from '@metamask/snaps-registry';\nimport { verify } from '@metamask/snaps-registry';\nimport { getTargetVersion, type SnapId } 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\n// TODO: Replace with a Codefi URL\nconst SNAP_REGISTRY_URL =\n 'https://cdn.jsdelivr.net/gh/MetaMask/snaps-registry@gh-pages/latest/registry.json';\n\nconst SNAP_REGISTRY_SIGNATURE_URL =\n 'https://cdn.jsdelivr.net/gh/MetaMask/snaps-registry@gh-pages/latest/signature.json';\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 failOnUnavailableRegistry?: 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 SnapsRegistryActions =\n | GetResult\n | GetMetadata\n | Update\n | ResolveVersion;\n\nexport type SnapsRegistryEvents = never;\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};\n\nconst controllerName = 'SnapsRegistry';\n\nconst defaultState = {\n database: null,\n lastUpdated: null,\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 #failOnUnavailableRegistry: 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,\n fetchFunction = globalThis.fetch.bind(globalThis),\n recentFetchThreshold = inMilliseconds(5, Duration.Minute),\n failOnUnavailableRegistry = true,\n refetchOnAllowlistMiss = true,\n }: JsonSnapsRegistryArgs) {\n super({\n messenger,\n metadata: {\n database: { persist: true, anonymous: false },\n lastUpdated: { 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.#failOnUnavailableRegistry = failOnUnavailableRegistry;\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 if (this.#publicKey) {\n const signature = await this.#safeFetch(this.#url.signature);\n await this.#verifySignature(database, signature);\n }\n\n this.update((state) => {\n state.database = JSON.parse(database);\n state.lastUpdated = Date.now();\n });\n } catch {\n // Ignore\n }\n }\n\n async #getDatabase(): Promise<SnapsRegistryDatabase | null> {\n if (this.state.database === null) {\n await this.#triggerUpdate();\n }\n\n // If the database is still null and we require it, throw.\n if (this.#failOnUnavailableRegistry && this.state.database === null) {\n throw new Error('Snaps registry is unavailable, installation blocked.');\n }\n return this.state.database;\n }\n\n async #getSingle(\n snapId: SnapId,\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 { status: SnapsRegistryStatus.Unverified };\n }\n\n async #get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<SnapId, SnapsRegistryResult>> {\n return Object.entries(snaps).reduce<\n Promise<Record<SnapId, 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.\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.\n * @throws If an allowlisted version does not exist within the version range.\n */\n async #resolveVersion(\n snapId: SnapId,\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 assert(versions, 'The snap is not on the allowlist');\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 assert(\n targetVersion,\n 'No matching versions of the snap are on the allowlist',\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: SnapId): 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 async #verifySignature(database: string, signature: string) {\n assert(this.#publicKey, 'No public key provided.');\n\n const valid = await 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"],"names":["BaseControllerV2","BaseController","verify","getTargetVersion","assert","assertIsSemVerRange","Duration","inMilliseconds","satisfiesVersionRange","SnapsRegistryStatus","SNAP_REGISTRY_URL","SNAP_REGISTRY_SIGNATURE_URL","controllerName","defaultState","database","lastUpdated","JsonSnapsRegistry","constructor","messenger","state","url","registry","signature","publicKey","fetchFunction","globalThis","fetch","bind","recentFetchThreshold","Minute","failOnUnavailableRegistry","refetchOnAllowlistMiss","metadata","persist","anonymous","name","currentUpdate","messagingSystem","registerActionHandler","args","get","getMetadata","resolveVersion","triggerUpdate","Date","now","update","wasRecentlyFetched","safeFetch","verifySignature","JSON","parse","Error","snapId","snapInfo","refetch","getDatabase","blockedEntry","blockedSnaps","find","blocked","id","version","versionRange","checksum","status","Blocked","reason","verified","verifiedSnaps","versions","Verified","getSingle","Unverified","snaps","Object","entries","reduce","previousPromise","result","acc","Promise","resolve","targetVersion","keys","valid","response","ok","text"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/snaps/registry/registry.ts"],"sourcesContent":["import type {\n BlockReason,\n SnapsRegistryDatabase,\n} from '@metamask/snaps-registry';\nimport type { SnapId, ValidatedSnapId } from '@metamask/snaps-utils';\nimport type { SemVerVersion } from '@metamask/utils';\n\nexport type SnapsRegistryInfo = { version: SemVerVersion; checksum: string };\nexport type SnapsRegistryRequest = Record<SnapId, SnapsRegistryInfo>;\nexport type SnapsRegistryMetadata =\n SnapsRegistryDatabase['verifiedSnaps'][ValidatedSnapId]['metadata'];\n\n// TODO: Decide on names for these\nexport enum SnapsRegistryStatus {\n Unverified = 0,\n Blocked = 1,\n Verified = 2,\n}\n\nexport type SnapsRegistryResult = {\n status: SnapsRegistryStatus;\n reason?: BlockReason;\n};\n\nexport type SnapsRegistry = {\n get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<ValidatedSnapId, SnapsRegistryResult>>;\n\n update(): Promise<void>;\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 getMetadata(snapId: SnapId): Promise<SnapsRegistryMetadata | null>;\n};\n"],"names":["SnapsRegistryStatus","Unverified","Blocked","Verified"],"mappings":"WAaO;UAAKA,mBAAmB;IAAnBA,oBAAAA,oBACVC,gBAAa,KAAbA;IADUD,oBAAAA,oBAEVE,aAAU,KAAVA;IAFUF,oBAAAA,oBAGVG,cAAW,KAAXA;GAHUH,wBAAAA"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/snaps/registry/registry.ts"],"sourcesContent":["import type {\n BlockReason,\n SnapsRegistryDatabase,\n} from '@metamask/snaps-registry';\nimport type { SnapId, ValidatedSnapId } from '@metamask/snaps-utils';\nimport type { SemVerRange, SemVerVersion } from '@metamask/utils';\n\nexport type SnapsRegistryInfo = { version: SemVerVersion; checksum: string };\nexport type SnapsRegistryRequest = Record<SnapId, SnapsRegistryInfo>;\nexport type SnapsRegistryMetadata =\n SnapsRegistryDatabase['verifiedSnaps'][ValidatedSnapId]['metadata'];\n\n// TODO: Decide on names for these\nexport enum SnapsRegistryStatus {\n Unverified = 0,\n Blocked = 1,\n Verified = 2,\n}\n\nexport type SnapsRegistryResult = {\n status: SnapsRegistryStatus;\n reason?: BlockReason;\n};\n\nexport type SnapsRegistry = {\n get(\n snaps: SnapsRegistryRequest,\n ): Promise<Record<ValidatedSnapId, SnapsRegistryResult>>;\n\n update(): Promise<void>;\n\n /**\n * Find an allowlisted version within a specified version range.\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.\n * @throws If an allowlisted version does not exist within the version range.\n */\n resolveVersion(\n snapId: SnapId,\n versionRange: SemVerRange,\n ): Promise<SemVerRange>;\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 getMetadata(snapId: SnapId): Promise<SnapsRegistryMetadata | null>;\n};\n"],"names":["SnapsRegistryStatus","Unverified","Blocked","Verified"],"mappings":"WAaO;UAAKA,mBAAmB;IAAnBA,oBAAAA,oBACVC,gBAAa,KAAbA;IADUD,oBAAAA,oBAEVE,aAAU,KAAVA;IAFUF,oBAAAA,oBAGVG,cAAW,KAAXA;GAHUH,wBAAAA"}
|
|
@@ -88,7 +88,7 @@ export declare class CronjobController extends BaseController<typeof controllerN
|
|
|
88
88
|
/**
|
|
89
89
|
* Runs every 24 hours to check if new jobs need to be scheduled.
|
|
90
90
|
*
|
|
91
|
-
* This is
|
|
91
|
+
* This is necessary for longer running jobs that execute with more than 24 hours between them.
|
|
92
92
|
*/
|
|
93
93
|
dailyCheckIn(): Promise<void>;
|
|
94
94
|
/**
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
|
+
import { JsonRpcEngine } from '@metamask/json-rpc-engine';
|
|
2
3
|
import ObjectMultiplex from '@metamask/object-multiplex';
|
|
3
4
|
import type { BasePostMessageStream } from '@metamask/post-message-stream';
|
|
4
5
|
import type { SnapRpcHookArgs } from '@metamask/snaps-utils';
|
|
5
|
-
import { JsonRpcEngine } from 'json-rpc-engine';
|
|
6
6
|
import type { Duplex } from 'stream';
|
|
7
7
|
import type { ExecutionService, ExecutionServiceMessenger, SnapExecutionData } from './ExecutionService';
|
|
8
8
|
export declare type SetupSnapProvider = (snapId: string, stream: Duplex) => void;
|
|
@@ -4,14 +4,14 @@ import { BaseControllerV2 as BaseController } from '@metamask/base-controller';
|
|
|
4
4
|
import type { GetEndowments, GetPermissions, GetSubjectMetadata, GetSubjects, GrantPermissions, HasPermission, HasPermissions, RevokeAllPermissions, RevokePermissionForAllSubjects, RevokePermissions, UpdateCaveat } from '@metamask/permission-controller';
|
|
5
5
|
import type { BlockReason } from '@metamask/snaps-registry';
|
|
6
6
|
import type { InstallSnapsResult, PersistedSnap, RequestedSnapPermissions, Snap, SnapId, SnapRpcHook, SnapRpcHookArgs, StatusContext, StatusEvents, StatusStates, TruncatedSnap, ValidatedSnapId } from '@metamask/snaps-utils';
|
|
7
|
-
import { SnapStatusEvents } from '@metamask/snaps-utils';
|
|
7
|
+
import { AuxiliaryFileEncoding, SnapStatusEvents } from '@metamask/snaps-utils';
|
|
8
8
|
import type { Json, NonEmptyArray } from '@metamask/utils';
|
|
9
9
|
import type { StateMachine } from '@xstate/fsm';
|
|
10
10
|
import type { Patch } from 'immer';
|
|
11
11
|
import type { ExecuteSnapAction, ExecutionServiceEvents, HandleRpcRequestAction, SnapErrorJson, TerminateAllSnapsAction, TerminateSnapAction } from '../services';
|
|
12
12
|
import type { SnapLocation } from './location';
|
|
13
13
|
import { detectSnapLocation } from './location';
|
|
14
|
-
import type { GetMetadata, GetResult, SnapsRegistryMetadata, Update } from './registry';
|
|
14
|
+
import type { GetMetadata, GetResult, ResolveVersion, SnapsRegistryMetadata, Update } from './registry';
|
|
15
15
|
import { Timer } from './Timer';
|
|
16
16
|
export declare const controllerName = "SnapController";
|
|
17
17
|
export declare const SNAP_APPROVAL_INSTALL = "wallet_installSnap";
|
|
@@ -70,11 +70,6 @@ declare type StoredSnaps = Record<ValidatedSnapId, Snap>;
|
|
|
70
70
|
export declare type SnapControllerState = {
|
|
71
71
|
snaps: StoredSnaps;
|
|
72
72
|
snapStates: Record<ValidatedSnapId, string | null>;
|
|
73
|
-
snapErrors: {
|
|
74
|
-
[internalID: string]: SnapError & {
|
|
75
|
-
internalID: string;
|
|
76
|
-
};
|
|
77
|
-
};
|
|
78
73
|
};
|
|
79
74
|
export declare type PersistedSnapControllerState = SnapControllerState & {
|
|
80
75
|
snaps: Record<ValidatedSnapId, PersistedSnap>;
|
|
@@ -161,10 +156,6 @@ export declare type InstallSnaps = {
|
|
|
161
156
|
type: `${typeof controllerName}:install`;
|
|
162
157
|
handler: SnapController['installSnaps'];
|
|
163
158
|
};
|
|
164
|
-
export declare type RemoveSnapError = {
|
|
165
|
-
type: `${typeof controllerName}:removeSnapError`;
|
|
166
|
-
handler: SnapController['removeSnapError'];
|
|
167
|
-
};
|
|
168
159
|
export declare type GetRegistryMetadata = {
|
|
169
160
|
type: `${typeof controllerName}:getRegistryMetadata`;
|
|
170
161
|
handler: SnapController['getRegistryMetadata'];
|
|
@@ -177,7 +168,11 @@ export declare type RevokeDynamicPermissions = {
|
|
|
177
168
|
type: `${typeof controllerName}:revokeDynamicPermissions`;
|
|
178
169
|
handler: SnapController['revokeDynamicSnapPermissions'];
|
|
179
170
|
};
|
|
180
|
-
export declare type
|
|
171
|
+
export declare type GetSnapFile = {
|
|
172
|
+
type: `${typeof controllerName}:getFile`;
|
|
173
|
+
handler: SnapController['getSnapFile'];
|
|
174
|
+
};
|
|
175
|
+
export declare type SnapControllerActions = ClearSnapState | GetSnap | GetSnapState | HandleSnapRequest | HasSnap | UpdateBlockedSnaps | UpdateSnapState | EnableSnap | DisableSnap | RemoveSnap | GetPermittedSnaps | InstallSnaps | GetAllSnaps | IncrementActiveReferences | DecrementActiveReferences | GetRegistryMetadata | DisconnectOrigin | RevokeDynamicPermissions | GetSnapFile;
|
|
181
176
|
export declare type SnapStateChange = {
|
|
182
177
|
type: `${typeof controllerName}:stateChange`;
|
|
183
178
|
payload: [SnapControllerState, Patch[]];
|
|
@@ -202,7 +197,7 @@ export declare type SnapBlocked = {
|
|
|
202
197
|
*/
|
|
203
198
|
export declare type SnapInstalled = {
|
|
204
199
|
type: `${typeof controllerName}:snapInstalled`;
|
|
205
|
-
payload: [snap: TruncatedSnap];
|
|
200
|
+
payload: [snap: TruncatedSnap, origin: string];
|
|
206
201
|
};
|
|
207
202
|
/**
|
|
208
203
|
* Emitted when a snap that has previously been fully installed, is uninstalled.
|
|
@@ -231,7 +226,7 @@ export declare type SnapUnblocked = {
|
|
|
231
226
|
*/
|
|
232
227
|
export declare type SnapUpdated = {
|
|
233
228
|
type: `${typeof controllerName}:snapUpdated`;
|
|
234
|
-
payload: [snap: TruncatedSnap, oldVersion: string];
|
|
229
|
+
payload: [snap: TruncatedSnap, oldVersion: string, origin: string];
|
|
235
230
|
};
|
|
236
231
|
/**
|
|
237
232
|
* Emitted when a snap is rolled back.
|
|
@@ -264,7 +259,7 @@ export declare type SnapDisabled = {
|
|
|
264
259
|
payload: [snap: TruncatedSnap];
|
|
265
260
|
};
|
|
266
261
|
export declare type SnapControllerEvents = SnapAdded | SnapBlocked | SnapInstalled | SnapUninstalled | SnapRemoved | SnapStateChange | SnapUnblocked | SnapUpdated | SnapRolledback | SnapTerminated | SnapEnabled | SnapDisabled;
|
|
267
|
-
export declare type AllowedActions = GetEndowments | GetPermissions | GetSubjects | GetSubjectMetadata | HasPermission | HasPermissions | RevokePermissions | RevokeAllPermissions | RevokePermissionForAllSubjects | GrantPermissions | AddApprovalRequest | HandleRpcRequestAction | ExecuteSnapAction | TerminateAllSnapsAction | TerminateSnapAction | UpdateCaveat | UpdateRequestState | GetResult | GetMetadata | Update;
|
|
262
|
+
export declare type AllowedActions = GetEndowments | GetPermissions | GetSubjects | GetSubjectMetadata | HasPermission | HasPermissions | RevokePermissions | RevokeAllPermissions | RevokePermissionForAllSubjects | GrantPermissions | AddApprovalRequest | HandleRpcRequestAction | ExecuteSnapAction | TerminateAllSnapsAction | TerminateSnapAction | UpdateCaveat | UpdateRequestState | GetResult | GetMetadata | Update | ResolveVersion;
|
|
268
263
|
export declare type AllowedEvents = ExecutionServiceEvents | SnapInstalled | SnapUpdated;
|
|
269
264
|
declare type SnapControllerMessenger = RestrictedControllerMessenger<typeof controllerName, SnapControllerActions | AllowedActions, SnapControllerEvents | AllowedEvents, AllowedActions['type'], AllowedEvents['type']>;
|
|
270
265
|
declare type FeatureFlags = {
|
|
@@ -342,7 +337,7 @@ export declare class SnapController extends BaseController<string, SnapControlle
|
|
|
342
337
|
* for more information.
|
|
343
338
|
*/
|
|
344
339
|
updateBlockedSnaps(): Promise<void>;
|
|
345
|
-
_onUnhandledSnapError(snapId: SnapId,
|
|
340
|
+
_onUnhandledSnapError(snapId: SnapId, _error: SnapErrorJson): void;
|
|
346
341
|
_onOutboundRequest(snapId: SnapId): void;
|
|
347
342
|
_onOutboundResponse(snapId: SnapId): void;
|
|
348
343
|
/**
|
|
@@ -441,22 +436,6 @@ export declare class SnapController extends BaseController<string, SnapControlle
|
|
|
441
436
|
* @param snapId - The id of the Snap whose state should be cleared.
|
|
442
437
|
*/
|
|
443
438
|
clearSnapState(snapId: ValidatedSnapId): void;
|
|
444
|
-
/**
|
|
445
|
-
* Adds error from a snap to the SnapController state.
|
|
446
|
-
*
|
|
447
|
-
* @param snapError - The error to store on the SnapController.
|
|
448
|
-
*/
|
|
449
|
-
addSnapError(snapError: SnapError): void;
|
|
450
|
-
/**
|
|
451
|
-
* Removes an error by internalID from the SnapControllers state.
|
|
452
|
-
*
|
|
453
|
-
* @param internalID - The internal error ID to remove on the SnapController.
|
|
454
|
-
*/
|
|
455
|
-
removeSnapError(internalID: string): void;
|
|
456
|
-
/**
|
|
457
|
-
* Clears all errors from the SnapControllers state.
|
|
458
|
-
*/
|
|
459
|
-
clearSnapErrors(): void;
|
|
460
439
|
/**
|
|
461
440
|
* Gets the own state of the snap with the given id.
|
|
462
441
|
* This is distinct from the state MetaMask uses to manage snaps.
|
|
@@ -466,6 +445,15 @@ export declare class SnapController extends BaseController<string, SnapControlle
|
|
|
466
445
|
* @throws If the snap state decryption fails.
|
|
467
446
|
*/
|
|
468
447
|
getSnapState(snapId: ValidatedSnapId): Promise<Json>;
|
|
448
|
+
/**
|
|
449
|
+
* Gets a static auxiliary snap file in a chosen file encoding.
|
|
450
|
+
*
|
|
451
|
+
* @param snapId - The id of the Snap whose state to get.
|
|
452
|
+
* @param path - The path to the requested file.
|
|
453
|
+
* @param encoding - An optional requested file encoding.
|
|
454
|
+
* @returns The file requested in the chosen file encoding or null if the file is not found.
|
|
455
|
+
*/
|
|
456
|
+
getSnapFile(snapId: ValidatedSnapId, path: string, encoding?: AuxiliaryFileEncoding): string | null;
|
|
469
457
|
/**
|
|
470
458
|
* Completely clear the controller's state: delete all associated data,
|
|
471
459
|
* handlers, event listeners, and permissions; tear down all snap providers.
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { SnapManifest, VirtualFile } from '@metamask/snaps-utils';
|
|
2
|
+
import type { SemVerRange } from '@metamask/utils';
|
|
2
3
|
import type { NpmOptions } from './npm';
|
|
3
4
|
declare module '@metamask/snaps-utils' {
|
|
4
5
|
interface DataMap {
|
|
@@ -31,6 +32,7 @@ export declare type DetectSnapLocationOptions = NpmOptions & {
|
|
|
31
32
|
* @default false
|
|
32
33
|
*/
|
|
33
34
|
allowLocal?: boolean;
|
|
35
|
+
resolveVersion?: (range: SemVerRange) => Promise<SemVerRange>;
|
|
34
36
|
};
|
|
35
37
|
/**
|
|
36
38
|
* Auto-magically detects which SnapLocation object to create based on the provided {@link location}.
|
|
@@ -2,7 +2,7 @@ import type { SnapManifest } from '@metamask/snaps-utils';
|
|
|
2
2
|
import { VirtualFile } from '@metamask/snaps-utils';
|
|
3
3
|
import type { SemVerRange } from '@metamask/utils';
|
|
4
4
|
import type { DetectSnapLocationOptions, SnapLocation } from './location';
|
|
5
|
-
export declare const DEFAULT_NPM_REGISTRY
|
|
5
|
+
export declare const DEFAULT_NPM_REGISTRY: URL;
|
|
6
6
|
export interface NpmOptions {
|
|
7
7
|
/**
|
|
8
8
|
* @default DEFAULT_REQUESTED_SNAP_VERSION
|
|
@@ -21,6 +21,10 @@ export declare type GetResult = {
|
|
|
21
21
|
type: `${typeof controllerName}:get`;
|
|
22
22
|
handler: SnapsRegistry['get'];
|
|
23
23
|
};
|
|
24
|
+
export declare type ResolveVersion = {
|
|
25
|
+
type: `${typeof controllerName}:resolveVersion`;
|
|
26
|
+
handler: SnapsRegistry['resolveVersion'];
|
|
27
|
+
};
|
|
24
28
|
export declare type GetMetadata = {
|
|
25
29
|
type: `${typeof controllerName}:getMetadata`;
|
|
26
30
|
handler: SnapsRegistry['getMetadata'];
|
|
@@ -29,7 +33,7 @@ export declare type Update = {
|
|
|
29
33
|
type: `${typeof controllerName}:update`;
|
|
30
34
|
handler: SnapsRegistry['update'];
|
|
31
35
|
};
|
|
32
|
-
export declare type SnapsRegistryActions = GetResult | GetMetadata | Update;
|
|
36
|
+
export declare type SnapsRegistryActions = GetResult | GetMetadata | Update | ResolveVersion;
|
|
33
37
|
export declare type SnapsRegistryEvents = never;
|
|
34
38
|
export declare type SnapsRegistryMessenger = RestrictedControllerMessenger<'SnapsRegistry', SnapsRegistryActions, SnapsRegistryEvents, SnapsRegistryActions['type'], SnapsRegistryEvents['type']>;
|
|
35
39
|
export declare type SnapsRegistryState = {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BlockReason, SnapsRegistryDatabase } from '@metamask/snaps-registry';
|
|
2
2
|
import type { SnapId, ValidatedSnapId } from '@metamask/snaps-utils';
|
|
3
|
-
import type { SemVerVersion } from '@metamask/utils';
|
|
3
|
+
import type { SemVerRange, SemVerVersion } from '@metamask/utils';
|
|
4
4
|
export declare type SnapsRegistryInfo = {
|
|
5
5
|
version: SemVerVersion;
|
|
6
6
|
checksum: string;
|
|
@@ -19,6 +19,16 @@ export declare type SnapsRegistryResult = {
|
|
|
19
19
|
export declare type SnapsRegistry = {
|
|
20
20
|
get(snaps: SnapsRegistryRequest): Promise<Record<ValidatedSnapId, SnapsRegistryResult>>;
|
|
21
21
|
update(): Promise<void>;
|
|
22
|
+
/**
|
|
23
|
+
* Find an allowlisted version within a specified version range.
|
|
24
|
+
*
|
|
25
|
+
* @param snapId - The ID of the snap we are trying to resolve a version for.
|
|
26
|
+
* @param versionRange - The version range.
|
|
27
|
+
* @param refetch - An optional flag used to determine if we are refetching the registry.
|
|
28
|
+
* @returns An allowlisted version within the specified version range.
|
|
29
|
+
* @throws If an allowlisted version does not exist within the version range.
|
|
30
|
+
*/
|
|
31
|
+
resolveVersion(snapId: SnapId, versionRange: SemVerRange): Promise<SemVerRange>;
|
|
22
32
|
/**
|
|
23
33
|
* Get metadata for the given snap ID.
|
|
24
34
|
*
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@metamask/snaps-controllers",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.1.1",
|
|
4
4
|
"description": "Controllers for MetaMask Snaps.",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -37,32 +37,31 @@
|
|
|
37
37
|
"lint": "yarn lint:eslint && yarn lint:misc --check && yarn lint:changelog && yarn lint:dependencies",
|
|
38
38
|
"lint:fix": "yarn lint:eslint --fix && yarn lint:misc --write",
|
|
39
39
|
"lint:changelog": "../../scripts/validate-changelog.sh @metamask/snaps-controllers",
|
|
40
|
-
"prepare-manifest:preview": "../../scripts/prepare-preview-manifest.sh",
|
|
41
40
|
"publish:preview": "yarn npm publish --tag preview",
|
|
42
41
|
"lint:ci": "yarn lint",
|
|
43
42
|
"lint:dependencies": "depcheck"
|
|
44
43
|
},
|
|
45
44
|
"dependencies": {
|
|
46
|
-
"@metamask/approval-controller": "^
|
|
45
|
+
"@metamask/approval-controller": "^4.0.0",
|
|
47
46
|
"@metamask/base-controller": "^3.2.0",
|
|
47
|
+
"@metamask/json-rpc-engine": "^7.1.1",
|
|
48
48
|
"@metamask/object-multiplex": "^1.2.0",
|
|
49
|
-
"@metamask/permission-controller": "^
|
|
49
|
+
"@metamask/permission-controller": "^5.0.0",
|
|
50
50
|
"@metamask/post-message-stream": "^7.0.0",
|
|
51
|
-
"@metamask/rpc-
|
|
52
|
-
"@metamask/snaps-
|
|
53
|
-
"@metamask/snaps-
|
|
54
|
-
"@metamask/snaps-utils": "^3.
|
|
51
|
+
"@metamask/rpc-errors": "^6.1.0",
|
|
52
|
+
"@metamask/snaps-registry": "^2.1.0",
|
|
53
|
+
"@metamask/snaps-rpc-methods": "^3.1.0",
|
|
54
|
+
"@metamask/snaps-utils": "^3.1.0",
|
|
55
55
|
"@metamask/utils": "^8.1.0",
|
|
56
56
|
"@xstate/fsm": "^2.0.0",
|
|
57
57
|
"concat-stream": "^2.0.0",
|
|
58
|
-
"
|
|
58
|
+
"get-npm-tarball-url": "^2.0.3",
|
|
59
59
|
"gunzip-maybe": "^1.4.2",
|
|
60
60
|
"immer": "^9.0.6",
|
|
61
|
-
"json-rpc-
|
|
62
|
-
"json-rpc-middleware-stream": "^4.2.0",
|
|
61
|
+
"json-rpc-middleware-stream": "^5.0.0",
|
|
63
62
|
"nanoid": "^3.1.31",
|
|
64
63
|
"readable-web-to-node-stream": "^3.0.2",
|
|
65
|
-
"tar-stream": "^
|
|
64
|
+
"tar-stream": "^3.1.6"
|
|
66
65
|
},
|
|
67
66
|
"devDependencies": {
|
|
68
67
|
"@esbuild-plugins/node-globals-polyfill": "^0.2.3",
|
|
@@ -84,17 +83,17 @@
|
|
|
84
83
|
"@types/mocha": "^10.0.1",
|
|
85
84
|
"@types/node": "18.14.2",
|
|
86
85
|
"@types/readable-stream": "^2.3.15",
|
|
87
|
-
"@types/tar-stream": "^
|
|
86
|
+
"@types/tar-stream": "^3.1.1",
|
|
88
87
|
"@typescript-eslint/eslint-plugin": "^5.42.1",
|
|
89
88
|
"@typescript-eslint/parser": "^5.42.1",
|
|
90
|
-
"@wdio/browser-runner": "^8.
|
|
91
|
-
"@wdio/cli": "^8.
|
|
92
|
-
"@wdio/globals": "^8.
|
|
93
|
-
"@wdio/mocha-framework": "^8.
|
|
94
|
-
"@wdio/spec-reporter": "^8.
|
|
95
|
-
"@wdio/static-server-service": "^8.
|
|
89
|
+
"@wdio/browser-runner": "^8.19.0",
|
|
90
|
+
"@wdio/cli": "^8.19.0",
|
|
91
|
+
"@wdio/globals": "^8.19.0",
|
|
92
|
+
"@wdio/mocha-framework": "^8.19.0",
|
|
93
|
+
"@wdio/spec-reporter": "^8.19.0",
|
|
94
|
+
"@wdio/static-server-service": "^8.19.0",
|
|
96
95
|
"deepmerge": "^4.2.2",
|
|
97
|
-
"depcheck": "^1.4.
|
|
96
|
+
"depcheck": "^1.4.7",
|
|
98
97
|
"esbuild": "^0.18.10",
|
|
99
98
|
"eslint": "^8.27.0",
|
|
100
99
|
"eslint-config-prettier": "^8.5.0",
|
|
@@ -104,7 +103,7 @@
|
|
|
104
103
|
"eslint-plugin-n": "^15.7.0",
|
|
105
104
|
"eslint-plugin-prettier": "^4.2.1",
|
|
106
105
|
"eslint-plugin-promise": "^6.1.1",
|
|
107
|
-
"expect-webdriverio": "^4.1
|
|
106
|
+
"expect-webdriverio": "^4.4.1",
|
|
108
107
|
"istanbul-lib-coverage": "^3.2.0",
|
|
109
108
|
"istanbul-lib-report": "^3.0.0",
|
|
110
109
|
"istanbul-reports": "^3.1.5",
|
|
@@ -120,7 +119,15 @@
|
|
|
120
119
|
"vite-tsconfig-paths": "^4.0.5",
|
|
121
120
|
"wdio-chromedriver-service": "^8.1.1",
|
|
122
121
|
"wdio-geckodriver-service": "^5.0.2",
|
|
123
|
-
"webdriverio": "^8.
|
|
122
|
+
"webdriverio": "^8.19.0"
|
|
123
|
+
},
|
|
124
|
+
"peerDependencies": {
|
|
125
|
+
"@metamask/snaps-execution-environments": "^3.1.0"
|
|
126
|
+
},
|
|
127
|
+
"peerDependenciesMeta": {
|
|
128
|
+
"@metamask/snaps-execution-environments": {
|
|
129
|
+
"optional": true
|
|
130
|
+
}
|
|
124
131
|
},
|
|
125
132
|
"engines": {
|
|
126
133
|
"node": "^18.16 || >=20"
|