@metamask/snaps-controllers 0.25.0 → 0.26.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/snaps/SnapController.d.ts +19 -31
- package/dist/snaps/SnapController.js +213 -152
- package/dist/snaps/SnapController.js.map +1 -1
- package/dist/snaps/index.d.ts +0 -1
- package/dist/snaps/index.js +0 -1
- package/dist/snaps/index.js.map +1 -1
- package/dist/snaps/location/http.d.ts +21 -0
- package/dist/snaps/location/http.js +71 -0
- package/dist/snaps/location/http.js.map +1 -0
- package/dist/snaps/location/index.d.ts +4 -0
- package/dist/snaps/{utils → location}/index.js +3 -1
- package/dist/snaps/location/index.js.map +1 -0
- package/dist/snaps/location/local.d.ts +10 -0
- package/dist/snaps/location/local.js +51 -0
- package/dist/snaps/location/local.js.map +1 -0
- package/dist/snaps/location/location.d.ts +32 -0
- package/dist/snaps/location/location.js +33 -0
- package/dist/snaps/location/location.js.map +1 -0
- package/dist/snaps/location/npm.d.ts +33 -0
- package/dist/snaps/location/npm.js +232 -0
- package/dist/snaps/location/npm.js.map +1 -0
- package/dist/utils.d.ts +7 -0
- package/dist/utils.js +17 -1
- package/dist/utils.js.map +1 -1
- package/package.json +9 -9
- package/dist/snaps/utils/index.d.ts +0 -2
- package/dist/snaps/utils/index.js.map +0 -1
- package/dist/snaps/utils/npm.d.ts +0 -14
- package/dist/snaps/utils/npm.js +0 -85
- package/dist/snaps/utils/npm.js.map +0 -1
- package/dist/snaps/utils/stream.d.ts +0 -30
- package/dist/snaps/utils/stream.js +0 -124
- package/dist/snaps/utils/stream.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, _SnapController_checkSnapBlockList, _SnapController_maxIdleTime, _SnapController_npmRegistryUrl, _SnapController_getAppKey, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsUnblocked, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_getEncryptionKey, _SnapController_encryptSnapState, _SnapController_decryptSnapState, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set,
|
|
24
|
+
var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_checkSnapBlockList, _SnapController_maxIdleTime, _SnapController_npmRegistryUrl, _SnapController_detectSnapLocation, _SnapController_rollbackSnapshots, _SnapController_getAppKey, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsUnblocked, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_getEncryptionKey, _SnapController_encryptSnapState, _SnapController_decryptSnapState, _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.AppKeyType = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
|
|
27
27
|
const base_controller_1 = require("@metamask/base-controller");
|
|
@@ -37,9 +37,9 @@ const fsm_2 = require("../fsm");
|
|
|
37
37
|
const utils_2 = require("../utils");
|
|
38
38
|
const endowments_1 = require("./endowments");
|
|
39
39
|
const rpc_1 = require("./endowments/rpc");
|
|
40
|
+
const location_1 = require("./location");
|
|
40
41
|
const RequestQueue_1 = require("./RequestQueue");
|
|
41
42
|
const Timer_1 = require("./Timer");
|
|
42
|
-
const utils_3 = require("./utils");
|
|
43
43
|
exports.controllerName = 'SnapController';
|
|
44
44
|
// TODO: Figure out how to name these
|
|
45
45
|
exports.SNAP_APPROVAL_INSTALL = 'wallet_installSnap';
|
|
@@ -85,7 +85,7 @@ const name = 'SnapController';
|
|
|
85
85
|
* - Start: Initializes the snap in its SES realm with the authorized permissions.
|
|
86
86
|
*/
|
|
87
87
|
class SnapController extends base_controller_1.BaseControllerV2 {
|
|
88
|
-
constructor({ closeAllConnections, messenger, state, getAppKey, environmentEndowmentPermissions = [], npmRegistryUrl, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second), checkBlockList, 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 = {}, }) {
|
|
88
|
+
constructor({ closeAllConnections, messenger, state, getAppKey, environmentEndowmentPermissions = [], npmRegistryUrl, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second), checkBlockList, 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, }) {
|
|
89
89
|
var _a, _b;
|
|
90
90
|
super({
|
|
91
91
|
messenger,
|
|
@@ -136,6 +136,8 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
136
136
|
_SnapController_checkSnapBlockList.set(this, void 0);
|
|
137
137
|
_SnapController_maxIdleTime.set(this, void 0);
|
|
138
138
|
_SnapController_npmRegistryUrl.set(this, void 0);
|
|
139
|
+
_SnapController_detectSnapLocation.set(this, void 0);
|
|
140
|
+
_SnapController_rollbackSnapshots.set(this, void 0);
|
|
139
141
|
_SnapController_getAppKey.set(this, void 0);
|
|
140
142
|
_SnapController_timeoutForLastRequestStatus.set(this, void 0);
|
|
141
143
|
_SnapController_statusMachine.set(this, void 0);
|
|
@@ -149,9 +151,11 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
149
151
|
__classPrivateFieldSet(this, _SnapController_maxIdleTime, maxIdleTime, "f");
|
|
150
152
|
this.maxRequestTime = maxRequestTime;
|
|
151
153
|
__classPrivateFieldSet(this, _SnapController_npmRegistryUrl, npmRegistryUrl, "f");
|
|
154
|
+
__classPrivateFieldSet(this, _SnapController_detectSnapLocation, detectSnapLocationFunction, "f");
|
|
152
155
|
this._onUnhandledSnapError = this._onUnhandledSnapError.bind(this);
|
|
153
156
|
this._onOutboundRequest = this._onOutboundRequest.bind(this);
|
|
154
157
|
this._onOutboundResponse = this._onOutboundResponse.bind(this);
|
|
158
|
+
__classPrivateFieldSet(this, _SnapController_rollbackSnapshots, new Map(), "f");
|
|
155
159
|
this.snapsRuntimeData = new Map();
|
|
156
160
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_pollForLastRequestStatus).call(this);
|
|
157
161
|
/* eslint-disable @typescript-eslint/unbound-method */
|
|
@@ -561,27 +565,46 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
561
565
|
*/
|
|
562
566
|
async installSnaps(origin, requestedSnaps) {
|
|
563
567
|
const result = {};
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
568
|
+
const snapIds = Object.keys(requestedSnaps);
|
|
569
|
+
// Existing snaps may need to be updated
|
|
570
|
+
const pendingUpdates = snapIds.filter((snapId) => this.has(snapId));
|
|
571
|
+
// Non-existing snaps will need to be installed
|
|
572
|
+
const pendingInstalls = snapIds.filter((snapId) => !pendingUpdates.includes(snapId));
|
|
573
|
+
try {
|
|
574
|
+
for (const [snapId, { version: rawVersion }] of Object.entries(requestedSnaps)) {
|
|
575
|
+
const [error, version] = (0, snaps_utils_1.resolveVersionRange)(rawVersion);
|
|
576
|
+
if (error) {
|
|
577
|
+
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${rawVersion}".`);
|
|
578
|
+
}
|
|
579
|
+
const permissionName = (0, snaps_utils_1.getSnapPermissionName)(snapId);
|
|
580
|
+
if (!this.messagingSystem.call('PermissionController:hasPermission', origin, permissionName)) {
|
|
581
|
+
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.`);
|
|
582
|
+
}
|
|
583
|
+
const isUpdate = pendingUpdates.includes(snapId);
|
|
584
|
+
if (isUpdate && __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_isValidUpdate).call(this, snapId, version)) {
|
|
585
|
+
let rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
|
|
586
|
+
if (rollbackSnapshot === undefined) {
|
|
587
|
+
const prevSourceCode = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId).sourceCode;
|
|
588
|
+
rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createRollbackSnapshot).call(this, snapId);
|
|
589
|
+
rollbackSnapshot.sourceCode = prevSourceCode;
|
|
590
|
+
rollbackSnapshot.newVersion = version;
|
|
591
|
+
}
|
|
592
|
+
else {
|
|
593
|
+
throw new Error('This snap is already being updated.');
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
result[snapId] = await this.processRequestedSnap(origin, snapId, version);
|
|
583
597
|
}
|
|
584
|
-
|
|
598
|
+
snapIds.forEach((snapId) => __classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").delete(snapId));
|
|
599
|
+
}
|
|
600
|
+
catch (error) {
|
|
601
|
+
const installed = pendingInstalls.filter((snapId) => this.has(snapId));
|
|
602
|
+
await this.removeSnaps(installed);
|
|
603
|
+
const snapshottedSnaps = [...__classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").keys()];
|
|
604
|
+
const snapsToRollback = pendingUpdates.filter((snapId) => snapshottedSnaps.includes(snapId));
|
|
605
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_rollbackSnaps).call(this, snapsToRollback);
|
|
606
|
+
throw error;
|
|
607
|
+
}
|
|
585
608
|
return result;
|
|
586
609
|
}
|
|
587
610
|
/**
|
|
@@ -594,39 +617,22 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
594
617
|
* @returns The resulting snap object, or an error if something went wrong.
|
|
595
618
|
*/
|
|
596
619
|
async processRequestedSnap(origin, snapId, versionRange) {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
}
|
|
600
|
-
catch (error) {
|
|
601
|
-
return {
|
|
602
|
-
error: eth_rpc_errors_1.ethErrors.rpc.invalidParams(`"${snapId}" is not a valid snap id.`),
|
|
603
|
-
};
|
|
604
|
-
}
|
|
620
|
+
(0, snaps_utils_1.validateSnapId)(snapId);
|
|
621
|
+
const location = __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, { versionRange });
|
|
605
622
|
const existingSnap = this.getTruncated(snapId);
|
|
606
623
|
// For devX we always re-install local snaps.
|
|
607
|
-
if (existingSnap &&
|
|
624
|
+
if (existingSnap && !location.shouldAlwaysReload) {
|
|
608
625
|
if ((0, snaps_utils_1.satisfiesVersionRange)(existingSnap.version, versionRange)) {
|
|
609
626
|
return existingSnap;
|
|
610
627
|
}
|
|
611
628
|
if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").dappsCanUpdateSnaps === true) {
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
return {
|
|
616
|
-
error: eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Snap "${snapId}@${existingSnap.version}" is already installed, couldn't update to a version inside requested "${versionRange}" range.`),
|
|
617
|
-
};
|
|
618
|
-
}
|
|
619
|
-
return updateResult;
|
|
620
|
-
}
|
|
621
|
-
catch (error) {
|
|
622
|
-
return { error: (0, eth_rpc_errors_1.serializeError)(error) };
|
|
629
|
+
const updateResult = await this.updateSnap(origin, snapId, versionRange, location);
|
|
630
|
+
if (updateResult === null) {
|
|
631
|
+
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.`);
|
|
623
632
|
}
|
|
633
|
+
return updateResult;
|
|
624
634
|
}
|
|
625
|
-
|
|
626
|
-
return {
|
|
627
|
-
error: eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Version mismatch with already installed snap. ${snapId}@${existingSnap.version} doesn't satisfy requested version ${versionRange}`),
|
|
628
|
-
};
|
|
629
|
-
}
|
|
635
|
+
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Version mismatch with already installed snap. ${snapId}@${existingSnap.version} doesn't satisfy requested version ${versionRange}.`);
|
|
630
636
|
}
|
|
631
637
|
// Existing snaps must be stopped before overwriting
|
|
632
638
|
if (existingSnap && this.isRunning(snapId)) {
|
|
@@ -636,7 +642,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
636
642
|
const { sourceCode } = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_add).call(this, {
|
|
637
643
|
origin,
|
|
638
644
|
id: snapId,
|
|
639
|
-
|
|
645
|
+
location,
|
|
640
646
|
});
|
|
641
647
|
await this.authorize(origin, snapId);
|
|
642
648
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, {
|
|
@@ -649,10 +655,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
649
655
|
}
|
|
650
656
|
catch (error) {
|
|
651
657
|
console.error(`Error when adding snap.`, error);
|
|
652
|
-
|
|
653
|
-
await this.removeSnap(snapId);
|
|
654
|
-
}
|
|
655
|
-
return { error: (0, eth_rpc_errors_1.serializeError)(error) };
|
|
658
|
+
throw error;
|
|
656
659
|
}
|
|
657
660
|
}
|
|
658
661
|
/**
|
|
@@ -670,27 +673,29 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
670
673
|
* @param origin - The origin requesting the snap update.
|
|
671
674
|
* @param snapId - The id of the Snap to be updated.
|
|
672
675
|
* @param newVersionRange - A semver version range in which the maximum version will be chosen.
|
|
676
|
+
* @param location - Optional location that was already used during installation flow.
|
|
673
677
|
* @returns The snap metadata if updated, `null` otherwise.
|
|
674
678
|
*/
|
|
675
|
-
async updateSnap(origin, snapId, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION) {
|
|
679
|
+
async updateSnap(origin, snapId, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION, location) {
|
|
680
|
+
var _a;
|
|
676
681
|
const snap = this.getExpect(snapId);
|
|
677
682
|
if (!(0, snaps_utils_1.isValidSemVerRange)(newVersionRange)) {
|
|
678
683
|
throw new Error(`Received invalid snap version range: "${newVersionRange}".`);
|
|
679
684
|
}
|
|
680
|
-
const newSnap = await this.
|
|
681
|
-
const newVersion = newSnap.manifest.version;
|
|
685
|
+
const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location !== null && location !== void 0 ? location : __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, { versionRange: newVersionRange }));
|
|
686
|
+
const newVersion = newSnap.manifest.result.version;
|
|
682
687
|
if (!(0, snaps_utils_1.gtVersion)(newVersion, snap.version)) {
|
|
683
688
|
console.warn(`Tried updating snap "${snapId}" within "${newVersionRange}" version range, but newer version "${snap.version}" is already installed`);
|
|
684
689
|
return null;
|
|
685
690
|
}
|
|
686
691
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsUnblocked).call(this, snapId, {
|
|
687
692
|
version: newVersion,
|
|
688
|
-
shasum: newSnap.manifest.source.shasum,
|
|
693
|
+
shasum: newSnap.manifest.result.source.shasum,
|
|
689
694
|
});
|
|
690
|
-
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.initialPermissions);
|
|
695
|
+
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.result.initialPermissions);
|
|
691
696
|
const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
692
697
|
const id = (0, nanoid_1.nanoid)();
|
|
693
|
-
const
|
|
698
|
+
const _b = (await this.messagingSystem.call('ApprovalController:addRequest', {
|
|
694
699
|
origin,
|
|
695
700
|
id,
|
|
696
701
|
type: exports.SNAP_APPROVAL_UPDATE,
|
|
@@ -699,12 +704,12 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
699
704
|
metadata: { id, origin: snapId, dappOrigin: origin },
|
|
700
705
|
permissions: newPermissions,
|
|
701
706
|
snapId,
|
|
702
|
-
newVersion: newSnap.manifest.version,
|
|
707
|
+
newVersion: newSnap.manifest.result.version,
|
|
703
708
|
newPermissions,
|
|
704
709
|
approvedPermissions,
|
|
705
710
|
unusedPermissions,
|
|
706
711
|
},
|
|
707
|
-
}, true)), { permissions: approvedNewPermissions } =
|
|
712
|
+
}, true)), { permissions: approvedNewPermissions } = _b, requestData = __rest(_b, ["permissions"]);
|
|
708
713
|
if (this.isRunning(snapId)) {
|
|
709
714
|
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
710
715
|
}
|
|
@@ -713,8 +718,9 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
713
718
|
origin,
|
|
714
719
|
id: snapId,
|
|
715
720
|
manifest: newSnap.manifest,
|
|
716
|
-
|
|
721
|
+
files: newSnap.files,
|
|
717
722
|
versionRange: newVersionRange,
|
|
723
|
+
isUpdate: true,
|
|
718
724
|
});
|
|
719
725
|
const unusedPermissionsKeys = Object.keys(unusedPermissions);
|
|
720
726
|
if ((0, utils_1.isNonEmptyArray)(unusedPermissionsKeys)) {
|
|
@@ -729,37 +735,24 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
729
735
|
requestData,
|
|
730
736
|
});
|
|
731
737
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
*
|
|
742
|
-
* @param snapId - The id of the Snap.
|
|
743
|
-
* @param versionRange - The SemVer version of the Snap to fetch.
|
|
744
|
-
* @returns A tuple of the Snap manifest object and the Snap source code.
|
|
745
|
-
*/
|
|
746
|
-
async fetchSnap(snapId, versionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION) {
|
|
738
|
+
const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
|
|
739
|
+
if (rollbackSnapshot !== undefined) {
|
|
740
|
+
rollbackSnapshot.permissions.revoked = unusedPermissions;
|
|
741
|
+
rollbackSnapshot.permissions.granted = Object.keys(approvedNewPermissions);
|
|
742
|
+
rollbackSnapshot.permissions.requestData = requestData;
|
|
743
|
+
}
|
|
744
|
+
const sourceCode = (_a = newSnap.files
|
|
745
|
+
.find((file) => file.path === newSnap.manifest.result.source.location.npm.filePath)) === null || _a === void 0 ? void 0 : _a.toString();
|
|
746
|
+
(0, utils_1.assert)(sourceCode !== undefined);
|
|
747
747
|
try {
|
|
748
|
-
|
|
749
|
-
switch (snapPrefix) {
|
|
750
|
-
case snaps_utils_1.SnapIdPrefixes.local:
|
|
751
|
-
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchLocalSnap).call(this, snapId.replace(snaps_utils_1.SnapIdPrefixes.local, ''));
|
|
752
|
-
case snaps_utils_1.SnapIdPrefixes.npm:
|
|
753
|
-
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchNpmSnap).call(this, snapId.replace(snaps_utils_1.SnapIdPrefixes.npm, ''), versionRange);
|
|
754
|
-
/* istanbul ignore next */
|
|
755
|
-
default:
|
|
756
|
-
// This whill fail to compile if the above switch is not fully exhaustive
|
|
757
|
-
return (0, utils_1.assertExhaustive)(snapPrefix);
|
|
758
|
-
}
|
|
748
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
|
|
759
749
|
}
|
|
760
|
-
catch (
|
|
761
|
-
throw new Error(`
|
|
750
|
+
catch (_c) {
|
|
751
|
+
throw new Error(`Snap ${snapId} crashed with updated source code.`);
|
|
762
752
|
}
|
|
753
|
+
const truncatedSnap = this.getTruncatedExpect(snapId);
|
|
754
|
+
this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
|
|
755
|
+
return truncatedSnap;
|
|
763
756
|
}
|
|
764
757
|
/**
|
|
765
758
|
* Initiates a request for the given snap's initial permissions.
|
|
@@ -850,7 +843,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
850
843
|
}
|
|
851
844
|
}
|
|
852
845
|
exports.SnapController = SnapController;
|
|
853
|
-
_SnapController_closeAllConnections = new WeakMap(), _SnapController_environmentEndowmentPermissions = new WeakMap(), _SnapController_featureFlags = new WeakMap(), _SnapController_fetchFunction = new WeakMap(), _SnapController_idleTimeCheckInterval = new WeakMap(), _SnapController_checkSnapBlockList = new WeakMap(), _SnapController_maxIdleTime = new WeakMap(), _SnapController_npmRegistryUrl = new WeakMap(), _SnapController_getAppKey = new WeakMap(), _SnapController_timeoutForLastRequestStatus = new WeakMap(), _SnapController_statusMachine = new WeakMap(), _SnapController_instances = new WeakSet(), _SnapController_initializeStateMachine = function _SnapController_initializeStateMachine() {
|
|
846
|
+
_SnapController_closeAllConnections = new WeakMap(), _SnapController_environmentEndowmentPermissions = new WeakMap(), _SnapController_featureFlags = new WeakMap(), _SnapController_fetchFunction = new WeakMap(), _SnapController_idleTimeCheckInterval = new WeakMap(), _SnapController_checkSnapBlockList = new WeakMap(), _SnapController_maxIdleTime = new WeakMap(), _SnapController_npmRegistryUrl = new WeakMap(), _SnapController_detectSnapLocation = new WeakMap(), _SnapController_rollbackSnapshots = new WeakMap(), _SnapController_getAppKey = new WeakMap(), _SnapController_timeoutForLastRequestStatus = new WeakMap(), _SnapController_statusMachine = new WeakMap(), _SnapController_instances = new WeakSet(), _SnapController_initializeStateMachine = function _SnapController_initializeStateMachine() {
|
|
854
847
|
const disableGuard = ({ snapId }) => {
|
|
855
848
|
return this.getExpect(snapId).enabled;
|
|
856
849
|
};
|
|
@@ -1020,15 +1013,8 @@ async function _SnapController_terminateSnap(snapId) {
|
|
|
1020
1013
|
* @returns The resulting snap object.
|
|
1021
1014
|
*/
|
|
1022
1015
|
async function _SnapController_add(args) {
|
|
1023
|
-
const { id: snapId } = args;
|
|
1016
|
+
const { id: snapId, location } = args;
|
|
1024
1017
|
(0, snaps_utils_1.validateSnapId)(snapId);
|
|
1025
|
-
if (!args ||
|
|
1026
|
-
!('origin' in args) ||
|
|
1027
|
-
!('id' in args) ||
|
|
1028
|
-
(!('manifest' in args) && 'sourceCode' in args) ||
|
|
1029
|
-
('manifest' in args && !('sourceCode' in args))) {
|
|
1030
|
-
throw new Error(`Invalid add snap args for snap "${snapId}".`);
|
|
1031
|
-
}
|
|
1032
1018
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snapId, { sourceCode: null, state: null });
|
|
1033
1019
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1034
1020
|
if (!runtime.installPromise) {
|
|
@@ -1036,13 +1022,10 @@ async function _SnapController_add(args) {
|
|
|
1036
1022
|
// If fetching and setting the snap succeeds, this property will be set
|
|
1037
1023
|
// to null in the authorize() method.
|
|
1038
1024
|
runtime.installPromise = (async () => {
|
|
1039
|
-
|
|
1040
|
-
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, Object.assign(Object.assign({}, args), { id: snapId }));
|
|
1041
|
-
}
|
|
1042
|
-
const fetchedSnap = await this.fetchSnap(snapId, args.versionRange);
|
|
1025
|
+
const fetchedSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
|
|
1043
1026
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsUnblocked).call(this, snapId, {
|
|
1044
|
-
version: fetchedSnap.manifest.version,
|
|
1045
|
-
shasum: fetchedSnap.manifest.source.shasum,
|
|
1027
|
+
version: fetchedSnap.manifest.result.version,
|
|
1028
|
+
shasum: fetchedSnap.manifest.result.source.shasum,
|
|
1046
1029
|
});
|
|
1047
1030
|
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, Object.assign(Object.assign(Object.assign({}, args), fetchedSnap), { id: snapId }));
|
|
1048
1031
|
})();
|
|
@@ -1109,25 +1092,23 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1109
1092
|
}
|
|
1110
1093
|
return dedupedEndowments;
|
|
1111
1094
|
}, _SnapController_set = function _SnapController_set(args) {
|
|
1112
|
-
var _a;
|
|
1113
|
-
const { id: snapId, origin, manifest,
|
|
1114
|
-
(0, snaps_utils_1.assertIsSnapManifest)(manifest);
|
|
1115
|
-
const { version } = manifest;
|
|
1095
|
+
var _a, _b;
|
|
1096
|
+
const { id: snapId, origin, manifest, files, versionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION, isUpdate = false, } = args;
|
|
1097
|
+
(0, snaps_utils_1.assertIsSnapManifest)(manifest.result);
|
|
1098
|
+
const { version } = manifest.result;
|
|
1116
1099
|
if (!(0, snaps_utils_1.satisfiesVersionRange)(version, versionRange)) {
|
|
1117
1100
|
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${version}" which doesn't satisfy requested version range "${versionRange}"`);
|
|
1118
1101
|
}
|
|
1102
|
+
const sourceCode = (_a = files
|
|
1103
|
+
.find((file) => file.path === manifest.result.source.location.npm.filePath)) === null || _a === void 0 ? void 0 : _a.toString();
|
|
1104
|
+
const svgIcon = files.find((file) => file.path === manifest.result.source.location.npm.iconPath);
|
|
1105
|
+
(0, utils_1.assert)(sourceCode !== undefined);
|
|
1119
1106
|
if (typeof sourceCode !== 'string' || sourceCode.length === 0) {
|
|
1120
1107
|
throw new Error(`Invalid source code for snap "${snapId}".`);
|
|
1121
1108
|
}
|
|
1122
|
-
const initialPermissions = manifest === null || manifest === void 0 ? void 0 : manifest.initialPermissions;
|
|
1123
|
-
if (!initialPermissions ||
|
|
1124
|
-
typeof initialPermissions !== 'object' ||
|
|
1125
|
-
Array.isArray(initialPermissions)) {
|
|
1126
|
-
throw new Error(`Invalid initial permissions for snap "${snapId}".`);
|
|
1127
|
-
}
|
|
1128
1109
|
const snapsState = this.state.snaps;
|
|
1129
1110
|
const existingSnap = snapsState[snapId];
|
|
1130
|
-
const previousVersionHistory = (
|
|
1111
|
+
const previousVersionHistory = (_b = existingSnap === null || existingSnap === void 0 ? void 0 : existingSnap.versionHistory) !== null && _b !== void 0 ? _b : [];
|
|
1131
1112
|
const versionHistory = [
|
|
1132
1113
|
...previousVersionHistory,
|
|
1133
1114
|
{
|
|
@@ -1141,52 +1122,54 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1141
1122
|
// previous state.
|
|
1142
1123
|
blocked: false, enabled: true,
|
|
1143
1124
|
// So we can easily correlate the snap with its permission
|
|
1144
|
-
permissionName: (0, snaps_utils_1.getSnapPermissionName)(snapId), id: snapId, initialPermissions,
|
|
1145
|
-
manifest, status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial, version,
|
|
1125
|
+
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,
|
|
1146
1126
|
versionHistory });
|
|
1147
1127
|
// If the snap was blocked, it isn't any longer
|
|
1148
1128
|
delete snap.blockInformation;
|
|
1149
1129
|
// store the snap back in state
|
|
1150
|
-
this.update((state) => {
|
|
1130
|
+
const { inversePatches } = this.update((state) => {
|
|
1151
1131
|
state.snaps[snapId] = snap;
|
|
1152
1132
|
});
|
|
1133
|
+
// checking for isUpdate here as this function is also used in
|
|
1134
|
+
// the install flow, we do not care to create snapshots for installs
|
|
1135
|
+
if (isUpdate) {
|
|
1136
|
+
const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
|
|
1137
|
+
if (rollbackSnapshot !== undefined) {
|
|
1138
|
+
rollbackSnapshot.statePatches = inversePatches;
|
|
1139
|
+
}
|
|
1140
|
+
}
|
|
1153
1141
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1154
1142
|
runtime.sourceCode = sourceCode;
|
|
1155
|
-
this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon);
|
|
1143
|
+
this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon === null || svgIcon === void 0 ? void 0 : svgIcon.toString());
|
|
1156
1144
|
return Object.assign(Object.assign({}, snap), { sourceCode });
|
|
1157
|
-
},
|
|
1158
|
-
if (!(0, snaps_utils_1.isValidSemVerRange)(versionRange)) {
|
|
1159
|
-
throw new Error(`Received invalid Snap version range: "${versionRange}".`);
|
|
1160
|
-
}
|
|
1161
|
-
const { manifest, sourceCode, svgIcon } = await (0, utils_3.fetchNpmSnap)(packageName, versionRange, __classPrivateFieldGet(this, _SnapController_npmRegistryUrl, "f"), __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"));
|
|
1162
|
-
return { manifest, sourceCode, svgIcon };
|
|
1163
|
-
}, _SnapController_fetchLocalSnap =
|
|
1145
|
+
}, _SnapController_fetchSnap =
|
|
1164
1146
|
/**
|
|
1165
|
-
* Fetches the manifest and source code of a
|
|
1147
|
+
* Fetches the manifest and source code of a snap.
|
|
1148
|
+
*
|
|
1149
|
+
* This function is not hash private yet because of tests.
|
|
1166
1150
|
*
|
|
1167
|
-
* @param
|
|
1168
|
-
* @
|
|
1151
|
+
* @param snapId - The id of the Snap.
|
|
1152
|
+
* @param location - Source from which snap will be fetched.
|
|
1153
|
+
* @returns A tuple of the Snap manifest object and the Snap source code.
|
|
1169
1154
|
*/
|
|
1170
|
-
async function
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
(0, snaps_utils_1.validateSnapShasum)(manifest, sourceCode);
|
|
1189
|
-
return { manifest, sourceCode, svgIcon };
|
|
1155
|
+
async function _SnapController_fetchSnap(snapId, location) {
|
|
1156
|
+
try {
|
|
1157
|
+
const manifest = await location.manifest();
|
|
1158
|
+
const sourceCode = await location.fetch(manifest.result.source.location.npm.filePath);
|
|
1159
|
+
(0, snaps_utils_1.validateSnapShasum)(manifest.result, sourceCode.toString());
|
|
1160
|
+
const { iconPath } = manifest.result.source.location.npm;
|
|
1161
|
+
const files = [sourceCode];
|
|
1162
|
+
if (iconPath) {
|
|
1163
|
+
files.push(await location.fetch(iconPath));
|
|
1164
|
+
}
|
|
1165
|
+
return { manifest, files, location };
|
|
1166
|
+
}
|
|
1167
|
+
catch (error) {
|
|
1168
|
+
// TODO(ritave): Export `getErrorMessage()` from @metamask/utils and use it here
|
|
1169
|
+
// https://github.com/MetaMask/utils/blob/62d022ef83c91fa4d150e51913be4441508a0ab1/src/assert.ts
|
|
1170
|
+
const message = error instanceof Error ? error.message : error.toString();
|
|
1171
|
+
throw new Error(`Failed to fetch Snap "${snapId}": ${message}.`);
|
|
1172
|
+
}
|
|
1190
1173
|
}, _SnapController_processSnapPermissions = function _SnapController_processSnapPermissions(initialPermissions) {
|
|
1191
1174
|
return (0, snaps_utils_1.fromEntries)(Object.entries(initialPermissions).map(([initialPermission, value]) => {
|
|
1192
1175
|
if ((0, utils_1.hasProperty)(rpc_methods_1.caveatMappers, initialPermission)) {
|
|
@@ -1198,8 +1181,11 @@ async function _SnapController_fetchLocalSnap(localhostUrl) {
|
|
|
1198
1181
|
endowments_1.endowmentCaveatMappers[initialPermission](value),
|
|
1199
1182
|
];
|
|
1200
1183
|
}
|
|
1201
|
-
|
|
1202
|
-
return [
|
|
1184
|
+
// If we have no mapping, this may be a non-snap permission, return as-is
|
|
1185
|
+
return [
|
|
1186
|
+
initialPermission,
|
|
1187
|
+
value,
|
|
1188
|
+
];
|
|
1203
1189
|
}));
|
|
1204
1190
|
}, _SnapController_getRpcRequestHandler = function _SnapController_getRpcRequestHandler(snapId) {
|
|
1205
1191
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
@@ -1297,6 +1283,72 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1297
1283
|
if (runtime.pendingInboundRequests.length === 0) {
|
|
1298
1284
|
runtime.lastRequest = Date.now();
|
|
1299
1285
|
}
|
|
1286
|
+
}, _SnapController_getRollbackSnapshot = function _SnapController_getRollbackSnapshot(snapId) {
|
|
1287
|
+
return __classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").get(snapId);
|
|
1288
|
+
}, _SnapController_createRollbackSnapshot = function _SnapController_createRollbackSnapshot(snapId) {
|
|
1289
|
+
(0, utils_1.assert)(__classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").get(snapId) === undefined, new Error(`Snap "${snapId}" rollback snapshot already exists.`));
|
|
1290
|
+
__classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").set(snapId, {
|
|
1291
|
+
statePatches: [],
|
|
1292
|
+
sourceCode: '',
|
|
1293
|
+
permissions: { revoked: null, granted: [], requestData: null },
|
|
1294
|
+
newVersion: '',
|
|
1295
|
+
});
|
|
1296
|
+
const newRollbackSnapshot = __classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").get(snapId);
|
|
1297
|
+
(0, utils_1.assert)(newRollbackSnapshot !== undefined, new Error(`Snapshot creation failed for ${snapId}.`));
|
|
1298
|
+
return newRollbackSnapshot;
|
|
1299
|
+
}, _SnapController_rollbackSnap =
|
|
1300
|
+
/**
|
|
1301
|
+
* Rolls back a snap to its previous state, permissions
|
|
1302
|
+
* and source code based on the `RollbackSnapshot` that
|
|
1303
|
+
* is captured during the update process. After rolling back,
|
|
1304
|
+
* the function also emits an event indicating that the
|
|
1305
|
+
* snap has been rolled back and it clears the snapshot
|
|
1306
|
+
* for that snap.
|
|
1307
|
+
*
|
|
1308
|
+
* @param snapId - The snap id.
|
|
1309
|
+
* @throws {@link Error}. If a snapshot does not exist.
|
|
1310
|
+
*/
|
|
1311
|
+
async function _SnapController_rollbackSnap(snapId) {
|
|
1312
|
+
var _a;
|
|
1313
|
+
const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
|
|
1314
|
+
if (!rollbackSnapshot) {
|
|
1315
|
+
throw new Error('A snapshot does not exist for this snap.');
|
|
1316
|
+
}
|
|
1317
|
+
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
1318
|
+
const { statePatches, sourceCode, permissions } = rollbackSnapshot;
|
|
1319
|
+
if (statePatches === null || statePatches === void 0 ? void 0 : statePatches.length) {
|
|
1320
|
+
this.applyPatches(statePatches);
|
|
1321
|
+
}
|
|
1322
|
+
if (sourceCode) {
|
|
1323
|
+
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1324
|
+
runtime.sourceCode = sourceCode;
|
|
1325
|
+
}
|
|
1326
|
+
if (permissions.revoked && Object.keys(permissions.revoked).length) {
|
|
1327
|
+
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
1328
|
+
approvedPermissions: permissions.revoked,
|
|
1329
|
+
subject: { origin: snapId },
|
|
1330
|
+
requestData: permissions.requestData,
|
|
1331
|
+
});
|
|
1332
|
+
}
|
|
1333
|
+
if ((_a = permissions.granted) === null || _a === void 0 ? void 0 : _a.length) {
|
|
1334
|
+
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
1335
|
+
[snapId]: permissions.granted,
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
const truncatedSnap = this.getTruncatedExpect(snapId);
|
|
1339
|
+
this.messagingSystem.publish('SnapController:snapRolledback', truncatedSnap, rollbackSnapshot.newVersion);
|
|
1340
|
+
__classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").delete(snapId);
|
|
1341
|
+
}, _SnapController_rollbackSnaps =
|
|
1342
|
+
/**
|
|
1343
|
+
* Iterates through an array of snap ids
|
|
1344
|
+
* and calls `rollbackSnap` on them.
|
|
1345
|
+
*
|
|
1346
|
+
* @param snapIds - An array of snap ids.
|
|
1347
|
+
*/
|
|
1348
|
+
async function _SnapController_rollbackSnaps(snapIds) {
|
|
1349
|
+
for (const snapId of snapIds) {
|
|
1350
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_rollbackSnap).call(this, snapId);
|
|
1351
|
+
}
|
|
1300
1352
|
}, _SnapController_getRuntime = function _SnapController_getRuntime(snapId) {
|
|
1301
1353
|
return this.snapsRuntimeData.get(snapId);
|
|
1302
1354
|
}, _SnapController_getRuntimeExpect = function _SnapController_getRuntimeExpect(snapId) {
|
|
@@ -1327,5 +1379,14 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1327
1379
|
// oldPermissions ∖ (oldPermissions ∖ desiredPermissionsSet) ⟺ oldPermissions ∩ desiredPermissionsSet
|
|
1328
1380
|
const approvedPermissions = (0, utils_2.setDiff)(oldPermissions, unusedPermissions);
|
|
1329
1381
|
return { newPermissions, unusedPermissions, approvedPermissions };
|
|
1382
|
+
}, _SnapController_isValidUpdate = function _SnapController_isValidUpdate(snapId, newVersionRange) {
|
|
1383
|
+
const existingSnap = this.getExpect(snapId);
|
|
1384
|
+
if ((0, snaps_utils_1.satisfiesVersionRange)(existingSnap.version, newVersionRange)) {
|
|
1385
|
+
return false;
|
|
1386
|
+
}
|
|
1387
|
+
if ((0, snaps_utils_1.gtRange)(existingSnap.version, newVersionRange)) {
|
|
1388
|
+
return false;
|
|
1389
|
+
}
|
|
1390
|
+
return true;
|
|
1330
1391
|
};
|
|
1331
1392
|
//# sourceMappingURL=SnapController.js.map
|