@metamask/snaps-controllers 0.27.1 → 0.29.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.
- package/dist/cronjob/CronjobController.js +3 -3
- package/dist/cronjob/CronjobController.js.map +1 -1
- package/dist/logging.d.ts +8 -0
- package/dist/logging.js +13 -0
- package/dist/logging.js.map +1 -0
- package/dist/multichain/MultiChainController.js +11 -12
- package/dist/multichain/MultiChainController.js.map +1 -1
- package/dist/services/AbstractExecutionService.js +10 -9
- package/dist/services/AbstractExecutionService.js.map +1 -1
- package/dist/services/browser.d.ts +1 -0
- package/dist/services/browser.js +1 -0
- package/dist/services/browser.js.map +1 -1
- package/dist/services/iframe/IframeExecutionService.d.ts +0 -10
- package/dist/services/iframe/IframeExecutionService.js +2 -53
- package/dist/services/iframe/IframeExecutionService.js.map +1 -1
- package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.js +0 -40
- package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.js.map +1 -1
- package/dist/services/index.d.ts +1 -0
- package/dist/services/index.js +1 -0
- package/dist/services/index.js.map +1 -1
- package/dist/services/offscreen/OffscreenExecutionService.d.ts +49 -0
- package/dist/services/offscreen/OffscreenExecutionService.js +100 -0
- package/dist/services/offscreen/OffscreenExecutionService.js.map +1 -0
- package/dist/services/offscreen/OffscreenPostMessageStream.d.ts +35 -0
- package/dist/services/offscreen/OffscreenPostMessageStream.js +66 -0
- package/dist/services/offscreen/OffscreenPostMessageStream.js.map +1 -0
- package/dist/services/offscreen/index.d.ts +2 -0
- package/dist/services/offscreen/index.js +19 -0
- package/dist/services/offscreen/index.js.map +1 -0
- package/dist/snaps/SnapController.d.ts +30 -35
- package/dist/snaps/SnapController.js +109 -87
- package/dist/snaps/SnapController.js.map +1 -1
- package/dist/snaps/endowments/index.d.ts +1 -1
- package/dist/snaps/endowments/network-access.d.ts +1 -1
- package/dist/snaps/endowments/network-access.js +1 -1
- package/dist/snaps/endowments/network-access.js.map +1 -1
- package/dist/snaps/index.d.ts +1 -0
- package/dist/snaps/index.js +1 -0
- package/dist/snaps/index.js.map +1 -1
- package/dist/snaps/location/location.d.ts +4 -0
- package/dist/snaps/location/location.js +3 -1
- package/dist/snaps/location/location.js.map +1 -1
- package/dist/snaps/location/npm.d.ts +2 -1
- package/dist/snaps/location/npm.js +30 -12
- package/dist/snaps/location/npm.js.map +1 -1
- package/dist/snaps/registry/index.d.ts +2 -0
- package/dist/snaps/registry/index.js +19 -0
- package/dist/snaps/registry/index.js.map +1 -0
- package/dist/snaps/registry/json.d.ts +20 -0
- package/dist/snaps/registry/json.js +95 -0
- package/dist/snaps/registry/json.js.map +1 -0
- package/dist/snaps/registry/registry.d.ts +29 -0
- package/dist/snaps/registry/registry.js +11 -0
- package/dist/snaps/registry/registry.js.map +1 -0
- package/package.json +10 -9
- package/dist/services/iframe/test/server.d.ts +0 -11
- package/dist/services/iframe/test/server.js +0 -71
- package/dist/services/iframe/test/server.js.map +0 -1
|
@@ -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_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval,
|
|
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,10 +33,12 @@ 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");
|
|
39
40
|
const location_1 = require("./location");
|
|
41
|
+
const registry_1 = require("./registry");
|
|
40
42
|
const RequestQueue_1 = require("./RequestQueue");
|
|
41
43
|
const Timer_1 = require("./Timer");
|
|
42
44
|
exports.controllerName = 'SnapController';
|
|
@@ -46,7 +48,6 @@ exports.SNAP_APPROVAL_UPDATE = 'wallet_updateSnap';
|
|
|
46
48
|
const TRUNCATED_SNAP_PROPERTIES = new Set([
|
|
47
49
|
'initialPermissions',
|
|
48
50
|
'id',
|
|
49
|
-
'permissionName',
|
|
50
51
|
'version',
|
|
51
52
|
'enabled',
|
|
52
53
|
'blocked',
|
|
@@ -80,7 +81,7 @@ const name = 'SnapController';
|
|
|
80
81
|
* - Start: Initializes the snap in its SES realm with the authorized permissions.
|
|
81
82
|
*/
|
|
82
83
|
class SnapController extends base_controller_1.BaseControllerV2 {
|
|
83
|
-
constructor({ closeAllConnections, messenger, state, environmentEndowmentPermissions = [], idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second),
|
|
84
|
+
constructor({ closeAllConnections, messenger, state, environmentEndowmentPermissions = [], excludedPermissions = {}, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second), registry = new registry_1.JsonSnapsRegistry(), maxIdleTime = (0, utils_1.inMilliseconds)(30, utils_1.Duration.Second), maxRequestTime = (0, utils_1.inMilliseconds)(60, utils_1.Duration.Second), fetchFunction = globalThis.fetch.bind(globalThis), featureFlags = {}, detectSnapLocation: detectSnapLocationFunction = location_1.detectSnapLocation, }) {
|
|
84
85
|
var _a, _b;
|
|
85
86
|
super({
|
|
86
87
|
messenger,
|
|
@@ -125,10 +126,11 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
125
126
|
_SnapController_instances.add(this);
|
|
126
127
|
_SnapController_closeAllConnections.set(this, void 0);
|
|
127
128
|
_SnapController_environmentEndowmentPermissions.set(this, void 0);
|
|
129
|
+
_SnapController_excludedPermissions.set(this, void 0);
|
|
128
130
|
_SnapController_featureFlags.set(this, void 0);
|
|
129
131
|
_SnapController_fetchFunction.set(this, void 0);
|
|
130
132
|
_SnapController_idleTimeCheckInterval.set(this, void 0);
|
|
131
|
-
|
|
133
|
+
_SnapController_registry.set(this, void 0);
|
|
132
134
|
_SnapController_maxIdleTime.set(this, void 0);
|
|
133
135
|
_SnapController_detectSnapLocation.set(this, void 0);
|
|
134
136
|
_SnapController_rollbackSnapshots.set(this, void 0);
|
|
@@ -136,10 +138,11 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
136
138
|
_SnapController_statusMachine.set(this, void 0);
|
|
137
139
|
__classPrivateFieldSet(this, _SnapController_closeAllConnections, closeAllConnections, "f");
|
|
138
140
|
__classPrivateFieldSet(this, _SnapController_environmentEndowmentPermissions, environmentEndowmentPermissions, "f");
|
|
141
|
+
__classPrivateFieldSet(this, _SnapController_excludedPermissions, excludedPermissions, "f");
|
|
139
142
|
__classPrivateFieldSet(this, _SnapController_featureFlags, featureFlags, "f");
|
|
140
143
|
__classPrivateFieldSet(this, _SnapController_fetchFunction, fetchFunction, "f");
|
|
141
144
|
__classPrivateFieldSet(this, _SnapController_idleTimeCheckInterval, idleTimeCheckInterval, "f");
|
|
142
|
-
__classPrivateFieldSet(this,
|
|
145
|
+
__classPrivateFieldSet(this, _SnapController_registry, registry, "f");
|
|
143
146
|
__classPrivateFieldSet(this, _SnapController_maxIdleTime, maxIdleTime, "f");
|
|
144
147
|
this.maxRequestTime = maxRequestTime;
|
|
145
148
|
__classPrivateFieldSet(this, _SnapController_detectSnapLocation, detectSnapLocationFunction, "f");
|
|
@@ -170,40 +173,26 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
170
173
|
* for more information.
|
|
171
174
|
*/
|
|
172
175
|
async updateBlockedSnaps() {
|
|
173
|
-
const blockedSnaps = await __classPrivateFieldGet(this,
|
|
176
|
+
const blockedSnaps = await __classPrivateFieldGet(this, _SnapController_registry, "f").get(Object.values(this.state.snaps).reduce((blockListArg, snap) => {
|
|
174
177
|
blockListArg[snap.id] = {
|
|
175
178
|
version: snap.version,
|
|
176
|
-
|
|
179
|
+
checksum: snap.manifest.source.shasum,
|
|
177
180
|
};
|
|
178
181
|
return blockListArg;
|
|
179
182
|
}, {}));
|
|
180
|
-
await Promise.all(Object.entries(blockedSnaps).map(async (
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_blockSnap).call(this, snapId, blockData);
|
|
183
|
+
await Promise.all(Object.entries(blockedSnaps).map(async ([snapId, { status, reason }]) => {
|
|
184
|
+
if (status === registry_1.SnapsRegistryStatus.Blocked) {
|
|
185
|
+
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_blockSnap).call(this, snapId, reason);
|
|
184
186
|
}
|
|
185
187
|
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_unblockSnap).call(this, snapId);
|
|
186
188
|
}));
|
|
187
189
|
}
|
|
188
|
-
/**
|
|
189
|
-
* Checks the block list to determine whether a version of a snap is blocked.
|
|
190
|
-
*
|
|
191
|
-
* @param snapId - The snap id to check.
|
|
192
|
-
* @param snapInfo - Snap information containing version and shasum.
|
|
193
|
-
* @returns Whether the version of the snap is blocked or not.
|
|
194
|
-
*/
|
|
195
|
-
async isBlocked(snapId, snapInfo) {
|
|
196
|
-
const result = await __classPrivateFieldGet(this, _SnapController_checkSnapBlockList, "f").call(this, {
|
|
197
|
-
[snapId]: snapInfo,
|
|
198
|
-
});
|
|
199
|
-
return result[snapId].blocked;
|
|
200
|
-
}
|
|
201
190
|
_onUnhandledSnapError(snapId, error) {
|
|
202
191
|
this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Crash)
|
|
203
192
|
.then(() => this.addSnapError(error))
|
|
204
193
|
.catch((stopSnapError) => {
|
|
205
194
|
// TODO: Decide how to handle errors.
|
|
206
|
-
|
|
195
|
+
(0, snaps_utils_1.logError)(stopSnapError);
|
|
207
196
|
});
|
|
208
197
|
}
|
|
209
198
|
_onOutboundRequest(snapId) {
|
|
@@ -475,9 +464,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
475
464
|
// affect the host environment while we are deleting it.
|
|
476
465
|
await this.disableSnap(snapId);
|
|
477
466
|
this.revokeAllSnapPermissions(snapId);
|
|
478
|
-
|
|
479
|
-
// Revoke all subjects access to the snap
|
|
480
|
-
this.messagingSystem.call('PermissionController:revokePermissionForAllSubjects', permissionName);
|
|
467
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_removeSnapFromSubjects).call(this, snapId);
|
|
481
468
|
this.snapsRuntimeData.delete(snapId);
|
|
482
469
|
this.update((state) => {
|
|
483
470
|
delete state.snaps[snapId];
|
|
@@ -530,15 +517,14 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
530
517
|
* @returns The serialized permitted snaps for the origin.
|
|
531
518
|
*/
|
|
532
519
|
getPermittedSnaps(origin) {
|
|
533
|
-
var _a;
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
}
|
|
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;
|
|
542
528
|
}
|
|
543
529
|
return permittedSnaps;
|
|
544
530
|
}, {});
|
|
@@ -566,8 +552,8 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
566
552
|
if (error) {
|
|
567
553
|
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${rawVersion}".`);
|
|
568
554
|
}
|
|
569
|
-
const
|
|
570
|
-
if (!
|
|
555
|
+
const permissions = this.messagingSystem.call('PermissionController:getPermissions', origin);
|
|
556
|
+
if (!(0, snaps_utils_1.isSnapPermitted)(permissions, snapId)) {
|
|
571
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.`);
|
|
572
558
|
}
|
|
573
559
|
const isUpdate = pendingUpdates.includes(snapId);
|
|
@@ -611,15 +597,16 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
611
597
|
const location = __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, {
|
|
612
598
|
versionRange,
|
|
613
599
|
fetch: __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"),
|
|
600
|
+
allowLocal: __classPrivateFieldGet(this, _SnapController_featureFlags, "f").allowLocalSnaps,
|
|
614
601
|
});
|
|
615
602
|
const existingSnap = this.getTruncated(snapId);
|
|
616
603
|
// For devX we always re-install local snaps.
|
|
617
604
|
if (existingSnap && !location.shouldAlwaysReload) {
|
|
618
|
-
if ((0,
|
|
605
|
+
if ((0, utils_1.satisfiesVersionRange)(existingSnap.version, versionRange)) {
|
|
619
606
|
return existingSnap;
|
|
620
607
|
}
|
|
621
608
|
if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").dappsCanUpdateSnaps === true) {
|
|
622
|
-
const updateResult = await this.updateSnap(origin, snapId,
|
|
609
|
+
const updateResult = await this.updateSnap(origin, snapId, location, versionRange);
|
|
623
610
|
if (updateResult === null) {
|
|
624
611
|
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Snap "${snapId}@${existingSnap.version}" is already installed. Couldn't update to a version inside requested "${versionRange}" range.`);
|
|
625
612
|
}
|
|
@@ -647,7 +634,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
647
634
|
return truncated;
|
|
648
635
|
}
|
|
649
636
|
catch (error) {
|
|
650
|
-
|
|
637
|
+
(0, snaps_utils_1.logError)(`Error when adding snap.`, error);
|
|
651
638
|
throw error;
|
|
652
639
|
}
|
|
653
640
|
}
|
|
@@ -665,25 +652,25 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
665
652
|
*
|
|
666
653
|
* @param origin - The origin requesting the snap update.
|
|
667
654
|
* @param snapId - The id of the Snap to be updated.
|
|
668
|
-
* @param newVersionRange - A semver version range in which the maximum version will be chosen.
|
|
669
655
|
* @param location - Optional location that was already used during installation flow.
|
|
656
|
+
* @param newVersionRange - A semver version range in which the maximum version will be chosen.
|
|
670
657
|
* @returns The snap metadata if updated, `null` otherwise.
|
|
671
658
|
*/
|
|
672
|
-
async updateSnap(origin, snapId, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION
|
|
659
|
+
async updateSnap(origin, snapId, location, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION) {
|
|
673
660
|
var _a;
|
|
674
661
|
const snap = this.getExpect(snapId);
|
|
675
|
-
if (!(0,
|
|
662
|
+
if (!(0, utils_1.isValidSemVerRange)(newVersionRange)) {
|
|
676
663
|
throw new Error(`Received invalid snap version range: "${newVersionRange}".`);
|
|
677
664
|
}
|
|
678
|
-
const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location
|
|
665
|
+
const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
|
|
679
666
|
const newVersion = newSnap.manifest.result.version;
|
|
680
|
-
if (!(0,
|
|
681
|
-
|
|
667
|
+
if (!(0, utils_1.gtVersion)(newVersion, snap.version)) {
|
|
668
|
+
(0, snaps_utils_1.logWarning)(`Tried updating snap "${snapId}" within "${newVersionRange}" version range, but newer version "${snap.version}" is already installed`);
|
|
682
669
|
return null;
|
|
683
670
|
}
|
|
684
|
-
await __classPrivateFieldGet(this, _SnapController_instances, "m",
|
|
671
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
|
|
685
672
|
version: newVersion,
|
|
686
|
-
|
|
673
|
+
checksum: newSnap.manifest.result.source.shasum,
|
|
687
674
|
});
|
|
688
675
|
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.result.initialPermissions);
|
|
689
676
|
const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
@@ -734,9 +721,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
734
721
|
rollbackSnapshot.permissions.granted = Object.keys(approvedNewPermissions);
|
|
735
722
|
rollbackSnapshot.permissions.requestData = requestData;
|
|
736
723
|
}
|
|
724
|
+
const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(newSnap.manifest.result.source.location.npm.filePath);
|
|
737
725
|
const sourceCode = (_a = newSnap.files
|
|
738
|
-
.find((file) => file.path ===
|
|
739
|
-
(0, utils_1.assert)(sourceCode
|
|
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}".`);
|
|
740
728
|
try {
|
|
741
729
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
|
|
742
730
|
}
|
|
@@ -747,6 +735,16 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
747
735
|
this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
|
|
748
736
|
return truncatedSnap;
|
|
749
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
|
+
}
|
|
750
748
|
/**
|
|
751
749
|
* Initiates a request for the given snap's initial permissions.
|
|
752
750
|
* Must be called in order. See processRequestedSnap.
|
|
@@ -758,12 +756,19 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
758
756
|
* @returns The snap's approvedPermissions.
|
|
759
757
|
*/
|
|
760
758
|
async authorize(origin, snapId) {
|
|
761
|
-
|
|
759
|
+
(0, logging_1.log)(`Authorizing snap: ${snapId}`);
|
|
762
760
|
const snapsState = this.state.snaps;
|
|
763
761
|
const snap = snapsState[snapId];
|
|
764
762
|
const { initialPermissions } = snap;
|
|
765
763
|
try {
|
|
766
764
|
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, initialPermissions);
|
|
765
|
+
const excludedPermissionErrors = Object.keys(processedPermissions).reduce((errors, permission) => {
|
|
766
|
+
if ((0, utils_1.hasProperty)(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f"), permission)) {
|
|
767
|
+
errors.push(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f")[permission]);
|
|
768
|
+
}
|
|
769
|
+
return errors;
|
|
770
|
+
}, []);
|
|
771
|
+
(0, utils_1.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
|
|
767
772
|
const id = (0, nanoid_1.nanoid)();
|
|
768
773
|
const _a = (await this.messagingSystem.call('ApprovalController:addRequest', {
|
|
769
774
|
origin,
|
|
@@ -836,7 +841,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
836
841
|
}
|
|
837
842
|
}
|
|
838
843
|
exports.SnapController = SnapController;
|
|
839
|
-
_SnapController_closeAllConnections = new WeakMap(), _SnapController_environmentEndowmentPermissions = new WeakMap(), _SnapController_featureFlags = new WeakMap(), _SnapController_fetchFunction = new WeakMap(), _SnapController_idleTimeCheckInterval = new WeakMap(),
|
|
844
|
+
_SnapController_closeAllConnections = new WeakMap(), _SnapController_environmentEndowmentPermissions = new WeakMap(), _SnapController_excludedPermissions = new WeakMap(), _SnapController_featureFlags = new WeakMap(), _SnapController_fetchFunction = new WeakMap(), _SnapController_idleTimeCheckInterval = new WeakMap(), _SnapController_registry = new WeakMap(), _SnapController_maxIdleTime = new WeakMap(), _SnapController_detectSnapLocation = new WeakMap(), _SnapController_rollbackSnapshots = new WeakMap(), _SnapController_timeoutForLastRequestStatus = new WeakMap(), _SnapController_statusMachine = new WeakMap(), _SnapController_instances = new WeakSet(), _SnapController_initializeStateMachine = function _SnapController_initializeStateMachine() {
|
|
840
845
|
const disableGuard = ({ snapId }) => {
|
|
841
846
|
return this.getExpect(snapId).enabled;
|
|
842
847
|
};
|
|
@@ -880,6 +885,7 @@ _SnapController_closeAllConnections = new WeakMap(), _SnapController_environment
|
|
|
880
885
|
target: snaps_utils_1.SnapStatus.Running,
|
|
881
886
|
cond: disableGuard,
|
|
882
887
|
},
|
|
888
|
+
[snaps_utils_1.SnapStatusEvents.Update]: snaps_utils_1.SnapStatus.Updating,
|
|
883
889
|
},
|
|
884
890
|
},
|
|
885
891
|
},
|
|
@@ -903,11 +909,12 @@ _SnapController_closeAllConnections = new WeakMap(), _SnapController_environment
|
|
|
903
909
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:getAll`, (...args) => this.getAllSnaps(...args));
|
|
904
910
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:incrementActiveReferences`, (...args) => this.incrementActiveReferences(...args));
|
|
905
911
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:decrementActiveReferences`, (...args) => this.decrementActiveReferences(...args));
|
|
912
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:getRegistryMetadata`, async (...args) => this.getRegistryMetadata(...args));
|
|
906
913
|
}, _SnapController_pollForLastRequestStatus = function _SnapController_pollForLastRequestStatus() {
|
|
907
914
|
__classPrivateFieldSet(this, _SnapController_timeoutForLastRequestStatus, setTimeout(() => {
|
|
908
915
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_stopSnapsLastRequestPastMax).call(this).catch((error) => {
|
|
909
916
|
// TODO: Decide how to handle errors.
|
|
910
|
-
|
|
917
|
+
(0, snaps_utils_1.logError)(error);
|
|
911
918
|
});
|
|
912
919
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_pollForLastRequestStatus).call(this);
|
|
913
920
|
}, __classPrivateFieldGet(this, _SnapController_idleTimeCheckInterval, "f")), "f");
|
|
@@ -931,7 +938,7 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
|
|
|
931
938
|
await this.disableSnap(snapId);
|
|
932
939
|
}
|
|
933
940
|
catch (error) {
|
|
934
|
-
|
|
941
|
+
(0, snaps_utils_1.logError)(`Encountered error when stopping blocked snap "${snapId}".`, error);
|
|
935
942
|
}
|
|
936
943
|
this.messagingSystem.publish(`${exports.controllerName}:snapBlocked`, snapId, blockedSnapInfo);
|
|
937
944
|
}, _SnapController_unblockSnap = function _SnapController_unblockSnap(snapId) {
|
|
@@ -943,17 +950,18 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
|
|
|
943
950
|
delete state.snaps[snapId].blockInformation;
|
|
944
951
|
});
|
|
945
952
|
this.messagingSystem.publish(`${exports.controllerName}:snapUnblocked`, snapId);
|
|
946
|
-
},
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
if (
|
|
956
|
-
|
|
953
|
+
}, _SnapController_assertIsInstallAllowed = async function _SnapController_assertIsInstallAllowed(snapId, snapInfo) {
|
|
954
|
+
var _a, _b;
|
|
955
|
+
const results = await __classPrivateFieldGet(this, _SnapController_registry, "f").get({
|
|
956
|
+
[snapId]: snapInfo,
|
|
957
|
+
});
|
|
958
|
+
const result = results[snapId];
|
|
959
|
+
if (result.status === registry_1.SnapsRegistryStatus.Blocked) {
|
|
960
|
+
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${(_b = (_a = result.reason) === null || _a === void 0 ? void 0 : _a.explanation) !== null && _b !== void 0 ? _b : ''}`);
|
|
961
|
+
}
|
|
962
|
+
else if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").requireAllowlist &&
|
|
963
|
+
result.status !== registry_1.SnapsRegistryStatus.Verified) {
|
|
964
|
+
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The snap is not on the allow list.`);
|
|
957
965
|
}
|
|
958
966
|
}, _SnapController_stopSnapsLastRequestPastMax = async function _SnapController_stopSnapsLastRequestPastMax() {
|
|
959
967
|
const entries = [...this.snapsRuntimeData.entries()];
|
|
@@ -980,6 +988,19 @@ async function _SnapController_assertIsUnblocked(snapId, snapInfo) {
|
|
|
980
988
|
async function _SnapController_terminateSnap(snapId) {
|
|
981
989
|
await this.messagingSystem.call('ExecutionService:terminateSnap', snapId);
|
|
982
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
|
+
this.messagingSystem.call('PermissionController:updateCaveat', subject, rpc_methods_1.WALLET_SNAP_PERMISSION_KEY, snaps_utils_1.SnapCaveatType.SnapIds, newCaveatValue);
|
|
1002
|
+
}
|
|
1003
|
+
}
|
|
983
1004
|
}, _SnapController_add =
|
|
984
1005
|
/**
|
|
985
1006
|
* Returns a promise representing the complete installation of the requested snap.
|
|
@@ -996,14 +1017,14 @@ async function _SnapController_add(args) {
|
|
|
996
1017
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snapId, { sourceCode: null, state: null });
|
|
997
1018
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
998
1019
|
if (!runtime.installPromise) {
|
|
999
|
-
|
|
1020
|
+
(0, logging_1.log)(`Adding snap: ${snapId}`);
|
|
1000
1021
|
// If fetching and setting the snap succeeds, this property will be set
|
|
1001
1022
|
// to null in the authorize() method.
|
|
1002
1023
|
runtime.installPromise = (async () => {
|
|
1003
1024
|
const fetchedSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
|
|
1004
|
-
await __classPrivateFieldGet(this, _SnapController_instances, "m",
|
|
1025
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
|
|
1005
1026
|
version: fetchedSnap.manifest.result.version,
|
|
1006
|
-
|
|
1027
|
+
checksum: fetchedSnap.manifest.result.source.shasum,
|
|
1007
1028
|
});
|
|
1008
1029
|
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, Object.assign(Object.assign(Object.assign({}, args), fetchedSnap), { id: snapId }));
|
|
1009
1030
|
})();
|
|
@@ -1066,7 +1087,7 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1066
1087
|
// This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313
|
|
1067
1088
|
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
1068
1089
|
snaps_utils_1.DEFAULT_ENDOWMENTS.length + allEndowments.length) {
|
|
1069
|
-
|
|
1090
|
+
(0, snaps_utils_1.logError)('Duplicate endowments found. Default endowments should not be requested.', allEndowments);
|
|
1070
1091
|
}
|
|
1071
1092
|
return dedupedEndowments;
|
|
1072
1093
|
}, _SnapController_set = function _SnapController_set(args) {
|
|
@@ -1074,17 +1095,18 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1074
1095
|
const { id: snapId, origin, manifest, files, versionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION, isUpdate = false, } = args;
|
|
1075
1096
|
(0, snaps_utils_1.assertIsSnapManifest)(manifest.result);
|
|
1076
1097
|
const { version } = manifest.result;
|
|
1077
|
-
if (!(0,
|
|
1098
|
+
if (!(0, utils_1.satisfiesVersionRange)(version, versionRange)) {
|
|
1078
1099
|
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${version}" which doesn't satisfy requested version range "${versionRange}"`);
|
|
1079
1100
|
}
|
|
1101
|
+
const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(manifest.result.source.location.npm.filePath);
|
|
1102
|
+
const { iconPath } = manifest.result.source.location.npm;
|
|
1103
|
+
const normalizedIconPath = iconPath && (0, snaps_utils_1.normalizeRelative)(iconPath);
|
|
1080
1104
|
const sourceCode = (_a = files
|
|
1081
|
-
.find((file) => file.path ===
|
|
1082
|
-
const svgIcon =
|
|
1083
|
-
file.path ===
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
throw new Error(`Invalid source code for snap "${snapId}".`);
|
|
1087
|
-
}
|
|
1105
|
+
.find((file) => file.path === normalizedSourcePath)) === null || _a === void 0 ? void 0 : _a.toString();
|
|
1106
|
+
const svgIcon = normalizedIconPath
|
|
1107
|
+
? files.find((file) => file.path === normalizedIconPath)
|
|
1108
|
+
: undefined;
|
|
1109
|
+
(0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
|
|
1088
1110
|
const snapsState = this.state.snaps;
|
|
1089
1111
|
const existingSnap = snapsState[snapId];
|
|
1090
1112
|
const previousVersionHistory = (_b = existingSnap === null || existingSnap === void 0 ? void 0 : existingSnap.versionHistory) !== null && _b !== void 0 ? _b : [];
|
|
@@ -1099,9 +1121,7 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1099
1121
|
const snap = Object.assign(Object.assign({}, existingSnap), {
|
|
1100
1122
|
// Note that the snap will be unblocked and enabled, regardless of its
|
|
1101
1123
|
// previous state.
|
|
1102
|
-
blocked: false, enabled: true,
|
|
1103
|
-
// So we can easily correlate the snap with its permission
|
|
1104
|
-
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,
|
|
1124
|
+
blocked: false, enabled: true, id: snapId, initialPermissions: manifest.result.initialPermissions, manifest: manifest.result, status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial, version,
|
|
1105
1125
|
versionHistory });
|
|
1106
1126
|
// If the snap was blocked, it isn't any longer
|
|
1107
1127
|
delete snap.blockInformation;
|
|
@@ -1135,12 +1155,13 @@ async function _SnapController_fetchSnap(snapId, location) {
|
|
|
1135
1155
|
try {
|
|
1136
1156
|
const manifest = await location.manifest();
|
|
1137
1157
|
const sourceCode = await location.fetch(manifest.result.source.location.npm.filePath);
|
|
1138
|
-
(0, snaps_utils_1.validateSnapShasum)(manifest.result, sourceCode.toString());
|
|
1139
1158
|
const { iconPath } = manifest.result.source.location.npm;
|
|
1159
|
+
const svgIcon = iconPath ? await location.fetch(iconPath) : undefined;
|
|
1140
1160
|
const files = [sourceCode];
|
|
1141
|
-
if (
|
|
1142
|
-
files.push(
|
|
1161
|
+
if (svgIcon) {
|
|
1162
|
+
files.push(svgIcon);
|
|
1143
1163
|
}
|
|
1164
|
+
(0, snaps_utils_1.validateSnapShasum)({ manifest, sourceCode, svgIcon });
|
|
1144
1165
|
return { manifest, files, location };
|
|
1145
1166
|
}
|
|
1146
1167
|
catch (error) {
|
|
@@ -1245,6 +1266,7 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1245
1266
|
const isLongRunning = this.messagingSystem.call('PermissionController:hasPermission', snapId, endowments_1.SnapEndowments.LongRunning);
|
|
1246
1267
|
// Long running snaps have timeouts disabled
|
|
1247
1268
|
if (isLongRunning) {
|
|
1269
|
+
(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
1270
|
return promise;
|
|
1249
1271
|
}
|
|
1250
1272
|
const result = await (0, utils_2.withTimeout)(promise, timer !== null && timer !== void 0 ? timer : this.maxRequestTime);
|
|
@@ -1360,10 +1382,10 @@ async function _SnapController_rollbackSnaps(snapIds) {
|
|
|
1360
1382
|
return { newPermissions, unusedPermissions, approvedPermissions };
|
|
1361
1383
|
}, _SnapController_isValidUpdate = function _SnapController_isValidUpdate(snapId, newVersionRange) {
|
|
1362
1384
|
const existingSnap = this.getExpect(snapId);
|
|
1363
|
-
if ((0,
|
|
1385
|
+
if ((0, utils_1.satisfiesVersionRange)(existingSnap.version, newVersionRange)) {
|
|
1364
1386
|
return false;
|
|
1365
1387
|
}
|
|
1366
|
-
if ((0,
|
|
1388
|
+
if ((0, utils_1.gtRange)(existingSnap.version, newVersionRange)) {
|
|
1367
1389
|
return false;
|
|
1368
1390
|
}
|
|
1369
1391
|
return true;
|