@metamask/snaps-controllers 0.24.0 → 0.25.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.d.ts +3 -2
- package/dist/cronjob/CronjobController.js +37 -23
- package/dist/cronjob/CronjobController.js.map +1 -1
- package/dist/fsm.js +1 -1
- package/dist/fsm.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/multichain/MultiChainController.d.ts +3 -1
- package/dist/multichain/MultiChainController.js +8 -8
- package/dist/multichain/MultiChainController.js.map +1 -1
- package/dist/multichain/middleware.d.ts +1 -1
- package/dist/multichain/middleware.js +2 -2
- package/dist/multichain/middleware.js.map +1 -1
- package/dist/services/AbstractExecutionService.d.ts +3 -3
- package/dist/services/AbstractExecutionService.js +13 -12
- package/dist/services/AbstractExecutionService.js.map +1 -1
- package/dist/services/ExecutionService.d.ts +1 -1
- package/dist/services/ExecutionService.js.map +1 -1
- package/dist/services/iframe/IframeExecutionService.js +1 -1
- package/dist/services/iframe/IframeExecutionService.js.map +1 -1
- package/dist/services/iframe/test/server.js +6 -6
- package/dist/services/iframe/test/server.js.map +1 -1
- package/dist/services/node/NodeProcessExecutionService.d.ts +1 -1
- package/dist/services/node/NodeProcessExecutionService.js +2 -2
- package/dist/services/node/NodeProcessExecutionService.js.map +1 -1
- package/dist/services/node/NodeThreadExecutionService.d.ts +2 -2
- package/dist/services/node/NodeThreadExecutionService.js +5 -4
- package/dist/services/node/NodeThreadExecutionService.js.map +1 -1
- package/dist/snaps/SnapController.d.ts +18 -16
- package/dist/snaps/SnapController.js +104 -87
- package/dist/snaps/SnapController.js.map +1 -1
- package/dist/snaps/endowments/cronjob.d.ts +2 -2
- package/dist/snaps/endowments/cronjob.js +3 -3
- package/dist/snaps/endowments/cronjob.js.map +1 -1
- package/dist/snaps/endowments/enum.d.ts +2 -1
- package/dist/snaps/endowments/enum.js +1 -0
- package/dist/snaps/endowments/enum.js.map +1 -1
- package/dist/snaps/endowments/ethereum-provider.d.ts +1 -1
- package/dist/snaps/endowments/ethereum-provider.js +2 -2
- package/dist/snaps/endowments/ethereum-provider.js.map +1 -1
- package/dist/snaps/endowments/index.d.ts +33 -19
- package/dist/snaps/endowments/index.js +16 -4
- package/dist/snaps/endowments/index.js.map +1 -1
- package/dist/snaps/endowments/keyring.d.ts +1 -1
- package/dist/snaps/endowments/keyring.js +2 -2
- package/dist/snaps/endowments/keyring.js.map +1 -1
- package/dist/snaps/endowments/long-running.d.ts +1 -1
- package/dist/snaps/endowments/long-running.js +2 -2
- package/dist/snaps/endowments/long-running.js.map +1 -1
- package/dist/snaps/endowments/network-access.d.ts +1 -1
- package/dist/snaps/endowments/network-access.js +2 -2
- package/dist/snaps/endowments/network-access.js.map +1 -1
- package/dist/snaps/endowments/rpc.d.ts +35 -0
- package/dist/snaps/endowments/rpc.js +91 -0
- package/dist/snaps/endowments/rpc.js.map +1 -0
- package/dist/snaps/endowments/transaction-insight.d.ts +3 -3
- package/dist/snaps/endowments/transaction-insight.js +3 -3
- package/dist/snaps/endowments/transaction-insight.js.map +1 -1
- package/dist/snaps/utils/npm.d.ts +2 -2
- package/dist/snaps/utils/npm.js +7 -3
- package/dist/snaps/utils/npm.js.map +1 -1
- package/dist/snaps/utils/stream.d.ts +1 -1
- package/dist/snaps/utils/stream.js +3 -3
- package/dist/snaps/utils/stream.js.map +1 -1
- package/dist/utils.d.ts +3 -3
- package/dist/utils.js.map +1 -1
- package/package.json +25 -20
|
@@ -21,26 +21,25 @@ var __rest = (this && this.__rest) || function (s, e) {
|
|
|
21
21
|
}
|
|
22
22
|
return t;
|
|
23
23
|
};
|
|
24
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
25
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
26
|
-
};
|
|
27
24
|
var _SnapController_instances, _SnapController_closeAllConnections, _SnapController_environmentEndowmentPermissions, _SnapController_featureFlags, _SnapController_fetchFunction, _SnapController_idleTimeCheckInterval, _SnapController_checkSnapBlockList, _SnapController_maxIdleTime, _SnapController_npmRegistryUrl, _SnapController_getAppKey, _SnapController_timeoutForLastRequestStatus, _SnapController_statusMachine, _SnapController_initializeStateMachine, _SnapController_registerMessageHandlers, _SnapController_pollForLastRequestStatus, _SnapController_blockSnap, _SnapController_unblockSnap, _SnapController_assertIsUnblocked, _SnapController_stopSnapsLastRequestPastMax, _SnapController_transition, _SnapController_terminateSnap, _SnapController_getEncryptionKey, _SnapController_encryptSnapState, _SnapController_decryptSnapState, _SnapController_add, _SnapController_startSnap, _SnapController_getEndowments, _SnapController_set, _SnapController_fetchNpmSnap, _SnapController_fetchLocalSnap, _SnapController_processSnapPermissions, _SnapController_getRpcRequestHandler, _SnapController_executeWithTimeout, _SnapController_recordSnapRpcRequestStart, _SnapController_recordSnapRpcRequestFinish, _SnapController_getRuntime, _SnapController_getRuntimeExpect, _SnapController_setupRuntime, _SnapController_calculatePermissionsChange;
|
|
28
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
26
|
exports.SnapController = exports.AppKeyType = exports.SNAP_APPROVAL_UPDATE = exports.SNAP_APPROVAL_INSTALL = exports.controllerName = void 0;
|
|
30
|
-
const
|
|
31
|
-
const
|
|
27
|
+
const base_controller_1 = require("@metamask/base-controller");
|
|
28
|
+
const browser_passworder_1 = require("@metamask/browser-passworder");
|
|
29
|
+
const rpc_methods_1 = require("@metamask/rpc-methods");
|
|
32
30
|
const snaps_utils_1 = require("@metamask/snaps-utils");
|
|
31
|
+
const subject_metadata_controller_1 = require("@metamask/subject-metadata-controller");
|
|
33
32
|
const utils_1 = require("@metamask/utils");
|
|
34
33
|
const fsm_1 = require("@xstate/fsm");
|
|
35
34
|
const eth_rpc_errors_1 = require("eth-rpc-errors");
|
|
36
35
|
const nanoid_1 = require("nanoid");
|
|
37
|
-
const rpc_methods_1 = require("@metamask/rpc-methods");
|
|
38
36
|
const fsm_2 = require("../fsm");
|
|
39
37
|
const utils_2 = require("../utils");
|
|
40
38
|
const endowments_1 = require("./endowments");
|
|
39
|
+
const rpc_1 = require("./endowments/rpc");
|
|
41
40
|
const RequestQueue_1 = require("./RequestQueue");
|
|
42
|
-
const utils_3 = require("./utils");
|
|
43
41
|
const Timer_1 = require("./Timer");
|
|
42
|
+
const utils_3 = require("./utils");
|
|
44
43
|
exports.controllerName = 'SnapController';
|
|
45
44
|
// TODO: Figure out how to name these
|
|
46
45
|
exports.SNAP_APPROVAL_INSTALL = 'wallet_installSnap';
|
|
@@ -55,7 +54,7 @@ const TRUNCATED_SNAP_PROPERTIES = new Set([
|
|
|
55
54
|
]);
|
|
56
55
|
var AppKeyType;
|
|
57
56
|
(function (AppKeyType) {
|
|
58
|
-
AppKeyType["
|
|
57
|
+
AppKeyType["StateEncryption"] = "stateEncryption";
|
|
59
58
|
})(AppKeyType = exports.AppKeyType || (exports.AppKeyType = {}));
|
|
60
59
|
const defaultState = {
|
|
61
60
|
snapErrors: {},
|
|
@@ -69,12 +68,14 @@ const defaultState = {
|
|
|
69
68
|
* @returns Object with serializable snap properties.
|
|
70
69
|
*/
|
|
71
70
|
function truncateSnap(snap) {
|
|
72
|
-
|
|
71
|
+
const truncatedSnap = Object.keys(snap).reduce((serialized, key) => {
|
|
73
72
|
if (TRUNCATED_SNAP_PROPERTIES.has(key)) {
|
|
74
73
|
serialized[key] = snap[key];
|
|
75
74
|
}
|
|
76
75
|
return serialized;
|
|
77
76
|
}, {});
|
|
77
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-type-assertion
|
|
78
|
+
return truncatedSnap;
|
|
78
79
|
}
|
|
79
80
|
const name = 'SnapController';
|
|
80
81
|
/*
|
|
@@ -83,7 +84,7 @@ const name = 'SnapController';
|
|
|
83
84
|
* - Authorize: Requests the snap's required permissions from the user.
|
|
84
85
|
* - Start: Initializes the snap in its SES realm with the authorized permissions.
|
|
85
86
|
*/
|
|
86
|
-
class SnapController extends
|
|
87
|
+
class SnapController extends base_controller_1.BaseControllerV2 {
|
|
87
88
|
constructor({ closeAllConnections, messenger, state, getAppKey, environmentEndowmentPermissions = [], npmRegistryUrl, idleTimeCheckInterval = (0, utils_1.inMilliseconds)(5, utils_1.Duration.Second), checkBlockList, maxIdleTime = (0, utils_1.inMilliseconds)(30, utils_1.Duration.Second), maxRequestTime = (0, utils_1.inMilliseconds)(60, utils_1.Duration.Second), fetchFunction = globalThis.fetch.bind(globalThis), featureFlags = {}, }) {
|
|
88
89
|
var _a, _b;
|
|
89
90
|
super({
|
|
@@ -153,9 +154,11 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
153
154
|
this._onOutboundResponse = this._onOutboundResponse.bind(this);
|
|
154
155
|
this.snapsRuntimeData = new Map();
|
|
155
156
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_pollForLastRequestStatus).call(this);
|
|
157
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
156
158
|
this.messagingSystem.subscribe('ExecutionService:unhandledError', this._onUnhandledSnapError);
|
|
157
159
|
this.messagingSystem.subscribe('ExecutionService:outboundRequest', this._onOutboundRequest);
|
|
158
160
|
this.messagingSystem.subscribe('ExecutionService:outboundResponse', this._onOutboundResponse);
|
|
161
|
+
/* eslint-enable @typescript-eslint/unbound-method */
|
|
159
162
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_initializeStateMachine).call(this);
|
|
160
163
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_registerMessageHandlers).call(this);
|
|
161
164
|
Object.values((_b = state === null || state === void 0 ? void 0 : state.snaps) !== null && _b !== void 0 ? _b : {}).forEach((snap) => {
|
|
@@ -179,7 +182,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
179
182
|
};
|
|
180
183
|
return blockListArg;
|
|
181
184
|
}, {}));
|
|
182
|
-
await Promise.all(Object.entries(blockedSnaps).map((_a) => {
|
|
185
|
+
await Promise.all(Object.entries(blockedSnaps).map(async (_a) => {
|
|
183
186
|
var [snapId, _b] = _a, { blocked } = _b, blockData = __rest(_b, ["blocked"]);
|
|
184
187
|
if (blocked) {
|
|
185
188
|
return __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_blockSnap).call(this, snapId, blockData);
|
|
@@ -200,11 +203,15 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
200
203
|
});
|
|
201
204
|
return result[snapId].blocked;
|
|
202
205
|
}
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
+
_onUnhandledSnapError(snapId, error) {
|
|
207
|
+
this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Crash)
|
|
208
|
+
.then(() => this.addSnapError(error))
|
|
209
|
+
.catch((stopSnapError) => {
|
|
210
|
+
// TODO: Decide how to handle errors.
|
|
211
|
+
console.error(stopSnapError);
|
|
212
|
+
});
|
|
206
213
|
}
|
|
207
|
-
|
|
214
|
+
_onOutboundRequest(snapId) {
|
|
208
215
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
209
216
|
// Ideally we would only pause the pending request that is making the outbound request
|
|
210
217
|
// but right now we don't have a way to know which request initiated the outbound request
|
|
@@ -213,7 +220,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
213
220
|
.forEach((pendingRequest) => pendingRequest.timer.pause());
|
|
214
221
|
runtime.pendingOutboundRequests += 1;
|
|
215
222
|
}
|
|
216
|
-
|
|
223
|
+
_onOutboundResponse(snapId) {
|
|
217
224
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
218
225
|
runtime.pendingOutboundRequests -= 1;
|
|
219
226
|
if (runtime.pendingOutboundRequests === 0) {
|
|
@@ -260,7 +267,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
260
267
|
* @param snapId - The id of the Snap to disable.
|
|
261
268
|
* @returns A promise that resolves once the snap has been disabled.
|
|
262
269
|
*/
|
|
263
|
-
disableSnap(snapId) {
|
|
270
|
+
async disableSnap(snapId) {
|
|
264
271
|
if (!this.has(snapId)) {
|
|
265
272
|
throw new Error(`Snap "${snapId}" not found.`);
|
|
266
273
|
}
|
|
@@ -386,7 +393,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
386
393
|
*
|
|
387
394
|
* @param snapId - The id of the Snap whose state should be cleared.
|
|
388
395
|
*/
|
|
389
|
-
|
|
396
|
+
clearSnapState(snapId) {
|
|
390
397
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
391
398
|
runtime.state = null;
|
|
392
399
|
}
|
|
@@ -402,20 +409,19 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
402
409
|
});
|
|
403
410
|
}
|
|
404
411
|
/**
|
|
405
|
-
* Removes an error by internalID from
|
|
412
|
+
* Removes an error by internalID from the SnapControllers state.
|
|
406
413
|
*
|
|
407
414
|
* @param internalID - The internal error ID to remove on the SnapController.
|
|
408
415
|
*/
|
|
409
|
-
|
|
416
|
+
removeSnapError(internalID) {
|
|
410
417
|
this.update((state) => {
|
|
411
418
|
delete state.snapErrors[internalID];
|
|
412
419
|
});
|
|
413
420
|
}
|
|
414
421
|
/**
|
|
415
422
|
* Clears all errors from the SnapControllers state.
|
|
416
|
-
*
|
|
417
423
|
*/
|
|
418
|
-
|
|
424
|
+
clearSnapErrors() {
|
|
419
425
|
this.update((state) => {
|
|
420
426
|
state.snapErrors = {};
|
|
421
427
|
});
|
|
@@ -436,13 +442,13 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
436
442
|
* Completely clear the controller's state: delete all associated data,
|
|
437
443
|
* handlers, event listeners, and permissions; tear down all snap providers.
|
|
438
444
|
*/
|
|
439
|
-
clearState() {
|
|
445
|
+
async clearState() {
|
|
440
446
|
const snapIds = Object.keys(this.state.snaps);
|
|
441
447
|
snapIds.forEach((snapId) => {
|
|
442
448
|
__classPrivateFieldGet(this, _SnapController_closeAllConnections, "f").call(this, snapId);
|
|
443
449
|
});
|
|
444
|
-
this.messagingSystem.call('ExecutionService:terminateAllSnaps');
|
|
445
|
-
snapIds.forEach(this.revokeAllSnapPermissions);
|
|
450
|
+
await this.messagingSystem.call('ExecutionService:terminateAllSnaps');
|
|
451
|
+
snapIds.forEach((snapId) => this.revokeAllSnapPermissions(snapId));
|
|
446
452
|
this.update((state) => {
|
|
447
453
|
state.snaps = {};
|
|
448
454
|
state.snapStates = {};
|
|
@@ -491,8 +497,8 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
491
497
|
*
|
|
492
498
|
* @param snapId - The snap ID.
|
|
493
499
|
*/
|
|
494
|
-
|
|
495
|
-
if (
|
|
500
|
+
revokeAllSnapPermissions(snapId) {
|
|
501
|
+
if (this.messagingSystem.call('PermissionController:hasPermissions', snapId)) {
|
|
496
502
|
this.messagingSystem.call('PermissionController:revokeAllPermissions', snapId);
|
|
497
503
|
}
|
|
498
504
|
}
|
|
@@ -529,9 +535,9 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
529
535
|
* @param origin - The origin whose permitted snaps to retrieve.
|
|
530
536
|
* @returns The serialized permitted snaps for the origin.
|
|
531
537
|
*/
|
|
532
|
-
|
|
538
|
+
getPermittedSnaps(origin) {
|
|
533
539
|
var _a;
|
|
534
|
-
return Object.values((_a =
|
|
540
|
+
return Object.values((_a = this.messagingSystem.call('PermissionController:getPermissions', origin)) !== null && _a !== void 0 ? _a : {}).reduce((permittedSnaps, perm) => {
|
|
535
541
|
if (perm.parentCapability.startsWith(snaps_utils_1.SNAP_PREFIX)) {
|
|
536
542
|
const snapId = perm.parentCapability.replace(snaps_utils_1.SNAP_PREFIX_REGEX, '');
|
|
537
543
|
const snap = this.get(snapId);
|
|
@@ -556,15 +562,15 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
556
562
|
async installSnaps(origin, requestedSnaps) {
|
|
557
563
|
const result = {};
|
|
558
564
|
await Promise.all(Object.entries(requestedSnaps).map(async ([snapId, { version: rawVersion }]) => {
|
|
559
|
-
const version = (0, snaps_utils_1.
|
|
560
|
-
|
|
561
|
-
if (!(0, snaps_utils_1.isValidSnapVersionRange)(version)) {
|
|
565
|
+
const [error, version] = (0, snaps_utils_1.resolveVersionRange)(rawVersion);
|
|
566
|
+
if (error) {
|
|
562
567
|
result[snapId] = {
|
|
563
568
|
error: eth_rpc_errors_1.ethErrors.rpc.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${version}".`),
|
|
564
569
|
};
|
|
565
570
|
return;
|
|
566
571
|
}
|
|
567
|
-
|
|
572
|
+
const permissionName = (0, snaps_utils_1.getSnapPermissionName)(snapId);
|
|
573
|
+
if (this.messagingSystem.call('PermissionController:hasPermission', origin, permissionName)) {
|
|
568
574
|
// Attempt to install and run the snap, storing any errors that
|
|
569
575
|
// occur during the process.
|
|
570
576
|
result[snapId] = Object.assign({}, (await this.processRequestedSnap(origin, snapId, version)));
|
|
@@ -591,7 +597,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
591
597
|
try {
|
|
592
598
|
(0, snaps_utils_1.validateSnapId)(snapId);
|
|
593
599
|
}
|
|
594
|
-
catch (
|
|
600
|
+
catch (error) {
|
|
595
601
|
return {
|
|
596
602
|
error: eth_rpc_errors_1.ethErrors.rpc.invalidParams(`"${snapId}" is not a valid snap id.`),
|
|
597
603
|
};
|
|
@@ -612,8 +618,8 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
612
618
|
}
|
|
613
619
|
return updateResult;
|
|
614
620
|
}
|
|
615
|
-
catch (
|
|
616
|
-
return { error: (0, eth_rpc_errors_1.serializeError)(
|
|
621
|
+
catch (error) {
|
|
622
|
+
return { error: (0, eth_rpc_errors_1.serializeError)(error) };
|
|
617
623
|
}
|
|
618
624
|
}
|
|
619
625
|
else {
|
|
@@ -641,12 +647,12 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
641
647
|
this.messagingSystem.publish(`SnapController:snapInstalled`, truncated);
|
|
642
648
|
return truncated;
|
|
643
649
|
}
|
|
644
|
-
catch (
|
|
645
|
-
console.error(`Error when adding snap.`,
|
|
650
|
+
catch (error) {
|
|
651
|
+
console.error(`Error when adding snap.`, error);
|
|
646
652
|
if (this.has(snapId)) {
|
|
647
|
-
this.removeSnap(snapId);
|
|
653
|
+
await this.removeSnap(snapId);
|
|
648
654
|
}
|
|
649
|
-
return { error: (0, eth_rpc_errors_1.serializeError)(
|
|
655
|
+
return { error: (0, eth_rpc_errors_1.serializeError)(error) };
|
|
650
656
|
}
|
|
651
657
|
}
|
|
652
658
|
/**
|
|
@@ -668,7 +674,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
668
674
|
*/
|
|
669
675
|
async updateSnap(origin, snapId, newVersionRange = snaps_utils_1.DEFAULT_REQUESTED_SNAP_VERSION) {
|
|
670
676
|
const snap = this.getExpect(snapId);
|
|
671
|
-
if (!(0, snaps_utils_1.
|
|
677
|
+
if (!(0, snaps_utils_1.isValidSemVerRange)(newVersionRange)) {
|
|
672
678
|
throw new Error(`Received invalid snap version range: "${newVersionRange}".`);
|
|
673
679
|
}
|
|
674
680
|
const newSnap = await this.fetchSnap(snapId, newVersionRange);
|
|
@@ -682,7 +688,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
682
688
|
shasum: newSnap.manifest.source.shasum,
|
|
683
689
|
});
|
|
684
690
|
const processedPermissions = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_processSnapPermissions).call(this, newSnap.manifest.initialPermissions);
|
|
685
|
-
const { newPermissions, unusedPermissions, approvedPermissions } =
|
|
691
|
+
const { newPermissions, unusedPermissions, approvedPermissions } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
686
692
|
const id = (0, nanoid_1.nanoid)();
|
|
687
693
|
const _a = (await this.messagingSystem.call('ApprovalController:addRequest', {
|
|
688
694
|
origin,
|
|
@@ -712,12 +718,12 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
712
718
|
});
|
|
713
719
|
const unusedPermissionsKeys = Object.keys(unusedPermissions);
|
|
714
720
|
if ((0, utils_1.isNonEmptyArray)(unusedPermissionsKeys)) {
|
|
715
|
-
|
|
721
|
+
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
716
722
|
[snapId]: unusedPermissionsKeys,
|
|
717
723
|
});
|
|
718
724
|
}
|
|
719
725
|
if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedNewPermissions))) {
|
|
720
|
-
|
|
726
|
+
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
721
727
|
approvedPermissions: approvedNewPermissions,
|
|
722
728
|
subject: { origin: snapId },
|
|
723
729
|
requestData,
|
|
@@ -785,7 +791,7 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
785
791
|
},
|
|
786
792
|
}, true)), { permissions: approvedPermissions } = _a, requestData = __rest(_a, ["permissions"]);
|
|
787
793
|
if ((0, utils_1.isNonEmptyArray)(Object.keys(approvedPermissions))) {
|
|
788
|
-
|
|
794
|
+
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
789
795
|
approvedPermissions,
|
|
790
796
|
subject: { origin: snapId },
|
|
791
797
|
requestData,
|
|
@@ -802,9 +808,11 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
802
808
|
if (__classPrivateFieldGet(this, _SnapController_timeoutForLastRequestStatus, "f")) {
|
|
803
809
|
clearTimeout(__classPrivateFieldGet(this, _SnapController_timeoutForLastRequestStatus, "f"));
|
|
804
810
|
}
|
|
811
|
+
/* eslint-disable @typescript-eslint/unbound-method */
|
|
805
812
|
this.messagingSystem.unsubscribe('ExecutionService:unhandledError', this._onUnhandledSnapError);
|
|
806
813
|
this.messagingSystem.unsubscribe('ExecutionService:outboundRequest', this._onOutboundRequest);
|
|
807
814
|
this.messagingSystem.unsubscribe('ExecutionService:outboundResponse', this._onOutboundResponse);
|
|
815
|
+
/* eslint-enable @typescript-eslint/unbound-method */
|
|
808
816
|
}
|
|
809
817
|
/**
|
|
810
818
|
* Passes a JSON-RPC request object to the RPC handler function of a snap.
|
|
@@ -817,6 +825,23 @@ class SnapController extends controllers_1.BaseControllerV2 {
|
|
|
817
825
|
* @returns The result of the JSON-RPC request.
|
|
818
826
|
*/
|
|
819
827
|
async handleRequest({ snapId, origin, handler: handlerType, request, }) {
|
|
828
|
+
const permissionName = endowments_1.handlerEndowments[handlerType];
|
|
829
|
+
const hasPermission = this.messagingSystem.call('PermissionController:hasPermission', snapId, permissionName);
|
|
830
|
+
if (!hasPermission) {
|
|
831
|
+
throw new Error(`Snap "${snapId}" is not permitted to use "${permissionName}".`);
|
|
832
|
+
}
|
|
833
|
+
if (permissionName === endowments_1.SnapEndowments.Rpc) {
|
|
834
|
+
const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
|
|
835
|
+
const isSnap = (subject === null || subject === void 0 ? void 0 : subject.subjectType) === subject_metadata_controller_1.SubjectType.Snap;
|
|
836
|
+
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
837
|
+
const rpcPermission = permissions === null || permissions === void 0 ? void 0 : permissions[endowments_1.SnapEndowments.Rpc];
|
|
838
|
+
(0, utils_1.assert)(rpcPermission);
|
|
839
|
+
const origins = (0, rpc_1.getRpcCaveatOrigins)(rpcPermission);
|
|
840
|
+
(0, utils_1.assert)(origins);
|
|
841
|
+
if ((isSnap && !origins.snaps) || (!isSnap && !origins.dapps)) {
|
|
842
|
+
throw new Error(`Snap "${snapId}" is not permitted to handle JSON-RPC requests from "${origin}".`);
|
|
843
|
+
}
|
|
844
|
+
}
|
|
820
845
|
const handler = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRpcRequestHandler).call(this, snapId);
|
|
821
846
|
if (!handler) {
|
|
822
847
|
throw new Error(`Snap RPC message handler not found for snap "${snapId}".`);
|
|
@@ -878,23 +903,26 @@ _SnapController_closeAllConnections = new WeakMap(), _SnapController_environment
|
|
|
878
903
|
}, _SnapController_registerMessageHandlers = function _SnapController_registerMessageHandlers() {
|
|
879
904
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:clearSnapState`, (...args) => this.clearSnapState(...args));
|
|
880
905
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:get`, (...args) => this.get(...args));
|
|
881
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:getSnapState`, (...args) => this.getSnapState(...args));
|
|
882
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:handleRequest`, (...args) => this.handleRequest(...args));
|
|
906
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:getSnapState`, async (...args) => this.getSnapState(...args));
|
|
907
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:handleRequest`, async (...args) => this.handleRequest(...args));
|
|
883
908
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:has`, (...args) => this.has(...args));
|
|
884
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:updateBlockedSnaps`, () => this.updateBlockedSnaps());
|
|
885
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:updateSnapState`, (...args) => this.updateSnapState(...args));
|
|
909
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:updateBlockedSnaps`, async () => this.updateBlockedSnaps());
|
|
910
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:updateSnapState`, async (...args) => this.updateSnapState(...args));
|
|
886
911
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:enable`, (...args) => this.enableSnap(...args));
|
|
887
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:disable`, (...args) => this.disableSnap(...args));
|
|
888
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:remove`, (...args) => this.removeSnap(...args));
|
|
912
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:disable`, async (...args) => this.disableSnap(...args));
|
|
913
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:remove`, async (...args) => this.removeSnap(...args));
|
|
889
914
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:getPermitted`, (...args) => this.getPermittedSnaps(...args));
|
|
890
|
-
this.messagingSystem.registerActionHandler(`${exports.controllerName}:install`, (...args) => this.installSnaps(...args));
|
|
915
|
+
this.messagingSystem.registerActionHandler(`${exports.controllerName}:install`, async (...args) => this.installSnaps(...args));
|
|
891
916
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:removeSnapError`, (...args) => this.removeSnapError(...args));
|
|
892
917
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:getAll`, (...args) => this.getAllSnaps(...args));
|
|
893
918
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:incrementActiveReferences`, (...args) => this.incrementActiveReferences(...args));
|
|
894
919
|
this.messagingSystem.registerActionHandler(`${exports.controllerName}:decrementActiveReferences`, (...args) => this.decrementActiveReferences(...args));
|
|
895
920
|
}, _SnapController_pollForLastRequestStatus = function _SnapController_pollForLastRequestStatus() {
|
|
896
|
-
__classPrivateFieldSet(this, _SnapController_timeoutForLastRequestStatus, setTimeout(
|
|
897
|
-
|
|
921
|
+
__classPrivateFieldSet(this, _SnapController_timeoutForLastRequestStatus, setTimeout(() => {
|
|
922
|
+
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_stopSnapsLastRequestPastMax).call(this).catch((error) => {
|
|
923
|
+
// TODO: Decide how to handle errors.
|
|
924
|
+
console.error(error);
|
|
925
|
+
});
|
|
898
926
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_pollForLastRequestStatus).call(this);
|
|
899
927
|
}, __classPrivateFieldGet(this, _SnapController_idleTimeCheckInterval, "f")), "f");
|
|
900
928
|
}, _SnapController_blockSnap =
|
|
@@ -920,15 +948,7 @@ async function _SnapController_blockSnap(snapId, blockedSnapInfo) {
|
|
|
920
948
|
console.error(`Encountered error when stopping blocked snap "${snapId}".`, error);
|
|
921
949
|
}
|
|
922
950
|
this.messagingSystem.publish(`${exports.controllerName}:snapBlocked`, snapId, blockedSnapInfo);
|
|
923
|
-
}, _SnapController_unblockSnap =
|
|
924
|
-
/**
|
|
925
|
-
* Unblocks a snap so that it can be enabled and started again. Emits
|
|
926
|
-
* {@link SnapUnblocked}. Does nothing if the snap is not installed or already
|
|
927
|
-
* unblocked.
|
|
928
|
-
*
|
|
929
|
-
* @param snapId - The id of the snap to unblock.
|
|
930
|
-
*/
|
|
931
|
-
async function _SnapController_unblockSnap(snapId) {
|
|
951
|
+
}, _SnapController_unblockSnap = function _SnapController_unblockSnap(snapId) {
|
|
932
952
|
if (!this.has(snapId) || !this.state.snaps[snapId].blocked) {
|
|
933
953
|
return;
|
|
934
954
|
}
|
|
@@ -958,7 +978,7 @@ async function _SnapController_assertIsUnblocked(snapId, snapInfo) {
|
|
|
958
978
|
runtime.lastRequest &&
|
|
959
979
|
__classPrivateFieldGet(this, _SnapController_maxIdleTime, "f") &&
|
|
960
980
|
(0, utils_1.timeSince)(runtime.lastRequest) > __classPrivateFieldGet(this, _SnapController_maxIdleTime, "f"))
|
|
961
|
-
.map(([snapId]) => this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop)));
|
|
981
|
+
.map(async ([snapId]) => this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Stop)));
|
|
962
982
|
}, _SnapController_transition = function _SnapController_transition(snapId, event) {
|
|
963
983
|
const { interpreter } = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
964
984
|
interpreter.send(event);
|
|
@@ -975,16 +995,18 @@ async function _SnapController_terminateSnap(snapId) {
|
|
|
975
995
|
await this.messagingSystem.call('ExecutionService:terminateSnap', snapId);
|
|
976
996
|
this.messagingSystem.publish('SnapController:snapTerminated', this.getTruncatedExpect(snapId));
|
|
977
997
|
}, _SnapController_getEncryptionKey = async function _SnapController_getEncryptionKey(snapId) {
|
|
978
|
-
return __classPrivateFieldGet(this, _SnapController_getAppKey, "f").call(this, snapId, AppKeyType.
|
|
998
|
+
return __classPrivateFieldGet(this, _SnapController_getAppKey, "f").call(this, snapId, AppKeyType.StateEncryption);
|
|
979
999
|
}, _SnapController_encryptSnapState = async function _SnapController_encryptSnapState(snapId, state) {
|
|
980
1000
|
const appKey = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getEncryptionKey).call(this, snapId);
|
|
981
|
-
return browser_passworder_1.
|
|
1001
|
+
return (0, browser_passworder_1.encrypt)(appKey, state);
|
|
982
1002
|
}, _SnapController_decryptSnapState = async function _SnapController_decryptSnapState(snapId, encrypted) {
|
|
983
1003
|
const appKey = await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getEncryptionKey).call(this, snapId);
|
|
984
1004
|
try {
|
|
985
|
-
|
|
1005
|
+
const value = await (0, browser_passworder_1.decrypt)(appKey, encrypted);
|
|
1006
|
+
(0, utils_1.assert)((0, utils_1.isValidJson)(value));
|
|
1007
|
+
return value;
|
|
986
1008
|
}
|
|
987
|
-
catch (
|
|
1009
|
+
catch (error) {
|
|
988
1010
|
throw new Error('Failed to decrypt snap state, the state must be corrupted.');
|
|
989
1011
|
}
|
|
990
1012
|
}, _SnapController_add =
|
|
@@ -1044,9 +1066,9 @@ async function _SnapController_add(args) {
|
|
|
1044
1066
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_transition).call(this, snapId, snaps_utils_1.SnapStatusEvents.Start);
|
|
1045
1067
|
return result;
|
|
1046
1068
|
}
|
|
1047
|
-
catch (
|
|
1069
|
+
catch (error) {
|
|
1048
1070
|
await __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_terminateSnap).call(this, snapId);
|
|
1049
|
-
throw
|
|
1071
|
+
throw error;
|
|
1050
1072
|
}
|
|
1051
1073
|
}, _SnapController_getEndowments =
|
|
1052
1074
|
/**
|
|
@@ -1063,7 +1085,7 @@ async function _SnapController_add(args) {
|
|
|
1063
1085
|
async function _SnapController_getEndowments(snapId) {
|
|
1064
1086
|
let allEndowments = [];
|
|
1065
1087
|
for (const permissionName of __classPrivateFieldGet(this, _SnapController_environmentEndowmentPermissions, "f")) {
|
|
1066
|
-
if (
|
|
1088
|
+
if (this.messagingSystem.call('PermissionController:hasPermission', snapId, permissionName)) {
|
|
1067
1089
|
const endowments = await this.messagingSystem.call('PermissionController:getEndowments', snapId, permissionName);
|
|
1068
1090
|
if (endowments) {
|
|
1069
1091
|
// We don't have any guarantees about the type of the endowments
|
|
@@ -1080,6 +1102,8 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1080
1102
|
...new Set([...snaps_utils_1.DEFAULT_ENDOWMENTS, ...allEndowments]),
|
|
1081
1103
|
];
|
|
1082
1104
|
if (dedupedEndowments.length <
|
|
1105
|
+
// This is a bug in TypeScript: https://github.com/microsoft/TypeScript/issues/48313
|
|
1106
|
+
// eslint-disable-next-line @typescript-eslint/restrict-plus-operands
|
|
1083
1107
|
snaps_utils_1.DEFAULT_ENDOWMENTS.length + allEndowments.length) {
|
|
1084
1108
|
console.error('Duplicate endowments found. Default endowments should not be requested.', allEndowments);
|
|
1085
1109
|
}
|
|
@@ -1131,7 +1155,7 @@ async function _SnapController_getEndowments(snapId) {
|
|
|
1131
1155
|
this.messagingSystem.publish(`SnapController:snapAdded`, snap, svgIcon);
|
|
1132
1156
|
return Object.assign(Object.assign({}, snap), { sourceCode });
|
|
1133
1157
|
}, _SnapController_fetchNpmSnap = async function _SnapController_fetchNpmSnap(packageName, versionRange) {
|
|
1134
|
-
if (!(0, snaps_utils_1.
|
|
1158
|
+
if (!(0, snaps_utils_1.isValidSemVerRange)(versionRange)) {
|
|
1135
1159
|
throw new Error(`Received invalid Snap version range: "${versionRange}".`);
|
|
1136
1160
|
}
|
|
1137
1161
|
const { manifest, sourceCode, svgIcon } = await (0, utils_3.fetchNpmSnap)(packageName, versionRange, __classPrivateFieldGet(this, _SnapController_npmRegistryUrl, "f"), __classPrivateFieldGet(this, _SnapController_fetchFunction, "f"));
|
|
@@ -1177,14 +1201,7 @@ async function _SnapController_fetchLocalSnap(localhostUrl) {
|
|
|
1177
1201
|
(0, utils_1.assert)(Object.keys(value).length === 0);
|
|
1178
1202
|
return [initialPermission, {}];
|
|
1179
1203
|
}));
|
|
1180
|
-
}, _SnapController_getRpcRequestHandler =
|
|
1181
|
-
/**
|
|
1182
|
-
* Gets the RPC message handler for the given snap.
|
|
1183
|
-
*
|
|
1184
|
-
* @param snapId - The id of the Snap whose message handler to get.
|
|
1185
|
-
* @returns The RPC handler for the given snap.
|
|
1186
|
-
*/
|
|
1187
|
-
async function _SnapController_getRpcRequestHandler(snapId) {
|
|
1204
|
+
}, _SnapController_getRpcRequestHandler = function _SnapController_getRpcRequestHandler(snapId) {
|
|
1188
1205
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1189
1206
|
const existingHandler = runtime.rpcHandler;
|
|
1190
1207
|
if (existingHandler) {
|
|
@@ -1201,7 +1218,7 @@ async function _SnapController_getRpcRequestHandler(snapId) {
|
|
|
1201
1218
|
if (this.state.snaps[snapId].status === snaps_utils_1.SnapStatus.Installing) {
|
|
1202
1219
|
throw new Error(`Snap "${snapId}" is currently being installed. Please try again later.`);
|
|
1203
1220
|
}
|
|
1204
|
-
if (this.isRunning(snapId)
|
|
1221
|
+
if (!this.isRunning(snapId)) {
|
|
1205
1222
|
let localStartPromise = startPromises.get(snapId);
|
|
1206
1223
|
if (!localStartPromise) {
|
|
1207
1224
|
localStartPromise = this.startSnap(snapId);
|
|
@@ -1241,9 +1258,9 @@ async function _SnapController_getRpcRequestHandler(snapId) {
|
|
|
1241
1258
|
__classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_recordSnapRpcRequestFinish).call(this, snapId, request.id);
|
|
1242
1259
|
return result;
|
|
1243
1260
|
}
|
|
1244
|
-
catch (
|
|
1261
|
+
catch (error) {
|
|
1245
1262
|
await this.stopSnap(snapId, snaps_utils_1.SnapStatusEvents.Crash);
|
|
1246
|
-
throw
|
|
1263
|
+
throw error;
|
|
1247
1264
|
}
|
|
1248
1265
|
};
|
|
1249
1266
|
runtime.rpcHandler = rpcHandler;
|
|
@@ -1260,7 +1277,7 @@ async function _SnapController_getRpcRequestHandler(snapId) {
|
|
|
1260
1277
|
* @template PromiseValue - The value of the Promise.
|
|
1261
1278
|
*/
|
|
1262
1279
|
async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
1263
|
-
const isLongRunning =
|
|
1280
|
+
const isLongRunning = this.messagingSystem.call('PermissionController:hasPermission', snapId, endowments_1.SnapEndowments.LongRunning);
|
|
1264
1281
|
// Long running snaps have timeouts disabled
|
|
1265
1282
|
if (isLongRunning) {
|
|
1266
1283
|
return promise;
|
|
@@ -1276,7 +1293,7 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1276
1293
|
runtime.lastRequest = null;
|
|
1277
1294
|
}, _SnapController_recordSnapRpcRequestFinish = function _SnapController_recordSnapRpcRequestFinish(snapId, requestId) {
|
|
1278
1295
|
const runtime = __classPrivateFieldGet(this, _SnapController_instances, "m", _SnapController_getRuntimeExpect).call(this, snapId);
|
|
1279
|
-
runtime.pendingInboundRequests = runtime.pendingInboundRequests.filter((
|
|
1296
|
+
runtime.pendingInboundRequests = runtime.pendingInboundRequests.filter((request) => request.requestId !== requestId);
|
|
1280
1297
|
if (runtime.pendingInboundRequests.length === 0) {
|
|
1281
1298
|
runtime.lastRequest = Date.now();
|
|
1282
1299
|
}
|
|
@@ -1299,9 +1316,9 @@ async function _SnapController_executeWithTimeout(snapId, promise, timer) {
|
|
|
1299
1316
|
});
|
|
1300
1317
|
(0, fsm_2.forceStrict)(interpreter);
|
|
1301
1318
|
this.snapsRuntimeData.set(snapId, Object.assign({ lastRequest: null, rpcHandler: null, installPromise: null, activeReferences: 0, pendingInboundRequests: [], pendingOutboundRequests: 0, interpreter }, data));
|
|
1302
|
-
}, _SnapController_calculatePermissionsChange =
|
|
1319
|
+
}, _SnapController_calculatePermissionsChange = function _SnapController_calculatePermissionsChange(snapId, desiredPermissionsSet) {
|
|
1303
1320
|
var _a;
|
|
1304
|
-
const oldPermissions = (_a =
|
|
1321
|
+
const oldPermissions = (_a = this.messagingSystem.call('PermissionController:getPermissions', snapId)) !== null && _a !== void 0 ? _a : {};
|
|
1305
1322
|
const newPermissions = (0, utils_2.setDiff)(desiredPermissionsSet, oldPermissions);
|
|
1306
1323
|
// TODO(ritave): The assumption that these are unused only holds so long as we do not
|
|
1307
1324
|
// permit dynamic permission requests.
|