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