@metamask/snaps-controllers 0.28.0 → 0.30.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.
@@ -21,7 +21,7 @@ var __rest = (this && this.__rest) || function (s, e) {
21
21
  }
22
22
  return t;
23
23
  };
24
- var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_registry, _SnapController_maxIdleTime, _SnapController_detectSnapLocation, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_fetchSnap, _SnapController_processSnapPermissions, _SnapController_getRpcRequestHandler, _SnapController_executeWithTimeout, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRollbackSnapshot, _SnapController_createRollbackSnapshot, _SnapController_rollbackSnap, _SnapController_rollbackSnaps, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange, _SnapController_isValidUpdate;
24
+ var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_registry, _SnapController_maxIdleTime, _SnapController_detectSnapLocation, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_removeSnapFromSubjects, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_fetchSnap, _SnapController_processSnapPermissions, _SnapController_getRpcRequestHandler, _SnapController_executeWithTimeout, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRollbackSnapshot, _SnapController_createRollbackSnapshot, _SnapController_rollbackSnap, _SnapController_rollbackSnaps, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange, _SnapController_isValidUpdate;
25
25
  Object.defineProperty(exports, "__esModule", { value: true });
26
26
  exports.SnapController = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
27
27
  const base_controller_1 = require("@metamask/base-controller");
@@ -33,6 +33,7 @@ const fsm_1 = require("@xstate/fsm");
33
33
  const eth_rpc_errors_1 = require("eth-rpc-errors");
34
34
  const nanoid_1 = require("nanoid");
35
35
  const fsm_2 = require("../fsm");
36
+ const logging_1 = require("../logging");
36
37
  const utils_2 = require("../utils");
37
38
  const endowments_1 = require("./endowments");
38
39
  const rpc_1 = require("./endowments/rpc");
