@metamask/snaps-controllers 0.30.0 → 0.32.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 +11 -8
- package/dist/cronjob/CronjobController.js.map +1 -1
- package/dist/fsm.js +5 -5
- package/dist/fsm.js.map +1 -1
- package/dist/multichain/MultiChainController.js +12 -20
- package/dist/multichain/MultiChainController.js.map +1 -1
- package/dist/multichain/matching.js +3 -4
- package/dist/multichain/matching.js.map +1 -1
- package/dist/services/iframe/IframeExecutionService.js +1 -2
- package/dist/services/iframe/IframeExecutionService.js.map +1 -1
- package/dist/services/node/NodeProcessExecutionService.js +1 -1
- package/dist/services/node/NodeProcessExecutionService.js.map +1 -1
- package/dist/services/node/NodeThreadExecutionService.js +1 -1
- package/dist/services/node/NodeThreadExecutionService.js.map +1 -1
- package/dist/snaps/RequestQueue.js +3 -6
- package/dist/snaps/RequestQueue.js.map +1 -1
- package/dist/snaps/SnapController.d.ts +9 -11
- package/dist/snaps/SnapController.js +285 -188
- package/dist/snaps/SnapController.js.map +1 -1
- package/dist/snaps/endowments/cronjob.js +2 -3
- package/dist/snaps/endowments/cronjob.js.map +1 -1
- package/dist/snaps/endowments/index.js +6 -1
- package/dist/snaps/endowments/index.js.map +1 -1
- package/dist/snaps/endowments/keyring.js +3 -4
- package/dist/snaps/endowments/keyring.js.map +1 -1
- package/dist/snaps/endowments/rpc.js +2 -2
- package/dist/snaps/endowments/rpc.js.map +1 -1
- package/dist/snaps/endowments/transaction-insight.js +4 -5
- package/dist/snaps/endowments/transaction-insight.js.map +1 -1
- package/dist/snaps/location/http.js +9 -3
- package/dist/snaps/location/http.js.map +1 -1
- package/dist/snaps/location/local.js +1 -1
- package/dist/snaps/location/local.js.map +1 -1
- package/dist/snaps/location/location.js +2 -3
- package/dist/snaps/location/location.js.map +1 -1
- package/dist/snaps/location/npm.js +11 -8
- package/dist/snaps/location/npm.js.map +1 -1
- package/dist/snaps/registry/json.d.ts +33 -14
- package/dist/snaps/registry/json.js +119 -44
- package/dist/snaps/registry/json.js.map +1 -1
- package/package.json +33 -13
- package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.d.ts +0 -3
- package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.js +0 -34
- package/dist/services/iframe/test/fixJSDOMPostMessageEventSource.js.map +0 -1
|
@@ -10,20 +10,9 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
|
|
|
10
10
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
11
|
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
12
|
};
|
|
13
|
-
var
|
|
14
|
-
var t = {};
|
|
15
|
-
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
|
|
16
|
-
t[p] = s[p];
|
|
17
|
-
if (s != null && typeof Object.getOwnPropertySymbols === "function")
|
|
18
|
-
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
|
|
19
|
-
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
|
|
20
|
-
t[p[i]] = s[p[i]];
|
|
21
|
-
}
|
|
22
|
-
return t;
|
|
23
|
-
};
|
|
24
|
-
var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_registry, _SnapController_maxIdleTime, _SnapController_detectSnapLocation, _SnapController_rollbackSnapshots, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsInstallAllowed, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_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;
|
|
13
|
+
var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_excludedPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _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_createApproval, _SnapController_updateApproval, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_fetchSnap, _SnapController_processSnapPermissions, _SnapController_validateSnapPermissions, _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
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.SnapController = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
|
|
15
|
+
exports.SnapController = exports.SNAP_APPROVAL_RESULT = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
|
|
27
16
|
const base_controller_1 = require("@metamask/base-controller");
|
|
28
17
|
const rpc_methods_1 = require("@metamask/rpc-methods");
|
|
29
18
|
const snaps_utils_1 = require("@metamask/snaps-utils");
|
|
@@ -45,6 +34,7 @@ exports.controllerName = 'SnapController';
|
|
|
45
34
|
// TODO: Figure out how to name these
|
|
46
35
|
exports.SNAP_APPROVAL_INSTALL = 'wallet_installSnap';
|
|
47
36
|
exports.SNAP_APPROVAL_UPDATE = 'wallet_updateSnap';
|
|
37
|
+
exports.SNAP_APPROVAL_RESULT = 'wallet_installSnapResult';
|
|
48
38
|
const TRUNCATED_SNAP_PROPERTIES = new Set([
|
|
49
39
|
'initialPermissions',
|
|
50
40
|
'id',
|
|
@@ -81,8 +71,7 @@ const name = 'SnapController';
|
|
|
81
71
|
* - Start: Initializes the snap in its SES realm with the authorized permissions.
|
|
82
72
|
*/
|
|
83
73
|
class SnapController extends base_controller_1.BaseControllerV2 {
|
|
84
|
-
constructor({ closeAllConnections, messenger, state, environmentEndowmentPermissions = [], excludedPermissions = {}, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second),
|
|
85
|
-
var _a, _b;
|
|
74
|
+
constructor({ closeAllConnections, messenger, state, environmentEndowmentPermissions = [], excludedPermissions = {}, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second), 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, }) {
|
|
86
75
|
super({
|
|
87
76
|
messenger,
|
|
88
77
|
metadata: {
|
|
@@ -103,9 +92,12 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
103
92
|
persist: (snaps) => {
|
|
104
93
|
return Object.values(snaps)
|
|
105
94
|
.map((snap) => {
|
|
106
|
-
return
|
|
95
|
+
return {
|
|
96
|
+
...snap,
|
|
97
|
+
sourceCode: __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snap.id).sourceCode,
|
|
107
98
|
// At the time state is rehydrated, no snap will be running.
|
|
108
|
-
status: snaps_utils_1.SnapStatus.Stopped
|
|
99
|
+
status: snaps_utils_1.SnapStatus.Stopped,
|
|
100
|
+
};
|
|
109
101
|
})
|
|
110
102
|
.reduce((memo, snap) => {
|
|
111
103
|
memo[snap.id] = snap;
|
|
@@ -116,12 +108,18 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
116
108
|
},
|
|
117
109
|
},
|
|
118
110
|
name,
|
|
119
|
-
state:
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
111
|
+
state: {
|
|
112
|
+
...defaultState,
|
|
113
|
+
...{
|
|
114
|
+
...state,
|
|
115
|
+
snaps: Object.values(state?.snaps ?? {}).reduce((memo, snap) => {
|
|
116
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
117
|
+
const { sourceCode, ...rest } = snap;
|
|
118
|
+
memo[snap.id] = rest;
|
|
119
|
+
return memo;
|
|
120
|
+
}, {}),
|
|
121
|
+
},
|
|
122
|
+
},
|
|
125
123
|
});
|
|
126
124
|
_SnapController_instances.add(this);
|
|
127
125
|
_SnapController_closeAllConnections.set(this, void 0);
|
|
@@ -130,7 +128,6 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
130
128
|
_SnapController_featureFlags.set(this, void 0);
|
|
131
129
|
_SnapController_fetchFunction.set(this, void 0);
|
|
132
130
|
_SnapController_idleTimeCheckInterval.set(this, void 0);
|
|
133
|
-
_SnapController_registry.set(this, void 0);
|
|
134
131
|
_SnapController_maxIdleTime.set(this, void 0);
|
|
135
132
|
_SnapController_detectSnapLocation.set(this, void 0);
|
|
136
133
|
_SnapController_rollbackSnapshots.set(this, void 0);
|
|
@@ -142,7 +139,6 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
142
139
|
__classPrivateFieldSet(this, _SnapController_featureFlags, featureFlags, "f");
|
|
143
140
|
__classPrivateFieldSet(this, _SnapController_fetchFunction, fetchFunction, "f");
|
|
144
141
|
__classPrivateFieldSet(this, _SnapController_idleTimeCheckInterval, idleTimeCheckInterval, "f");
|
|
145
|
-
__classPrivateFieldSet(this, _SnapController_registry, registry, "f");
|
|
146
142
|
__classPrivateFieldSet(this, _SnapController_maxIdleTime, maxIdleTime, "f");
|
|
147
143
|
this.maxRequestTime = maxRequestTime;
|
|
148
144
|
__classPrivateFieldSet(this, _SnapController_detectSnapLocation, detectSnapLocationFunction, "f");
|
|
@@ -159,13 +155,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
159
155
|
/* eslint-enable @typescript-eslint/unbound-method */
|
|
160
156
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_initializeStateMachine).call(this);
|
|
161
157
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_registerMessageHandlers).call(this);
|
|
162
|
-
Object.values(
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
state: (_b = (_a = state === null || state === void 0 ? void 0 : state.snapStates) === null || _a === void 0 ? void 0 : _a[snap.id]) !== null && _b !== void 0 ? _b : null,
|
|
167
|
-
});
|
|
168
|
-
});
|
|
158
|
+
Object.values(state?.snaps ?? {}).forEach((snap) => __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snap.id, {
|
|
159
|
+
sourceCode: snap.sourceCode,
|
|
160
|
+
state: state?.snapStates?.[snap.id] ?? null,
|
|
161
|
+
}));
|
|
169
162
|
}
|
|
170
163
|
/**
|
|
171
164
|
* Checks all installed snaps against the block list and
|
|
@@ -173,7 +166,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
173
166
|
* for more information.
|
|
174
167
|
*/
|
|
175
168
|
async updateBlockedSnaps() {
|
|
176
|
-
const blockedSnaps = await
|
|
169
|
+
const blockedSnaps = await this.messagingSystem.call('SnapsRegistry:get', Object.values(this.state.snaps).reduce((blockListArg, snap) => {
|
|
177
170
|
blockListArg[snap.id] = {
|
|
178
171
|
version: snap.version,
|
|
179
172
|
checksum: snap.manifest.source.shasum,
|
|
@@ -388,7 +381,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
388
381
|
addSnapError(snapError) {
|
|
389
382
|
this.update((state) => {
|
|
390
383
|
const id = (0, nanoid_1.nanoid)();
|
|
391
|
-
state.snapErrors[id] =
|
|
384
|
+
state.snapErrors[id] = {
|
|
385
|
+
...snapError,
|
|
386
|
+
internalID: id,
|
|
387
|
+
};
|
|
392
388
|
});
|
|
393
389
|
}
|
|
394
390
|
/**
|
|
@@ -419,7 +415,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
419
415
|
*/
|
|
420
416
|
async getSnapState(snapId) {
|
|
421
417
|
const { state } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
422
|
-
return state
|
|
418
|
+
return state ?? null;
|
|
423
419
|
}
|
|
424
420
|
/**
|
|
425
421
|
* Completely clear the controller's state: delete all associated data,
|
|
@@ -517,13 +513,12 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
517
513
|
* @returns The serialized permitted snaps for the origin.
|
|
518
514
|
*/
|
|
519
515
|
getPermittedSnaps(origin) {
|
|
520
|
-
|
|
521
|
-
const
|
|
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 : {};
|
|
516
|
+
const permissions = this.messagingSystem.call('PermissionController:getPermissions', origin) ?? {};
|
|
517
|
+
const snaps = permissions[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds)?.value ?? {};
|
|
523
518
|
return Object.keys(snaps).reduce((permittedSnaps, snapId) => {
|
|
524
519
|
const snap = this.get(snapId);
|
|
525
520
|
const truncatedSnap = this.getTruncated(snapId);
|
|
526
|
-
if (truncatedSnap &&
|
|
521
|
+
if (truncatedSnap && snap?.status !== snaps_utils_1.SnapStatus.Installing) {
|
|
527
522
|
permittedSnaps[snapId] = truncatedSnap;
|
|
528
523
|
}
|
|
529
524
|
return permittedSnaps;
|
|
@@ -542,22 +537,25 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
542
537
|
async installSnaps(origin, requestedSnaps) {
|
|
543
538
|
const result = {};
|
|
544
539
|
const snapIds = Object.keys(requestedSnaps);
|
|
545
|
-
|
|
546
|
-
const
|
|
547
|
-
// Non-existing snaps will need to be installed
|
|
548
|
-
const pendingInstalls = snapIds.filter((snapId) => !pendingUpdates.includes(snapId));
|
|
540
|
+
const pendingUpdates = [];
|
|
541
|
+
const pendingInstalls = [];
|
|
549
542
|
try {
|
|
550
543
|
for (const [snapId, { version: rawVersion }] of Object.entries(requestedSnaps)) {
|
|
544
|
+
(0, snaps_utils_1.assertIsValidSnapId)(snapId);
|
|
551
545
|
const [error, version] = (0, snaps_utils_1.resolveVersionRange)(rawVersion);
|
|
552
546
|
if (error) {
|
|
553
547
|
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${rawVersion}".`);
|
|
554
548
|
}
|
|
555
|
-
const
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
549
|
+
const location = __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, {
|
|
550
|
+
versionRange: version,
|
|
551
|
+
fetch: __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"),
|
|
552
|
+
allowLocal: __classPrivateFieldGet(this, _SnapController_featureFlags, "f").allowLocalSnaps,
|
|
553
|
+
});
|
|
554
|
+
// Existing snaps may need to be updated, unless they should be re-installed (e.g. local snaps)
|
|
555
|
+
// Everything else is treated as an install
|
|
556
|
+
const isUpdate = this.has(snapId) && !location.shouldAlwaysReload;
|
|
560
557
|
if (isUpdate && __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_isValidUpdate).call(this, snapId, version)) {
|
|
558
|
+
pendingUpdates.push(snapId);
|
|
561
559
|
let rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
|
|
562
560
|
if (rollbackSnapshot === undefined) {
|
|
563
561
|
const prevSourceCode = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId).sourceCode;
|
|
@@ -569,7 +567,10 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
569
567
|
throw new Error('This snap is already being updated.');
|
|
570
568
|
}
|
|
571
569
|
}
|
|
572
|
-
|
|
570
|
+
else if (!isUpdate) {
|
|
571
|
+
pendingInstalls.push(snapId);
|
|
572
|
+
}
|
|
573
|
+
result[snapId] = await this.processRequestedSnap(origin, snapId, location, version);
|
|
573
574
|
}
|
|
574
575
|
snapIds.forEach((snapId) => __classPrivateFieldGet(this, _SnapController_rollbackSnapshots, "f").delete(snapId));
|
|
575
576
|
}
|
|
@@ -589,16 +590,11 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
589
590
|
*
|
|
590
591
|
* @param origin - The origin requesting the snap.
|
|
591
592
|
* @param snapId - The id of the snap.
|
|
593
|
+
* @param location - The location implementation of the snap.
|
|
592
594
|
* @param versionRange - The semver range of the snap to install.
|
|
593
595
|
* @returns The resulting snap object, or an error if something went wrong.
|
|
594
596
|
*/
|
|
595
|
-
async processRequestedSnap(origin, snapId, versionRange) {
|
|
596
|
-
(0, snaps_utils_1.validateSnapId)(snapId);
|
|
597
|
-
const location = __classPrivateFieldGet(this, _SnapController_detectSnapLocation, "f").call(this, snapId, {
|
|
598
|
-
versionRange,
|
|
599
|
-
fetch: __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"),
|
|
600
|
-
allowLocal: __classPrivateFieldGet(this, _SnapController_featureFlags, "f").allowLocalSnaps,
|
|
601
|
-
});
|
|
597
|
+
async processRequestedSnap(origin, snapId, location, versionRange) {
|
|
602
598
|
const existingSnap = this.getTruncated(snapId);
|
|
603
599
|
// For devX we always re-install local snaps.
|
|
604
600
|
if (existingSnap && !location.shouldAlwaysReload) {
|
|
@@ -606,35 +602,55 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
606
602
|
return existingSnap;
|
|
607
603
|
}
|
|
608
604
|
if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").dappsCanUpdateSnaps === true) {
|
|
609
|
-
|
|
610
|
-
if (updateResult === null) {
|
|
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.`);
|
|
612
|
-
}
|
|
613
|
-
return updateResult;
|
|
605
|
+
return await this.updateSnap(origin, snapId, location, versionRange);
|
|
614
606
|
}
|
|
615
607
|
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Version mismatch with already installed snap. ${snapId}@${existingSnap.version} doesn't satisfy requested version ${versionRange}.`);
|
|
616
608
|
}
|
|
609
|
+
let pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
|
|
610
|
+
origin,
|
|
611
|
+
snapId,
|
|
612
|
+
type: exports.SNAP_APPROVAL_INSTALL,
|
|
613
|
+
});
|
|
617
614
|
// Existing snaps must be stopped before overwriting
|
|
618
615
|
if (existingSnap && this.isRunning(snapId)) {
|
|
619
616
|
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
620
617
|
}
|
|
618
|
+
// Existing snaps that should be re-installed should not maintain their existing permissions
|
|
619
|
+
if (existingSnap && location.shouldAlwaysReload) {
|
|
620
|
+
this.revokeAllSnapPermissions(snapId);
|
|
621
|
+
}
|
|
621
622
|
try {
|
|
622
623
|
const { sourceCode } = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_add).call(this, {
|
|
623
624
|
origin,
|
|
624
625
|
id: snapId,
|
|
625
626
|
location,
|
|
627
|
+
versionRange,
|
|
628
|
+
});
|
|
629
|
+
await this.authorize(snapId, pendingApproval);
|
|
630
|
+
pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
|
|
631
|
+
origin,
|
|
632
|
+
snapId,
|
|
633
|
+
type: exports.SNAP_APPROVAL_RESULT,
|
|
626
634
|
});
|
|
627
|
-
await this.authorize(origin, snapId);
|
|
628
635
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, {
|
|
629
636
|
snapId,
|
|
630
637
|
sourceCode,
|
|
631
638
|
});
|
|
632
639
|
const truncated = this.getTruncatedExpect(snapId);
|
|
640
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
|
|
641
|
+
loading: false,
|
|
642
|
+
type: exports.SNAP_APPROVAL_INSTALL,
|
|
643
|
+
});
|
|
633
644
|
this.messagingSystem.publish(`SnapController:snapInstalled`, truncated);
|
|
634
645
|
return truncated;
|
|
635
646
|
}
|
|
636
647
|
catch (error) {
|
|
637
648
|
(0, snaps_utils_1.logError)(`Error when adding snap.`, error);
|
|
649
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
|
|
650
|
+
loading: false,
|
|
651
|
+
type: exports.SNAP_APPROVAL_INSTALL,
|
|
652
|
+
error: error instanceof Error ? error.message : error.toString(),
|
|
653
|
+
});
|
|
638
654
|
throw error;
|
|
639
655
|
}
|
|
640
656
|
}
|
|
@@ -652,88 +668,108 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
652
668
|
*
|
|
653
669
|
* @param origin - The origin requesting the snap update.
|
|
654
670
|
* @param snapId - The id of the Snap to be updated.
|
|
655
|
-
* @param location -
|
|
671
|
+
* @param location - The location implementation of the snap.
|
|
656
672
|
* @param newVersionRange - A semver version range in which the maximum version will be chosen.
|
|
657
673
|
* @returns The snap metadata if updated, `null` otherwise.
|
|
658
674
|
*/
|
|
659
675
|
async updateSnap(origin, snapId, location, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION) {
|
|
660
|
-
var _a;
|
|
661
|
-
const snap = this.getExpect(snapId);
|
|
662
676
|
if (!(0, utils_1.isValidSemVerRange)(newVersionRange)) {
|
|
663
677
|
throw new Error(`Received invalid snap version range: "${newVersionRange}".`);
|
|
664
678
|
}
|
|
665
|
-
|
|
666
|
-
const newVersion = newSnap.manifest.result.version;
|
|
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`);
|
|
669
|
-
return null;
|
|
670
|
-
}
|
|
671
|
-
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
|
|
672
|
-
version: newVersion,
|
|
673
|
-
checksum: newSnap.manifest.result.source.shasum,
|
|
674
|
-
});
|
|
675
|
-
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.result.initialPermissions);
|
|
676
|
-
const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
677
|
-
const id = (0, nanoid_1.nanoid)();
|
|
678
|
-
const _b = (await this.messagingSystem.call('ApprovalController:addRequest', {
|
|
679
|
+
let pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
|
|
679
680
|
origin,
|
|
680
|
-
|
|
681
|
+
snapId,
|
|
681
682
|
type: exports.SNAP_APPROVAL_UPDATE,
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
683
|
+
});
|
|
684
|
+
try {
|
|
685
|
+
const snap = this.getExpect(snapId);
|
|
686
|
+
const newSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
|
|
687
|
+
const newVersion = newSnap.manifest.result.version;
|
|
688
|
+
if (!(0, utils_1.gtVersion)(newVersion, snap.version)) {
|
|
689
|
+
throw eth_rpc_errors_1.ethErrors.rpc.invalidParams(`Snap "${snapId}@${snap.version}" is already installed. Couldn't update to a version inside requested "${newVersionRange}" range.`);
|
|
690
|
+
}
|
|
691
|
+
if (!(0, utils_1.satisfiesVersionRange)(newVersion, newVersionRange)) {
|
|
692
|
+
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${newVersion}" which doesn't satisfy requested version range "${newVersionRange}".`);
|
|
693
|
+
}
|
|
694
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
|
|
695
|
+
version: newVersion,
|
|
696
|
+
checksum: newSnap.manifest.result.source.shasum,
|
|
697
|
+
});
|
|
698
|
+
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.result.initialPermissions);
|
|
699
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_validateSnapPermissions).call(this, processedPermissions);
|
|
700
|
+
const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
701
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
|
|
685
702
|
permissions: newPermissions,
|
|
686
|
-
snapId,
|
|
687
703
|
newVersion: newSnap.manifest.result.version,
|
|
688
704
|
newPermissions,
|
|
689
705
|
approvedPermissions,
|
|
690
706
|
unusedPermissions,
|
|
691
|
-
|
|
692
|
-
}, true)), { permissions: approvedNewPermissions } = _b, requestData = __rest(_b, ["permissions"]);
|
|
693
|
-
if (this.isRunning(snapId)) {
|
|
694
|
-
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
695
|
-
}
|
|
696
|
-
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Update);
|
|
697
|
-
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, {
|
|
698
|
-
origin,
|
|
699
|
-
id: snapId,
|
|
700
|
-
manifest: newSnap.manifest,
|
|
701
|
-
files: newSnap.files,
|
|
702
|
-
versionRange: newVersionRange,
|
|
703
|
-
isUpdate: true,
|
|
704
|
-
});
|
|
705
|
-
const unusedPermissionsKeys = Object.keys(unusedPermissions);
|
|
706
|
-
if ((0, utils_1.isNonEmptyArray)(unusedPermissionsKeys)) {
|
|
707
|
-
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
708
|
-
[snapId]: unusedPermissionsKeys,
|
|
707
|
+
loading: false,
|
|
709
708
|
});
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
requestData,
|
|
709
|
+
const { permissions: approvedNewPermissions, ...requestData } = (await pendingApproval.promise);
|
|
710
|
+
pendingApproval = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_createApproval).call(this, {
|
|
711
|
+
origin,
|
|
712
|
+
snapId,
|
|
713
|
+
type: exports.SNAP_APPROVAL_RESULT,
|
|
716
714
|
});
|
|
715
|
+
if (this.isRunning(snapId)) {
|
|
716
|
+
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
717
|
+
}
|
|
718
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Update);
|
|
719
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, {
|
|
720
|
+
origin,
|
|
721
|
+
id: snapId,
|
|
722
|
+
manifest: newSnap.manifest,
|
|
723
|
+
files: newSnap.files,
|
|
724
|
+
isUpdate: true,
|
|
725
|
+
});
|
|
726
|
+
const unusedPermissionsKeys = Object.keys(unusedPermissions);
|
|
727
|
+
if ((0, utils_1.isNonEmptyArray)(unusedPermissionsKeys)) {
|
|
728
|
+
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
729
|
+
[snapId]: unusedPermissionsKeys,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedNewPermissions))) {
|
|
733
|
+
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
734
|
+
approvedPermissions: approvedNewPermissions,
|
|
735
|
+
subject: { origin: snapId },
|
|
736
|
+
requestData,
|
|
737
|
+
});
|
|
738
|
+
}
|
|
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 normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(newSnap.manifest.result.source.location.npm.filePath);
|
|
746
|
+
const sourceCode = newSnap.files
|
|
747
|
+
.find((file) => file.path === normalizedSourcePath)
|
|
748
|
+
?.toString();
|
|
749
|
+
(0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
|
|
750
|
+
try {
|
|
751
|
+
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
|
|
752
|
+
}
|
|
753
|
+
catch {
|
|
754
|
+
throw new Error(`Snap ${snapId} crashed with updated source code.`);
|
|
755
|
+
}
|
|
756
|
+
const truncatedSnap = this.getTruncatedExpect(snapId);
|
|
757
|
+
this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
|
|
758
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
|
|
759
|
+
loading: false,
|
|
760
|
+
type: exports.SNAP_APPROVAL_UPDATE,
|
|
761
|
+
});
|
|
762
|
+
return truncatedSnap;
|
|
717
763
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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}".`);
|
|
728
|
-
try {
|
|
729
|
-
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_startSnap).call(this, { snapId, sourceCode });
|
|
730
|
-
}
|
|
731
|
-
catch (_c) {
|
|
732
|
-
throw new Error(`Snap ${snapId} crashed with updated source code.`);
|
|
764
|
+
catch (error) {
|
|
765
|
+
(0, snaps_utils_1.logError)(`Error when updating snap,`, error);
|
|
766
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
|
|
767
|
+
loading: false,
|
|
768
|
+
error: error instanceof Error ? error.message : error.toString(),
|
|
769
|
+
type: exports.SNAP_APPROVAL_UPDATE,
|
|
770
|
+
});
|
|
771
|
+
throw error;
|
|
733
772
|
}
|
|
734
|
-
const truncatedSnap = this.getTruncatedExpect(snapId);
|
|
735
|
-
this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
|
|
736
|
-
return truncatedSnap;
|
|
737
773
|
}
|
|
738
774
|
/**
|
|
739
775
|
* Get metadata for the given snap ID.
|
|
@@ -743,7 +779,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
743
779
|
* verified.
|
|
744
780
|
*/
|
|
745
781
|
async getRegistryMetadata(snapId) {
|
|
746
|
-
return await
|
|
782
|
+
return await this.messagingSystem.call('SnapsRegistry:getMetadata', snapId);
|
|
747
783
|
}
|
|
748
784
|
/**
|
|
749
785
|
* Initiates a request for the given snap's initial permissions.
|
|
@@ -751,36 +787,23 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
751
787
|
*
|
|
752
788
|
* This function is not hash private yet because of tests.
|
|
753
789
|
*
|
|
754
|
-
* @param origin - The origin of the install request.
|
|
755
790
|
* @param snapId - The id of the Snap.
|
|
791
|
+
* @param pendingApproval - Pending approval to update.
|
|
756
792
|
* @returns The snap's approvedPermissions.
|
|
757
793
|
*/
|
|
758
|
-
async authorize(
|
|
794
|
+
async authorize(snapId, pendingApproval) {
|
|
759
795
|
(0, logging_1.log)(`Authorizing snap: ${snapId}`);
|
|
760
796
|
const snapsState = this.state.snaps;
|
|
761
797
|
const snap = snapsState[snapId];
|
|
762
798
|
const { initialPermissions } = snap;
|
|
763
799
|
try {
|
|
764
800
|
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, initialPermissions);
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
(0, utils_1.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
|
|
772
|
-
const id = (0, nanoid_1.nanoid)();
|
|
773
|
-
const _a = (await this.messagingSystem.call('ApprovalController:addRequest', {
|
|
774
|
-
origin,
|
|
775
|
-
id,
|
|
776
|
-
type: exports.SNAP_APPROVAL_INSTALL,
|
|
777
|
-
requestData: {
|
|
778
|
-
// Mirror previous installation metadata
|
|
779
|
-
metadata: { id, origin: snapId, dappOrigin: origin },
|
|
780
|
-
permissions: processedPermissions,
|
|
781
|
-
snapId,
|
|
782
|
-
},
|
|
783
|
-
}, true)), { permissions: approvedPermissions } = _a, requestData = __rest(_a, ["permissions"]);
|
|
801
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_validateSnapPermissions).call(this, processedPermissions);
|
|
802
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_updateApproval).call(this, pendingApproval.id, {
|
|
803
|
+
loading: false,
|
|
804
|
+
permissions: processedPermissions,
|
|
805
|
+
});
|
|
806
|
+
const { permissions: approvedPermissions, ...requestData } = (await pendingApproval.promise);
|
|
784
807
|
if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedPermissions))) {
|
|
785
808
|
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
786
809
|
approvedPermissions,
|
|
@@ -823,9 +846,9 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
823
846
|
}
|
|
824
847
|
if (permissionName === endowments_1.SnapEndowments.Rpc) {
|
|
825
848
|
const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
|
|
826
|
-
const isSnap =
|
|
849
|
+
const isSnap = subject?.subjectType === subject_metadata_controller_1.SubjectType.Snap;
|
|
827
850
|
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
828
|
-
const rpcPermission = permissions
|
|
851
|
+
const rpcPermission = permissions?.[endowments_1.SnapEndowments.Rpc];
|
|
829
852
|
(0, utils_1.assert)(rpcPermission);
|
|
830
853
|
const origins = (0, rpc_1.getRpcCaveatOrigins)(rpcPermission);
|
|
831
854
|
(0, utils_1.assert)(origins);
|
|
@@ -841,7 +864,7 @@ class SnapController extends base_controller_1.BaseControllerV2 {
|
|
|
841
864
|
}
|
|
842
865
|
}
|
|
843
866
|
exports.SnapController = SnapController;
|
|
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(),
|
|
867
|
+
_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_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() {
|
|
845
868
|
const disableGuard = ({ snapId }) => {
|
|
846
869
|
return this.getExpect(snapId).enabled;
|
|
847
870
|
};
|
|
@@ -862,6 +885,7 @@ _SnapController_closeAllConnections = new WeakMap(), _SnapController_environment
|
|
|
862
885
|
target: snaps_utils_1.SnapStatus.Running,
|
|
863
886
|
cond: disableGuard,
|
|
864
887
|
},
|
|
888
|
+
[snaps_utils_1.SnapStatusEvents.Stop]: snaps_utils_1.SnapStatus.Stopped,
|
|
865
889
|
},
|
|
866
890
|
},
|
|
867
891
|
[snaps_utils_1.SnapStatus.Running]: {
|
|
@@ -951,13 +975,12 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
|
|
|
951
975
|
});
|
|
952
976
|
this.messagingSystem.publish(`${exports.controllerName}:snapUnblocked`, snapId);
|
|
953
977
|
}, _SnapController_assertIsInstallAllowed = async function _SnapController_assertIsInstallAllowed(snapId, snapInfo) {
|
|
954
|
-
|
|
955
|
-
const results = await __classPrivateFieldGet(this, _SnapController_registry, "f").get({
|
|
978
|
+
const results = await this.messagingSystem.call('SnapsRegistry:get', {
|
|
956
979
|
[snapId]: snapInfo,
|
|
957
980
|
});
|
|
958
981
|
const result = results[snapId];
|
|
959
982
|
if (result.status === registry_1.SnapsRegistryStatus.Blocked) {
|
|
960
|
-
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${
|
|
983
|
+
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${result.reason?.explanation ?? ''}`);
|
|
961
984
|
}
|
|
962
985
|
else if (__classPrivateFieldGet(this, _SnapController_featureFlags, "f").requireAllowlist &&
|
|
963
986
|
result.status !== registry_1.SnapsRegistryStatus.Verified) {
|
|
@@ -989,14 +1012,16 @@ async function _SnapController_terminateSnap(snapId) {
|
|
|
989
1012
|
await this.messagingSystem.call('ExecutionService:terminateSnap', snapId);
|
|
990
1013
|
this.messagingSystem.publish('SnapController:snapTerminated', this.getTruncatedExpect(snapId));
|
|
991
1014
|
}, _SnapController_removeSnapFromSubjects = function _SnapController_removeSnapFromSubjects(snapId) {
|
|
992
|
-
var _a, _b, _c, _d;
|
|
993
1015
|
const subjects = this.messagingSystem.call('PermissionController:getSubjectNames');
|
|
994
1016
|
for (const subject of subjects) {
|
|
995
1017
|
const subjectPermissions = this.messagingSystem.call('PermissionController:getPermissions', subject);
|
|
996
|
-
const snapIdsCaveat = (
|
|
997
|
-
|
|
1018
|
+
const snapIdsCaveat = (subjectPermissions?.[rpc_methods_1.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat) => caveat.type === snaps_utils_1.SnapCaveatType.SnapIds) ??
|
|
1019
|
+
{});
|
|
1020
|
+
const caveatHasSnap = Boolean(snapIdsCaveat.value?.[snapId]);
|
|
998
1021
|
if (caveatHasSnap) {
|
|
999
|
-
const newCaveatValue =
|
|
1022
|
+
const newCaveatValue = {
|
|
1023
|
+
...snapIdsCaveat.value,
|
|
1024
|
+
};
|
|
1000
1025
|
delete newCaveatValue[snapId];
|
|
1001
1026
|
if (Object.keys(newCaveatValue).length > 0) {
|
|
1002
1027
|
this.messagingSystem.call('PermissionController:updateCaveat', subject, rpc_methods_1.WALLET_SNAP_PERMISSION_KEY, snaps_utils_1.SnapCaveatType.SnapIds, newCaveatValue);
|
|
@@ -1008,6 +1033,32 @@ async function _SnapController_terminateSnap(snapId) {
|
|
|
1008
1033
|
}
|
|
1009
1034
|
}
|
|
1010
1035
|
}
|
|
1036
|
+
}, _SnapController_createApproval = function _SnapController_createApproval({ origin, snapId, type, }) {
|
|
1037
|
+
const id = (0, nanoid_1.nanoid)();
|
|
1038
|
+
const promise = this.messagingSystem.call('ApprovalController:addRequest', {
|
|
1039
|
+
origin,
|
|
1040
|
+
id,
|
|
1041
|
+
type,
|
|
1042
|
+
requestData: {
|
|
1043
|
+
// Mirror previous installation metadata
|
|
1044
|
+
metadata: { id, origin: snapId, dappOrigin: origin },
|
|
1045
|
+
snapId,
|
|
1046
|
+
},
|
|
1047
|
+
requestState: {
|
|
1048
|
+
loading: true,
|
|
1049
|
+
},
|
|
1050
|
+
}, true);
|
|
1051
|
+
return { id, promise };
|
|
1052
|
+
}, _SnapController_updateApproval = function _SnapController_updateApproval(id, requestState) {
|
|
1053
|
+
try {
|
|
1054
|
+
this.messagingSystem.call('ApprovalController:updateRequestState', {
|
|
1055
|
+
id,
|
|
1056
|
+
requestState,
|
|
1057
|
+
});
|
|
1058
|
+
}
|
|
1059
|
+
catch {
|
|
1060
|
+
// Do nothing
|
|
1061
|
+
}
|
|
1011
1062
|
}, _SnapController_add =
|
|
1012
1063
|
/**
|
|
1013
1064
|
* Returns a promise representing the complete installation of the requested snap.
|
|
@@ -1019,8 +1070,7 @@ async function _SnapController_terminateSnap(snapId) {
|
|
|
1019
1070
|
* @returns The resulting snap object.
|
|
1020
1071
|
*/
|
|
1021
1072
|
async function _SnapController_add(args) {
|
|
1022
|
-
const { id: snapId, location } = args;
|
|
1023
|
-
(0, snaps_utils_1.validateSnapId)(snapId);
|
|
1073
|
+
const { id: snapId, location, versionRange } = args;
|
|
1024
1074
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_setupRuntime).call(this, snapId, { sourceCode: null, state: null });
|
|
1025
1075
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1026
1076
|
if (!runtime.installPromise) {
|
|
@@ -1029,11 +1079,20 @@ async function _SnapController_add(args) {
|
|
|
1029
1079
|
// to null in the authorize() method.
|
|
1030
1080
|
runtime.installPromise = (async () => {
|
|
1031
1081
|
const fetchedSnap = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_fetchSnap).call(this, snapId, location);
|
|
1082
|
+
const manifest = fetchedSnap.manifest.result;
|
|
1083
|
+
(0, snaps_utils_1.assertIsSnapManifest)(manifest);
|
|
1084
|
+
if (!(0, utils_1.satisfiesVersionRange)(manifest.version, versionRange)) {
|
|
1085
|
+
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${manifest.version}" which doesn't satisfy requested version range "${versionRange}".`);
|
|
1086
|
+
}
|
|
1032
1087
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_assertIsInstallAllowed).call(this, snapId, {
|
|
1033
|
-
version:
|
|
1034
|
-
checksum:
|
|
1088
|
+
version: manifest.version,
|
|
1089
|
+
checksum: manifest.source.shasum,
|
|
1090
|
+
});
|
|
1091
|
+
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, {
|
|
1092
|
+
...args,
|
|
1093
|
+
...fetchedSnap,
|
|
1094
|
+
id: snapId,
|
|
1035
1095
|
});
|
|
1036
|
-
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_set).call(this, Object.assign(Object.assign(Object.assign({}, args), fetchedSnap), { id: snapId }));
|
|
1037
1096
|
})();
|
|
1038
1097
|
}
|
|
1039
1098
|
try {
|
|
@@ -1051,7 +1110,10 @@ async function _SnapController_add(args) {
|
|
|
1051
1110
|
throw new Error(`Snap "${snapId}" is already started.`);
|
|
1052
1111
|
}
|
|
1053
1112
|
try {
|
|
1054
|
-
const result = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_executeWithTimeout).call(this, snapId, this.messagingSystem.call('ExecutionService:executeSnap',
|
|
1113
|
+
const result = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_executeWithTimeout).call(this, snapId, this.messagingSystem.call('ExecutionService:executeSnap', {
|
|
1114
|
+
...snapData,
|
|
1115
|
+
endowments: await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getEndowments).call(this, snapId),
|
|
1116
|
+
}));
|
|
1055
1117
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Start);
|
|
1056
1118
|
return result;
|
|
1057
1119
|
}
|
|
@@ -1098,25 +1160,22 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1098
1160
|
}
|
|
1099
1161
|
return dedupedEndowments;
|
|
1100
1162
|
}, _SnapController_set = function _SnapController_set(args) {
|
|
1101
|
-
|
|
1102
|
-
const { id: snapId, origin, manifest, files, versionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION, isUpdate = false, } = args;
|
|
1163
|
+
const { id: snapId, origin, manifest, files, isUpdate = false } = args;
|
|
1103
1164
|
(0, snaps_utils_1.assertIsSnapManifest)(manifest.result);
|
|
1104
1165
|
const { version } = manifest.result;
|
|
1105
|
-
if (!(0, utils_1.satisfiesVersionRange)(version, versionRange)) {
|
|
1106
|
-
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${version}" which doesn't satisfy requested version range "${versionRange}"`);
|
|
1107
|
-
}
|
|
1108
1166
|
const normalizedSourcePath = (0, snaps_utils_1.normalizeRelative)(manifest.result.source.location.npm.filePath);
|
|
1109
1167
|
const { iconPath } = manifest.result.source.location.npm;
|
|
1110
1168
|
const normalizedIconPath = iconPath && (0, snaps_utils_1.normalizeRelative)(iconPath);
|
|
1111
|
-
const sourceCode =
|
|
1112
|
-
.find((file) => file.path === normalizedSourcePath)
|
|
1169
|
+
const sourceCode = files
|
|
1170
|
+
.find((file) => file.path === normalizedSourcePath)
|
|
1171
|
+
?.toString();
|
|
1113
1172
|
const svgIcon = normalizedIconPath
|
|
1114
1173
|
? files.find((file) => file.path === normalizedIconPath)
|
|
1115
1174
|
: undefined;
|
|
1116
1175
|
(0, utils_1.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
|
|
1117
1176
|
const snapsState = this.state.snaps;
|
|
1118
1177
|
const existingSnap = snapsState[snapId];
|
|
1119
|
-
const previousVersionHistory =
|
|
1178
|
+
const previousVersionHistory = existingSnap?.versionHistory ?? [];
|
|
1120
1179
|
const versionHistory = [
|
|
1121
1180
|
...previousVersionHistory,
|
|
1122
1181
|
{
|
|
@@ -1125,11 +1184,20 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1125
1184
|
origin,
|
|
1126
1185
|
},
|
|
1127
1186
|
];
|
|
1128
|
-
const snap =
|
|
1187
|
+
const snap = {
|
|
1188
|
+
// Restore relevant snap state if it exists
|
|
1189
|
+
...existingSnap,
|
|
1129
1190
|
// Note that the snap will be unblocked and enabled, regardless of its
|
|
1130
1191
|
// previous state.
|
|
1131
|
-
blocked: false,
|
|
1132
|
-
|
|
1192
|
+
blocked: false,
|
|
1193
|
+
enabled: true,
|
|
1194
|
+
id: snapId,
|
|
1195
|
+
initialPermissions: manifest.result.initialPermissions,
|
|
1196
|
+
manifest: manifest.result,
|
|
1197
|
+
status: __classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial,
|
|
1198
|
+
version,
|
|
1199
|
+
versionHistory,
|
|
1200
|
+
};
|
|
1133
1201
|
// If the snap was blocked, it isn't any longer
|
|
1134
1202
|
delete snap.blockInformation;
|
|
1135
1203
|
// store the snap back in state
|
|
@@ -1146,8 +1214,8 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1146
1214
|
}
|
|
1147
1215
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1148
1216
|
runtime.sourceCode = sourceCode;
|
|
1149
|
-
this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon
|
|
1150
|
-
return
|
|
1217
|
+
this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon?.toString());
|
|
1218
|
+
return { ...snap, sourceCode };
|
|
1151
1219
|
}, _SnapController_fetchSnap =
|
|
1152
1220
|
/**
|
|
1153
1221
|
* Fetches the manifest and source code of a snap.
|
|
@@ -1178,7 +1246,7 @@ async function _SnapController_fetchSnap(snapId, location) {
|
|
|
1178
1246
|
throw new Error(`Failed to fetch Snap "${snapId}": ${message}.`);
|
|
1179
1247
|
}
|
|
1180
1248
|
}, _SnapController_processSnapPermissions = function _SnapController_processSnapPermissions(initialPermissions) {
|
|
1181
|
-
return
|
|
1249
|
+
return Object.fromEntries(Object.entries(initialPermissions).map(([initialPermission, value]) => {
|
|
1182
1250
|
if ((0, utils_1.hasProperty)(rpc_methods_1.caveatMappers, initialPermission)) {
|
|
1183
1251
|
return [initialPermission, rpc_methods_1.caveatMappers[initialPermission](value)];
|
|
1184
1252
|
}
|
|
@@ -1194,6 +1262,17 @@ async function _SnapController_fetchSnap(snapId, location) {
|
|
|
1194
1262
|
value,
|
|
1195
1263
|
];
|
|
1196
1264
|
}));
|
|
1265
|
+
}, _SnapController_validateSnapPermissions = function _SnapController_validateSnapPermissions(processedPermissions) {
|
|
1266
|
+
const permissionKeys = Object.keys(processedPermissions);
|
|
1267
|
+
const handlerPermissions = Object.values(endowments_1.handlerEndowments);
|
|
1268
|
+
(0, utils_1.assert)(permissionKeys.some((key) => handlerPermissions.includes(key)), `A snap must request at least one of the following permissions: ${handlerPermissions.join(', ')}.`);
|
|
1269
|
+
const excludedPermissionErrors = permissionKeys.reduce((errors, permission) => {
|
|
1270
|
+
if ((0, utils_1.hasProperty)(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f"), permission)) {
|
|
1271
|
+
errors.push(__classPrivateFieldGet(this, _SnapController_excludedPermissions, "f")[permission]);
|
|
1272
|
+
}
|
|
1273
|
+
return errors;
|
|
1274
|
+
}, []);
|
|
1275
|
+
(0, utils_1.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
|
|
1197
1276
|
}, _SnapController_getRpcRequestHandler = function _SnapController_getRpcRequestHandler(snapId) {
|
|
1198
1277
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1199
1278
|
const existingHandler = runtime.rpcHandler;
|
|
@@ -1234,7 +1313,7 @@ async function _SnapController_fetchSnap(snapId, location) {
|
|
|
1234
1313
|
}
|
|
1235
1314
|
let _request = request;
|
|
1236
1315
|
if (!(0, utils_1.hasProperty)(request, 'jsonrpc')) {
|
|
1237
|
-
_request =
|
|
1316
|
+
_request = { ...request, jsonrpc: '2.0' };
|
|
1238
1317
|
}
|
|
1239
1318
|
else if (request.jsonrpc !== '2.0') {
|
|
1240
1319
|
throw eth_rpc_errors_1.ethErrors.rpc.invalidRequest({
|
|
@@ -1276,7 +1355,7 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1276
1355
|
(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.`);
|
|
1277
1356
|
return promise;
|
|
1278
1357
|
}
|
|
1279
|
-
const result = await (0, utils_2.withTimeout)(promise, timer
|
|
1358
|
+
const result = await (0, utils_2.withTimeout)(promise, timer ?? this.maxRequestTime);
|
|
1280
1359
|
if (result === utils_2.hasTimedOut) {
|
|
1281
1360
|
throw new Error('The request timed out.');
|
|
1282
1361
|
}
|
|
@@ -1317,16 +1396,26 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1317
1396
|
* @throws {@link Error}. If a snapshot does not exist.
|
|
1318
1397
|
*/
|
|
1319
1398
|
async function _SnapController_rollbackSnap(snapId) {
|
|
1320
|
-
var _a;
|
|
1321
1399
|
const rollbackSnapshot = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRollbackSnapshot).call(this, snapId);
|
|
1322
1400
|
if (!rollbackSnapshot) {
|
|
1323
1401
|
throw new Error('A snapshot does not exist for this snap.');
|
|
1324
1402
|
}
|
|
1325
1403
|
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
1404
|
+
// Always set to stopped even if it wasn't running initially
|
|
1405
|
+
if (this.get(snapId)?.status !== snaps_utils_1.SnapStatus.Stopped) {
|
|
1406
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Stop);
|
|
1407
|
+
}
|
|
1326
1408
|
const { statePatches, sourceCode, permissions } = rollbackSnapshot;
|
|
1327
|
-
if (statePatches
|
|
1409
|
+
if (statePatches?.length) {
|
|
1328
1410
|
this.applyPatches(statePatches);
|
|
1329
1411
|
}
|
|
1412
|
+
// Reset snap status, as we may have been in another state when we stored state patches
|
|
1413
|
+
// But now we are 100% in a stopped state
|
|
1414
|
+
if (this.get(snapId)?.status !== snaps_utils_1.SnapStatus.Stopped) {
|
|
1415
|
+
this.update((state) => {
|
|
1416
|
+
state.snaps[snapId].status = snaps_utils_1.SnapStatus.Stopped;
|
|
1417
|
+
});
|
|
1418
|
+
}
|
|
1330
1419
|
if (sourceCode) {
|
|
1331
1420
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1332
1421
|
runtime.sourceCode = sourceCode;
|
|
@@ -1338,7 +1427,7 @@ async function _SnapController_rollbackSnap(snapId) {
|
|
|
1338
1427
|
requestData: permissions.requestData,
|
|
1339
1428
|
});
|
|
1340
1429
|
}
|
|
1341
|
-
if (
|
|
1430
|
+
if (permissions.granted?.length) {
|
|
1342
1431
|
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
1343
1432
|
[snapId]: permissions.granted,
|
|
1344
1433
|
});
|
|
@@ -1364,7 +1453,6 @@ async function _SnapController_rollbackSnaps(snapIds) {
|
|
|
1364
1453
|
(0, utils_1.assert)(runtime !== undefined, new Error(`Snap "${snapId}" runtime data not found`));
|
|
1365
1454
|
return runtime;
|
|
1366
1455
|
}, _SnapController_setupRuntime = function _SnapController_setupRuntime(snapId, data) {
|
|
1367
|
-
var _a;
|
|
1368
1456
|
if (this.snapsRuntimeData.has(snapId)) {
|
|
1369
1457
|
return;
|
|
1370
1458
|
}
|
|
@@ -1372,13 +1460,22 @@ async function _SnapController_rollbackSnaps(snapIds) {
|
|
|
1372
1460
|
const interpreter = (0, fsm_1.interpret)(__classPrivateFieldGet(this, _SnapController_statusMachine, "f"));
|
|
1373
1461
|
interpreter.start({
|
|
1374
1462
|
context: { snapId },
|
|
1375
|
-
value:
|
|
1463
|
+
value: snap?.status ??
|
|
1464
|
+
__classPrivateFieldGet(this, _SnapController_statusMachine, "f").config.initial,
|
|
1376
1465
|
});
|
|
1377
1466
|
(0, fsm_2.forceStrict)(interpreter);
|
|
1378
|
-
this.snapsRuntimeData.set(snapId,
|
|
1467
|
+
this.snapsRuntimeData.set(snapId, {
|
|
1468
|
+
lastRequest: null,
|
|
1469
|
+
rpcHandler: null,
|
|
1470
|
+
installPromise: null,
|
|
1471
|
+
activeReferences: 0,
|
|
1472
|
+
pendingInboundRequests: [],
|
|
1473
|
+
pendingOutboundRequests: 0,
|
|
1474
|
+
interpreter,
|
|
1475
|
+
...data,
|
|
1476
|
+
});
|
|
1379
1477
|
}, _SnapController_calculatePermissionsChange = function _SnapController_calculatePermissionsChange(snapId, desiredPermissionsSet) {
|
|
1380
|
-
|
|
1381
|
-
const oldPermissions = (_a = this.messagingSystem.call('PermissionController:getPermissions', snapId)) !== null && _a !== void 0 ? _a : {};
|
|
1478
|
+
const oldPermissions = this.messagingSystem.call('PermissionController:getPermissions', snapId) ?? {};
|
|
1382
1479
|
const newPermissions = (0, utils_2.setDiff)(desiredPermissionsSet, oldPermissions);
|
|
1383
1480
|
// TODO(ritave): The assumption that these are unused only holds so long as we do not
|
|
1384
1481
|
// permit dynamic permission requests.
|