@@ -47,7 +48,6 @@ exports.SNAP_APPROVAL_UPDATE = 'wallet_updateSnap';
47
48
  const TRUNCATED_SNAP_PROPERTIES = new Set([
48
49
  'initialPermissions',
49
50
  'id',
50
- 'permissionName',
51
51
  'version',
52
52
  'enabled',
53
53
  'blocked',
@@ -192,7 +192,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
192
192
  .then(() => this.addSnapError(error))
193
193
  .catch((stopSnapError) => {
194
194
  // TODO: Decide how to handle errors.
195
- console.error(stopSnapError);
195
+ (0, snaps_utils_1.logError)(stopSnapError);
196
196
  });
197
197
  }
198
198
  _onOutboundRequest(snapId) {
@@ -464,9 +464,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
464
464
  // affect the host environment while we are deleting it.
465
465
  await this.disableSnap(snapId);
466
466
  this.revokeAllSnapPermissions(snapId);
467
- const permissionName = (0, snaps_utils_1.getSnapPermissionName)(snapId);
468
- // Revoke all subjects access to the snap
469
- this.messagingSystem.call('PermissionController:revokePermissionForAllSubjects', permissionName);
467
+ __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_removeSnapFromSubjects).call(this, snapId);
470
468
  this.snapsRuntimeData.delete(snapId);
471
469
  this.update((state) => {
472
470
  delete state.snaps[snapId];
@@ -519,15 +517,14 @@ class SnapController extends base_controller_1.BaseControllerV2 {
519
517
  * @returns The serialized permitted snaps for the origin.
520
518
  */
521
519
  getPermittedSnaps(origin) {
522
- var _a;
523
- return Object.values((_a = this.messagingSystem.call('PermissionController:getPermissions', origin)) !== null && _a !== void 0 ? _a : {}).reduce((permittedSnaps, perm) => {
524
- if (perm.parentCapability.startsWith(snaps_utils_1.SNAP_PREFIX)) {
525
- const snapId = perm.parentCapability.replace(snaps_utils_1.SNAP_PREFIX_REGEX, '');
526
- const snap = this.get(snapId);
527
- const truncatedSnap = this.getTruncated(snapId);
528
- if (truncatedSnap && (snap === null || snap === void 0 ? void 0 : snap.status) !== snaps_utils_1.SnapStatus.Installing) {
529
- permittedSnaps[snapId] = truncatedSnap;
530
- }
520
+ var _a, _b, _c, _d, _e;
521
+ const permissions = (_a = this.messagingSystem.call('PermissionController:getPermissions', origin)) !== null && _a !== void 0 ? _a : {};
522
+ const snaps = (_e = (_d = (_c = (_b = permissions[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]) === null || _b === void 0 ? void 0 : _b.caveats) === null || _c === void 0 ? void 0 : _c.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds)) === null || _d === void 0 ? void 0 : _d.value) !== null && _e !== void 0 ? _e : {};
523
+ return Object.keys(snaps).reduce((permittedSnaps, snapId) => {
524
+ const snap = this.get(snapId);
525
+ const truncatedSnap = this.getTruncated(snapId);
526
+ if (truncatedSnap && (snap === null || snap === void 0 ? void 0 : snap.status) !== snaps_utils_1.SnapStatus.Installing) {
527
+ permittedSnaps[snapId] = truncatedSnap;
531
528
  }
532
529
  return permittedSnaps;
533
530
  }, {});
@@ -555,8 +552,8 @@ class SnapController extends base_controller_1.BaseControllerV2 {
555
552
  if (error) {
556
553
  throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${rawVersion}".`);
557
554
  }
558
- const permissionName = (0, snaps_utils_1.getSnapPermissionName)(snapId);
559
- if (!this.messagingSystem.call('PermissionController:hasPermission', origin, permissionName)) {
555
+ const permissions = this.messagingSystem.call('PermissionController:getPermissions', origin);
556
+ if (!(0, snaps_utils_1.isSnapPermitted)(permissions, snapId)) {
560
557
  throw eth_rpc_errors_1.ethErrors.provider.unauthorized(`Not authorized to install snap "${snapId}". Request the permission for the snap before attempting to install it.`);
561
558
  }
562
559
  const isUpdate = pendingUpdates.includes(snapId);
@@ -637,7 +634,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
637
634
  return truncated;
638
635
  }
639
636
  catch (error) {
640
- console.error(`Error when adding snap.`, error);
637
+ (0, snaps_utils_1.logError)(`Error when adding snap.`, error);
641
638
  throw error;
642
639
  }
643
640
  }
@@ -668,7 +665,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
668
665
  const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
669
666
  const newVersion = newSnap.manifest.result.version;
670
667
  if (!(0, utils_1.gtVersion)(newVersion, snap.version)) {
671
- console.warn(`Tried updating snap "${snapId}" within "${newVersionRange}" version range, but newer version "${snap.version}" is already installed`);
668
+ (0, snaps_utils_1.logWarning)(`Tried updating snap "${snapId}" within "${newVersionRange}" version range, but newer version "${snap.version}" is already installed`);
672
669
  return null;
673
670
  }
674
671
  await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
@@ -724,9 +721,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
724
721
  rollbackSnapshot.permissions.granted = Object.keys(approvedNewPermissions);
725
722
  rollbackSnapshot.permissions.requestData = requestData;
726
723
  }
724
+ const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(newSnap.manifest.result.source.location.npm.filePath);
727
725
  const sourceCode = (_a = newSnap.files
728
- .find((file) => file.path === newSnap.manifest.result.source.location.npm.filePath)) === null || _a === void 0 ? void 0 : _a.toString();
729
- (0, utils_1.assert)(sourceCode !== undefined);
726
+ .find((file) => file.path === normalizedSourcePath)) === null || _a === void 0 ? void 0 : _a.toString();
727
+ (0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
730
728
  try {
731
729
  await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
732
730
  }
@@ -737,6 +735,16 @@ class SnapController extends base_controller_1.BaseControllerV2 {
737
735
  this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
738
736
  return truncatedSnap;
739
737
  }
738
+ /**
739
+ * Get metadata for the given snap ID.
740
+ *
741
+ * @param snapId - The ID of the snap to get metadata for.
742
+ * @returns The metadata for the given snap ID, or `null` if the snap is not
743
+ * verified.
744
+ */
745
+ async getRegistryMetadata(snapId) {
746
+ return await __classPrivateFieldGet(this, _SnapController_registry, "f").getMetadata(snapId);
747
+ }
740
748
  /**
741
749
  * Initiates a request for the given snap's initial permissions.
742
750
  * Must be called in order. See processRequestedSnap.
@@ -748,7 +756,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
748
756
  * @returns The snap's approvedPermissions.
749
757
  */
750
758
  async authorize(origin, snapId) {
751
- console.info(`Authorizing snap: ${snapId}`);
759
+ (0, logging_1.log)(`Authorizing snap: ${snapId}`);
752
760
  const snapsState = this.state.snaps;
753
761
  const snap = snapsState[snapId];
754
762
  const { initialPermissions } = snap;
@@ -901,11 +909,12 @@ _SnapController_closeAllConnections = new WeakMap(), _SnapController_environment
901
909
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:getAll`, (...args) => this.getAllSnaps(...args));
902
910
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:incrementActiveReferences`, (...args) => this.incrementActiveReferences(...args));
903
911
  this.messagingSystem.registerActionHandler(`${exports.controllerName}:decrementActiveReferences`, (...args) => this.decrementActiveReferences(...args));
912
+ this.messagingSystem.registerActionHandler(`${exports.controllerName}:getRegistryMetadata`, async (...args) => this.getRegistryMetadata(...args));
904
913
  }, _SnapController_pollForLastRequestStatus = function _SnapController_pollForLastRequestStatus() {
905
914
  __classPrivateFieldSet(this, _SnapController_timeoutForLastRequestStatus, setTimeout(() => {
906
915
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_stopSnapsLastRequestPastMax).call(this).catch((error) => {
907
916
  // TODO: Decide how to handle errors.
908
- console.error(error);
917
+ (0, snaps_utils_1.logError)(error);
909
918
  });
910
919
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_pollForLastRequestStatus).call(this);
911
920
  }, __classPrivateFieldGet(this, _SnapController_idleTimeCheckInterval, "f")), "f");
@@ -929,7 +938,7 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
929
938
  await this.disableSnap(snapId);
930
939
  }
931
940
  catch (error) {
932
- console.error(`Encountered error when stopping blocked snap "${snapId}".`, error);
941
+ (0, snaps_utils_1.logError)(`Encountered error when stopping blocked snap "${snapId}".`, error);
933
942
  }
934
943
  this.messagingSystem.publish(`${exports.controllerName}:snapBlocked`, snapId, blockedSnapInfo);
935
944
  }, _SnapController_unblockSnap = function _SnapController_unblockSnap(snapId) {
@@ -979,6 +988,26 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
979
988
  async function _SnapController_terminateSnap(snapId) {
980
989
  await this.messagingSystem.call('ExecutionService:terminateSnap', snapId);
981
990
  this.messagingSystem.publish('SnapController:snapTerminated', this.getTruncatedExpect(snapId));
991
+ }, _SnapController_removeSnapFromSubjects = function _SnapController_removeSnapFromSubjects(snapId) {
992
+ var _a, _b, _c, _d;
993
+ const subjects = this.messagingSystem.call('PermissionController:getSubjectNames');
994
+ for (const subject of subjects) {
995
+ const subjectPermissions = this.messagingSystem.call('PermissionController:getPermissions', subject);
996
+ const snapIdsCaveat = ((_c = (_b = (_a = subjectPermissions === null || subjectPermissions === void 0 ? void 0 : subjectPermissions[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]) === null || _a === void 0 ? void 0 : _a.caveats) === null || _b === void 0 ? void 0 : _b.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds)) !== null && _c !== void 0 ? _c : {});
997
+ const caveatHasSnap = Boolean((_d = snapIdsCaveat.value) === null || _d === void 0 ? void 0 : _d[snapId]);
998
+ if (caveatHasSnap) {
999
+ const newCaveatValue = Object.assign({}, snapIdsCaveat.value);
1000
+ delete newCaveatValue[snapId];
1001
+ if (Object.keys(newCaveatValue).length > 0) {
1002
+ this.messagingSystem.call('PermissionController:updateCaveat', subject, rpc_methods_1.WALLET_SNAP_PERMISSION_KEY, snaps_utils_1.SnapCaveatType.SnapIds, newCaveatValue);
1003
+ }
1004
+ else {
1005
+ this.messagingSystem.call('PermissionController:revokePermissions', {
1006
+ [subject]: [rpc_methods_1.WALLET_SNAP_PERMISSION_KEY],
1007
+ });
1008
+ }
1009
+ }
1010
+ }
982
1011
  }, _SnapController_add =
983
1012
  /**
984
1013
  * Returns a promise representing the complete installation of the requested snap.
@@ -995,7 +1024,7 @@ async function _SnapController_add(args) {
995
1024
  __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snapId, { sourceCode: null, state: null });
996
1025
  const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
997
1026
  if (!runtime.installPromise) {
998
- console.info(`Adding snap: ${snapId}`);
1027
+ (0, logging_1.log)(`Adding snap: ${snapId}`);
999
1028
  // If fetching and setting the snap succeeds, this property will be set
1000
1029
  // to null in the authorize() method.
1001
1030
  runtime.installPromise = (async () => {
@@ -1065,7 +1094,7 @@ async function _SnapController_getEndowments(snapId) {
1065
1094
  // This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313
1066
1095
  // eslint-disable-next-line @typescript-eslint/restrict-plus-operands
1067
1096
  snaps_utils_1.DEFAULT_ENDOWMENTS.length + allEndowments.length) {
1068
- console.error('Duplicate endowments found. Default endowments should not be requested.', allEndowments);
1097
+ (0, snaps_utils_1.logError)('Duplicate endowments found. Default endowments should not be requested.', allEndowments);
1069
1098
  }
1070
1099
  return dedupedEndowments;
1071
1100
  }, _SnapController_set = function _SnapController_set(args) {
@@ -1076,14 +1105,15 @@ async function _SnapController_getEndowments(snapId) {
1076
1105
  if (!(0, utils_1.satisfiesVersionRange)(version, versionRange)) {
1077
1106
  throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${version}" which doesn't satisfy requested version range "${versionRange}"`);
1078
1107
  }
1108
+ const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(manifest.result.source.location.npm.filePath);
1109
+ const { iconPath } = manifest.result.source.location.npm;
1110
+ const normalizedIconPath = iconPath && (0, snaps_utils_1.normalizeRelative)(iconPath);
1079
1111
  const sourceCode = (_a = files
1080
- .find((file) => file.path === manifest.result.source.location.npm.filePath)) === null || _a === void 0 ? void 0 : _a.toString();
1081
- const svgIcon = files.find((file) => manifest.result.source.location.npm.iconPath !== undefined &&
1082
- file.path === manifest.result.source.location.npm.iconPath);
1083
- (0, utils_1.assert)(sourceCode !== undefined);
1084
- if (typeof sourceCode !== 'string' || sourceCode.length === 0) {
1085
- throw new Error(`Invalid source code for snap "${snapId}".`);
1086
- }
1112
+ .find((file) => file.path === normalizedSourcePath)) === null || _a === void 0 ? void 0 : _a.toString();
1113
+ const svgIcon = normalizedIconPath
1114
+ ? files.find((file) => file.path === normalizedIconPath)
1115
+ : undefined;
1116
+ (0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
1087
1117
  const snapsState = this.state.snaps;
1088
1118
  const existingSnap = snapsState[snapId];
1089
1119
  const previousVersionHistory = (_b = existingSnap === null || existingSnap === void 0 ? void 0 : existingSnap.versionHistory) !== null && _b !== void 0 ? _b : [];
@@ -1098,9 +1128,7 @@ async function _SnapController_getEndowments(snapId) {
1098
1128
  const snap = Object.assign(Object.assign({}, existingSnap), {
1099
1129
  // Note that the snap will be unblocked and enabled, regardless of its
1100
1130
  // previous state.
1101
- blocked: false, enabled: true,
1102
- // So we can easily correlate the snap with its permission
1103
- permissionName: (0, snaps_utils_1.getSnapPermissionName)(snapId), id: snapId, initialPermissions: manifest.result.initialPermissions, manifest: manifest.result, status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial, version,
1131
+ blocked: false, enabled: true, id: snapId, initialPermissions: manifest.result.initialPermissions, manifest: manifest.result, status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial, version,
1104
1132
  versionHistory });
1105
1133
  // If the snap was blocked, it isn't any longer
1106
1134
  delete snap.blockInformation;
@@ -1134,12 +1162,13 @@ async function _SnapController_fetchSnap(snapId, location) {
1134
1162
  try {
1135
1163
  const manifest = await location.manifest();
1136
1164
  const sourceCode = await location.fetch(manifest.result.source.location.npm.filePath);
1137
- (0, snaps_utils_1.validateSnapShasum)(manifest.result, sourceCode.toString());
1138
1165
  const { iconPath } = manifest.result.source.location.npm;
1166
+ const svgIcon = iconPath ? await location.fetch(iconPath) : undefined;
1139
1167
  const files = [sourceCode];
1140
- if (iconPath) {
1141
- files.push(await location.fetch(iconPath));
1168
+ if (svgIcon) {
1169
+ files.push(svgIcon);
1142
1170
  }
1171
+ (0, snaps_utils_1.validateSnapShasum)({ manifest, sourceCode, svgIcon });
1143
1172
  return { manifest, files, location };
1144
1173
  }
1145
1174
  catch (error) {
@@ -1244,7 +1273,7 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
1244
1273
  const isLongRunning = this.messagingSystem.call('PermissionController:hasPermission', snapId, endowments_1.SnapEndowments.LongRunning);
1245
1274
  // Long running snaps have timeouts disabled
1246
1275
  if (isLongRunning) {
1247
- console.warn(`${endowments_1.SnapEndowments.LongRunning} will soon be deprecated. For more information please see https://github.com/MetaMask/snaps-monorepo/issues/945.`);
1276
+ (0, snaps_utils_1.logWarning)(`${endowments_1.SnapEndowments.LongRunning} will soon be deprecated. For more information please see https://github.com/MetaMask/snaps-monorepo/issues/945.`);
1248
1277
  return promise;
1249
1278
  }
1250
1279
  const result = await (0, utils_2.withTimeout)(promise, timer !== null && timer !== void 0 ? timer : this.maxRequestTime);