@metamask/snaps-controllers 4.0.0 → 5.0.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/CHANGELOG.md +33 -1
- package/dist/cjs/cronjob/CronjobController.js +3 -3
- package/dist/cjs/cronjob/CronjobController.js.map +1 -1
- package/dist/cjs/index.js +1 -0
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/interface/SnapInterfaceController.js +166 -0
- package/dist/cjs/interface/SnapInterfaceController.js.map +1 -0
- package/dist/cjs/interface/index.js +20 -0
- package/dist/cjs/interface/index.js.map +1 -0
- package/dist/cjs/interface/utils.js +59 -0
- package/dist/cjs/interface/utils.js.map +1 -0
- package/dist/cjs/services/ProxyPostMessageStream.js +3 -10
- package/dist/cjs/services/ProxyPostMessageStream.js.map +1 -1
- package/dist/cjs/services/browser.js +1 -0
- package/dist/cjs/services/browser.js.map +1 -1
- package/dist/cjs/services/index.js +1 -0
- package/dist/cjs/services/index.js.map +1 -1
- package/dist/cjs/services/node/NodeProcessExecutionService.js +13 -1
- package/dist/cjs/services/node/NodeProcessExecutionService.js.map +1 -1
- package/dist/cjs/services/node/NodeThreadExecutionService.js +14 -1
- package/dist/cjs/services/node/NodeThreadExecutionService.js.map +1 -1
- package/dist/cjs/services/offscreen/OffscreenExecutionService.js +36 -99
- package/dist/cjs/services/offscreen/OffscreenExecutionService.js.map +1 -1
- package/dist/cjs/services/proxy/ProxyExecutionService.js +110 -0
- package/dist/cjs/services/proxy/ProxyExecutionService.js.map +1 -0
- package/dist/cjs/services/webview/WebViewExecutionService.js +99 -0
- package/dist/cjs/services/webview/WebViewExecutionService.js.map +1 -0
- package/dist/cjs/services/webview/WebViewMessageStream.js +127 -0
- package/dist/cjs/services/webview/WebViewMessageStream.js.map +1 -0
- package/dist/cjs/services/webview/index.js +20 -0
- package/dist/cjs/services/webview/index.js.map +1 -0
- package/dist/cjs/snaps/SnapController.js +303 -138
- package/dist/cjs/snaps/SnapController.js.map +1 -1
- package/dist/cjs/snaps/constants.js +25 -0
- package/dist/cjs/snaps/constants.js.map +1 -0
- package/dist/cjs/snaps/index.js +0 -2
- package/dist/cjs/snaps/index.js.map +1 -1
- package/dist/cjs/snaps/location/npm.js +13 -2
- package/dist/cjs/snaps/location/npm.js.map +1 -1
- package/dist/cjs/utils.js +32 -0
- package/dist/cjs/utils.js.map +1 -1
- package/dist/esm/cronjob/CronjobController.js +2 -2
- package/dist/esm/cronjob/CronjobController.js.map +1 -1
- package/dist/esm/index.js +1 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/interface/SnapInterfaceController.js +158 -0
- package/dist/esm/interface/SnapInterfaceController.js.map +1 -0
- package/dist/esm/interface/index.js +3 -0
- package/dist/esm/interface/index.js.map +1 -0
- package/dist/esm/interface/utils.js +62 -0
- package/dist/esm/interface/utils.js.map +1 -0
- package/dist/esm/services/ProxyPostMessageStream.js +3 -10
- package/dist/esm/services/ProxyPostMessageStream.js.map +1 -1
- package/dist/esm/services/browser.js +1 -0
- package/dist/esm/services/browser.js.map +1 -1
- package/dist/esm/services/index.js +1 -0
- package/dist/esm/services/index.js.map +1 -1
- package/dist/esm/services/node/NodeProcessExecutionService.js +13 -1
- package/dist/esm/services/node/NodeProcessExecutionService.js.map +1 -1
- package/dist/esm/services/node/NodeThreadExecutionService.js +14 -1
- package/dist/esm/services/node/NodeThreadExecutionService.js.map +1 -1
- package/dist/esm/services/offscreen/OffscreenExecutionService.js +36 -99
- package/dist/esm/services/offscreen/OffscreenExecutionService.js.map +1 -1
- package/dist/esm/services/proxy/ProxyExecutionService.js +100 -0
- package/dist/esm/services/proxy/ProxyExecutionService.js.map +1 -0
- package/dist/esm/services/webview/WebViewExecutionService.js +89 -0
- package/dist/esm/services/webview/WebViewExecutionService.js.map +1 -0
- package/dist/esm/services/webview/WebViewMessageStream.js +119 -0
- package/dist/esm/services/webview/WebViewMessageStream.js.map +1 -0
- package/dist/esm/services/webview/index.js +3 -0
- package/dist/esm/services/webview/index.js.map +1 -0
- package/dist/esm/snaps/SnapController.js +299 -134
- package/dist/esm/snaps/SnapController.js.map +1 -1
- package/dist/esm/snaps/constants.js +16 -0
- package/dist/esm/snaps/constants.js.map +1 -0
- package/dist/esm/snaps/index.js +0 -2
- package/dist/esm/snaps/index.js.map +1 -1
- package/dist/esm/snaps/location/npm.js +13 -2
- package/dist/esm/snaps/location/npm.js.map +1 -1
- package/dist/esm/utils.js +37 -0
- package/dist/esm/utils.js.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/interface/SnapInterfaceController.d.ts +85 -0
- package/dist/types/interface/index.d.ts +1 -0
- package/dist/types/interface/utils.d.ts +36 -0
- package/dist/types/services/ProxyPostMessageStream.d.ts +1 -2
- package/dist/types/services/browser.d.ts +1 -0
- package/dist/types/services/index.d.ts +1 -0
- package/dist/types/services/offscreen/OffscreenExecutionService.d.ts +5 -22
- package/dist/types/services/proxy/ProxyExecutionService.d.ts +39 -0
- package/dist/types/services/webview/WebViewExecutionService.d.ts +20 -0
- package/dist/types/services/webview/WebViewMessageStream.d.ts +32 -0
- package/dist/types/services/webview/index.d.ts +1 -0
- package/dist/types/snaps/SnapController.d.ts +37 -6
- package/dist/types/snaps/constants.d.ts +1 -0
- package/dist/types/snaps/index.d.ts +0 -2
- package/dist/types/utils.d.ts +119 -0
- package/package.json +14 -14
- package/dist/cjs/snaps/endowments/cronjob.js +0 -100
- package/dist/cjs/snaps/endowments/cronjob.js.map +0 -1
- package/dist/cjs/snaps/endowments/enum.js +0 -25
- package/dist/cjs/snaps/endowments/enum.js.map +0 -1
- package/dist/cjs/snaps/endowments/ethereum-provider.js +0 -43
- package/dist/cjs/snaps/endowments/ethereum-provider.js.map +0 -1
- package/dist/cjs/snaps/endowments/home-page.js +0 -37
- package/dist/cjs/snaps/endowments/home-page.js.map +0 -1
- package/dist/cjs/snaps/endowments/index.js +0 -99
- package/dist/cjs/snaps/endowments/index.js.map +0 -1
- package/dist/cjs/snaps/endowments/keyring.js +0 -100
- package/dist/cjs/snaps/endowments/keyring.js.map +0 -1
- package/dist/cjs/snaps/endowments/lifecycle-hooks.js +0 -37
- package/dist/cjs/snaps/endowments/lifecycle-hooks.js.map +0 -1
- package/dist/cjs/snaps/endowments/name-lookup.js +0 -106
- package/dist/cjs/snaps/endowments/name-lookup.js.map +0 -1
- package/dist/cjs/snaps/endowments/network-access.js +0 -44
- package/dist/cjs/snaps/endowments/network-access.js.map +0 -1
- package/dist/cjs/snaps/endowments/rpc.js +0 -99
- package/dist/cjs/snaps/endowments/rpc.js.map +0 -1
- package/dist/cjs/snaps/endowments/transaction-insight.js +0 -106
- package/dist/cjs/snaps/endowments/transaction-insight.js.map +0 -1
- package/dist/cjs/snaps/endowments/web-assembly.js +0 -42
- package/dist/cjs/snaps/endowments/web-assembly.js.map +0 -1
- package/dist/cjs/snaps/permissions.js +0 -61
- package/dist/cjs/snaps/permissions.js.map +0 -1
- package/dist/esm/snaps/endowments/cronjob.js +0 -99
- package/dist/esm/snaps/endowments/cronjob.js.map +0 -1
- package/dist/esm/snaps/endowments/enum.js +0 -15
- package/dist/esm/snaps/endowments/enum.js.map +0 -1
- package/dist/esm/snaps/endowments/ethereum-provider.js +0 -33
- package/dist/esm/snaps/endowments/ethereum-provider.js.map +0 -1
- package/dist/esm/snaps/endowments/home-page.js +0 -27
- package/dist/esm/snaps/endowments/home-page.js.map +0 -1
- package/dist/esm/snaps/endowments/index.js +0 -54
- package/dist/esm/snaps/endowments/index.js.map +0 -1
- package/dist/esm/snaps/endowments/keyring.js +0 -91
- package/dist/esm/snaps/endowments/keyring.js.map +0 -1
- package/dist/esm/snaps/endowments/lifecycle-hooks.js +0 -27
- package/dist/esm/snaps/endowments/lifecycle-hooks.js.map +0 -1
- package/dist/esm/snaps/endowments/name-lookup.js +0 -98
- package/dist/esm/snaps/endowments/name-lookup.js.map +0 -1
- package/dist/esm/snaps/endowments/network-access.js +0 -34
- package/dist/esm/snaps/endowments/network-access.js.map +0 -1
- package/dist/esm/snaps/endowments/rpc.js +0 -88
- package/dist/esm/snaps/endowments/rpc.js.map +0 -1
- package/dist/esm/snaps/endowments/transaction-insight.js +0 -99
- package/dist/esm/snaps/endowments/transaction-insight.js.map +0 -1
- package/dist/esm/snaps/endowments/web-assembly.js +0 -32
- package/dist/esm/snaps/endowments/web-assembly.js.map +0 -1
- package/dist/esm/snaps/permissions.js +0 -50
- package/dist/esm/snaps/permissions.js.map +0 -1
- package/dist/types/snaps/endowments/cronjob.d.ts +0 -51
- package/dist/types/snaps/endowments/enum.d.ts +0 -12
- package/dist/types/snaps/endowments/ethereum-provider.d.ts +0 -14
- package/dist/types/snaps/endowments/home-page.d.ts +0 -15
- package/dist/types/snaps/endowments/index.d.ts +0 -115
- package/dist/types/snaps/endowments/keyring.d.ts +0 -39
- package/dist/types/snaps/endowments/lifecycle-hooks.d.ts +0 -15
- package/dist/types/snaps/endowments/name-lookup.d.ts +0 -38
- package/dist/types/snaps/endowments/network-access.d.ts +0 -14
- package/dist/types/snaps/endowments/rpc.d.ts +0 -38
- package/dist/types/snaps/endowments/transaction-insight.d.ts +0 -39
- package/dist/types/snaps/endowments/web-assembly.d.ts +0 -14
- package/dist/types/snaps/permissions.d.ts +0 -16
|
@@ -37,11 +37,8 @@ const _nanoid = require("nanoid");
|
|
|
37
37
|
const _fsm1 = require("../fsm");
|
|
38
38
|
const _logging = require("../logging");
|
|
39
39
|
const _utils1 = require("../utils");
|
|
40
|
-
const
|
|
41
|
-
const _keyring = require("./endowments/keyring");
|
|
42
|
-
const _rpc = require("./endowments/rpc");
|
|
40
|
+
const _constants = require("./constants");
|
|
43
41
|
const _location = require("./location");
|
|
44
|
-
const _permissions = require("./permissions");
|
|
45
42
|
const _registry = require("./registry");
|
|
46
43
|
const _RequestQueue = require("./RequestQueue");
|
|
47
44
|
const _Timer = require("./Timer");
|
|
@@ -151,7 +148,7 @@ var _closeAllConnections = /*#__PURE__*/ new WeakMap(), _dynamicPermissions = /*
|
|
|
151
148
|
_initializeStateMachine = /*#__PURE__*/ new WeakSet(), /**
|
|
152
149
|
* Constructor helper for registering the controller's messaging system
|
|
153
150
|
* actions.
|
|
154
|
-
*/ _registerMessageHandlers = /*#__PURE__*/ new WeakSet(), _pollForLastRequestStatus = /*#__PURE__*/ new WeakSet(), _blockSnap = /*#__PURE__*/ new WeakSet(), /**
|
|
151
|
+
*/ _registerMessageHandlers = /*#__PURE__*/ new WeakSet(), _handlePreinstalledSnaps = /*#__PURE__*/ new WeakSet(), _pollForLastRequestStatus = /*#__PURE__*/ new WeakSet(), _blockSnap = /*#__PURE__*/ new WeakSet(), /**
|
|
155
152
|
* Unblocks a snap so that it can be enabled and started again. Emits
|
|
156
153
|
* {@link SnapUnblocked}. Does nothing if the snap is not installed or already
|
|
157
154
|
* unblocked.
|
|
@@ -168,7 +165,7 @@ _initializeStateMachine = /*#__PURE__*/ new WeakSet(), /**
|
|
|
168
165
|
*
|
|
169
166
|
* @param snapId - The id of the snap to transition.
|
|
170
167
|
* @param event - The event enum to use to transition.
|
|
171
|
-
*/ _transition = /*#__PURE__*/ new WeakSet(), _terminateSnap = /*#__PURE__*/ new WeakSet(), /**
|
|
168
|
+
*/ _transition = /*#__PURE__*/ new WeakSet(), _terminateSnap = /*#__PURE__*/ new WeakSet(), _handleInitialConnections = /*#__PURE__*/ new WeakSet(), _addSnapToSubject = /*#__PURE__*/ new WeakSet(), /**
|
|
172
169
|
* Removes a snap's permission (caveat) from all subjects.
|
|
173
170
|
*
|
|
174
171
|
* @param snapId - The id of the Snap.
|
|
@@ -189,12 +186,20 @@ _initializeStateMachine = /*#__PURE__*/ new WeakSet(), /**
|
|
|
189
186
|
*
|
|
190
187
|
* @param args - The add snap args.
|
|
191
188
|
* @returns The resulting snap object.
|
|
192
|
-
*/ _set = /*#__PURE__*/ new WeakSet(),
|
|
189
|
+
*/ _set = /*#__PURE__*/ new WeakSet(), _validateSnapPermissions = /*#__PURE__*/ new WeakSet(), /**
|
|
190
|
+
* Determine the execution timeout for a given handler permission.
|
|
191
|
+
*
|
|
192
|
+
* If no permission is specified or the permission itself has no execution timeout defined
|
|
193
|
+
* the constructor argument `maxRequestTime` will be used.
|
|
194
|
+
*
|
|
195
|
+
* @param permission - An optional permission constraint for the handler being called.
|
|
196
|
+
* @returns The execution timeout for the given handler.
|
|
197
|
+
*/ _getExecutionTimeout = /*#__PURE__*/ new WeakSet(), /**
|
|
193
198
|
* Gets the RPC message handler for the given snap.
|
|
194
199
|
*
|
|
195
200
|
* @param snapId - The id of the Snap whose message handler to get.
|
|
196
201
|
* @returns The RPC handler for the given snap.
|
|
197
|
-
*/ _getRpcRequestHandler = /*#__PURE__*/ new WeakSet(),
|
|
202
|
+
*/ _getRpcRequestHandler = /*#__PURE__*/ new WeakSet(), _createInterface = /*#__PURE__*/ new WeakSet(), _assertInterfaceExists = /*#__PURE__*/ new WeakSet(), _transformSnapRpcRequestResult = /*#__PURE__*/ new WeakSet(), _assertSnapRpcRequestResult = /*#__PURE__*/ new WeakSet(), _executeWithTimeout = /*#__PURE__*/ new WeakSet(), _recordSnapRpcRequestStart = /*#__PURE__*/ new WeakSet(), _recordSnapRpcRequestFinish = /*#__PURE__*/ new WeakSet(), /**
|
|
198
203
|
* Retrieves the rollback snapshot of a snap.
|
|
199
204
|
*
|
|
200
205
|
* @param snapId - The snap id.
|
|
@@ -207,6 +212,16 @@ _initializeStateMachine = /*#__PURE__*/ new WeakSet(), /**
|
|
|
207
212
|
* @throws {@link Error}. If the snap exists before creation or if creation fails.
|
|
208
213
|
* @returns A `RollbackSnapshot`.
|
|
209
214
|
*/ _createRollbackSnapshot = /*#__PURE__*/ new WeakSet(), _rollbackSnap = /*#__PURE__*/ new WeakSet(), _rollbackSnaps = /*#__PURE__*/ new WeakSet(), _getRuntime = /*#__PURE__*/ new WeakSet(), _getRuntimeExpect = /*#__PURE__*/ new WeakSet(), _setupRuntime = /*#__PURE__*/ new WeakSet(), _calculatePermissionsChange = /*#__PURE__*/ new WeakSet(), /**
|
|
215
|
+
* Updates the permissions for a snap following an install, update or rollback.
|
|
216
|
+
*
|
|
217
|
+
* Grants newly requested permissions and revokes unused/revoked permissions.
|
|
218
|
+
*
|
|
219
|
+
* @param args - An options bag.
|
|
220
|
+
* @param args.snapId - The snap ID.
|
|
221
|
+
* @param args.newPermissions - New permissions to be granted.
|
|
222
|
+
* @param args.unusedPermissions - Unused permissions to be revoked.
|
|
223
|
+
* @param args.requestData - Optional request data from an approval.
|
|
224
|
+
*/ _updatePermissions = /*#__PURE__*/ new WeakSet(), /**
|
|
210
225
|
* Checks if a snap will pass version validation checks
|
|
211
226
|
* with the new version range that is requested. The first
|
|
212
227
|
* check that is done is to check if the existing snap version
|
|
@@ -492,6 +507,10 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
492
507
|
if (!Array.isArray(snapIds)) {
|
|
493
508
|
throw new Error('Expected array of snap ids.');
|
|
494
509
|
}
|
|
510
|
+
snapIds.forEach((snapId)=>{
|
|
511
|
+
const snap = this.getExpect(snapId);
|
|
512
|
+
(0, _utils.assert)(snap.removable !== false, `${snapId} is not removable.`);
|
|
513
|
+
});
|
|
495
514
|
await Promise.all(snapIds.map(async (snapId)=>{
|
|
496
515
|
const snap = this.getExpect(snapId);
|
|
497
516
|
const truncated = this.getTruncatedExpect(snapId);
|
|
@@ -685,6 +704,7 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
685
704
|
snapId,
|
|
686
705
|
type: SNAP_APPROVAL_INSTALL
|
|
687
706
|
});
|
|
707
|
+
this.messagingSystem.publish('SnapController:snapInstallStarted', snapId, origin, false);
|
|
688
708
|
// Existing snaps must be stopped before overwriting
|
|
689
709
|
if (existingSnap && this.isRunning(snapId)) {
|
|
690
710
|
await this.stopSnap(snapId, _snapsutils.SnapStatusEvents.Stop);
|
|
@@ -718,11 +738,13 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
718
738
|
return truncated;
|
|
719
739
|
} catch (error) {
|
|
720
740
|
(0, _snapsutils.logError)(`Error when adding ${snapId}.`, error);
|
|
741
|
+
const errorString = error instanceof Error ? error.message : error.toString();
|
|
721
742
|
_class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
|
|
722
743
|
loading: false,
|
|
723
744
|
type: SNAP_APPROVAL_INSTALL,
|
|
724
|
-
error:
|
|
745
|
+
error: errorString
|
|
725
746
|
});
|
|
747
|
+
this.messagingSystem.publish('SnapController:snapInstallFailed', snapId, origin, false, errorString);
|
|
726
748
|
throw error;
|
|
727
749
|
}
|
|
728
750
|
}
|
|
@@ -754,9 +776,11 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
754
776
|
type: SNAP_APPROVAL_UPDATE
|
|
755
777
|
});
|
|
756
778
|
try {
|
|
779
|
+
this.messagingSystem.publish('SnapController:snapInstallStarted', snapId, origin, true);
|
|
757
780
|
const snap = this.getExpect(snapId);
|
|
758
|
-
const
|
|
759
|
-
const
|
|
781
|
+
const oldManifest = snap.manifest;
|
|
782
|
+
const newSnap = await (0, _utils1.fetchSnap)(snapId, location);
|
|
783
|
+
const { sourceCode: sourceCodeFile, manifest: manifestFile } = newSnap;
|
|
760
784
|
const manifest = manifestFile.result;
|
|
761
785
|
const newVersion = manifest.version;
|
|
762
786
|
if (!(0, _utils.gtVersion)(newVersion, snap.version)) {
|
|
@@ -767,9 +791,10 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
767
791
|
}
|
|
768
792
|
await _class_private_method_get(this, _assertIsInstallAllowed, assertIsInstallAllowed).call(this, snapId, {
|
|
769
793
|
version: newVersion,
|
|
770
|
-
checksum: manifest.source.shasum
|
|
794
|
+
checksum: manifest.source.shasum,
|
|
795
|
+
permissions: manifest.initialPermissions
|
|
771
796
|
});
|
|
772
|
-
const processedPermissions = (0,
|
|
797
|
+
const processedPermissions = (0, _snapsrpcmethods.processSnapPermissions)(manifest.initialPermissions);
|
|
773
798
|
_class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
|
|
774
799
|
const { newPermissions, unusedPermissions, approvedPermissions } = _class_private_method_get(this, _calculatePermissionsChange, calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
775
800
|
_class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
|
|
@@ -793,28 +818,22 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
793
818
|
_class_private_method_get(this, _set, set).call(this, {
|
|
794
819
|
origin,
|
|
795
820
|
id: snapId,
|
|
796
|
-
files: newSnap
|
|
821
|
+
files: newSnap,
|
|
797
822
|
isUpdate: true
|
|
798
823
|
});
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
}
|
|
805
|
-
if (
|
|
806
|
-
this.
|
|
807
|
-
approvedPermissions: approvedNewPermissions,
|
|
808
|
-
subject: {
|
|
809
|
-
origin: snapId
|
|
810
|
-
},
|
|
811
|
-
requestData
|
|
812
|
-
});
|
|
824
|
+
_class_private_method_get(this, _updatePermissions, updatePermissions).call(this, {
|
|
825
|
+
snapId,
|
|
826
|
+
unusedPermissions,
|
|
827
|
+
newPermissions: approvedNewPermissions,
|
|
828
|
+
requestData
|
|
829
|
+
});
|
|
830
|
+
if (manifest.initialConnections) {
|
|
831
|
+
_class_private_method_get(this, _handleInitialConnections, handleInitialConnections).call(this, snapId, oldManifest.initialConnections ?? null, manifest.initialConnections);
|
|
813
832
|
}
|
|
814
833
|
const rollbackSnapshot = _class_private_method_get(this, _getRollbackSnapshot, getRollbackSnapshot).call(this, snapId);
|
|
815
834
|
if (rollbackSnapshot !== undefined) {
|
|
816
835
|
rollbackSnapshot.permissions.revoked = unusedPermissions;
|
|
817
|
-
rollbackSnapshot.permissions.granted =
|
|
836
|
+
rollbackSnapshot.permissions.granted = approvedNewPermissions;
|
|
818
837
|
rollbackSnapshot.permissions.requestData = requestData;
|
|
819
838
|
}
|
|
820
839
|
const sourceCode = sourceCodeFile.toString();
|
|
@@ -838,11 +857,13 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
838
857
|
return truncatedSnap;
|
|
839
858
|
} catch (error) {
|
|
840
859
|
(0, _snapsutils.logError)(`Error when updating ${snapId},`, error);
|
|
860
|
+
const errorString = error instanceof Error ? error.message : error.toString();
|
|
841
861
|
_class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
|
|
842
862
|
loading: false,
|
|
843
|
-
error:
|
|
863
|
+
error: errorString,
|
|
844
864
|
type: SNAP_APPROVAL_UPDATE
|
|
845
865
|
});
|
|
866
|
+
this.messagingSystem.publish('SnapController:snapInstallFailed', snapId, origin, true, errorString);
|
|
846
867
|
throw error;
|
|
847
868
|
}
|
|
848
869
|
}
|
|
@@ -870,21 +891,20 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
870
891
|
const snap = snapsState[snapId];
|
|
871
892
|
const { initialPermissions } = snap;
|
|
872
893
|
try {
|
|
873
|
-
const processedPermissions = (0,
|
|
894
|
+
const processedPermissions = (0, _snapsrpcmethods.processSnapPermissions)(initialPermissions);
|
|
874
895
|
_class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
|
|
875
896
|
_class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
|
|
876
897
|
loading: false,
|
|
877
898
|
permissions: processedPermissions
|
|
878
899
|
});
|
|
879
900
|
const { permissions: approvedPermissions, ...requestData } = await pendingApproval.promise;
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
});
|
|
901
|
+
_class_private_method_get(this, _updatePermissions, updatePermissions).call(this, {
|
|
902
|
+
snapId,
|
|
903
|
+
newPermissions: approvedPermissions,
|
|
904
|
+
requestData
|
|
905
|
+
});
|
|
906
|
+
if (snap.manifest.initialConnections) {
|
|
907
|
+
_class_private_method_get(this, _handleInitialConnections, handleInitialConnections).call(this, snapId, null, snap.manifest.initialConnections);
|
|
888
908
|
}
|
|
889
909
|
} finally{
|
|
890
910
|
const runtime = _class_private_method_get(this, _getRuntimeExpect, getRuntimeExpect).call(this, snapId);
|
|
@@ -918,35 +938,38 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
918
938
|
...rawRequest
|
|
919
939
|
};
|
|
920
940
|
(0, _utils.assertIsJsonRpcRequest)(request);
|
|
921
|
-
const permissionName =
|
|
922
|
-
|
|
923
|
-
|
|
941
|
+
const permissionName = _snapsrpcmethods.handlerEndowments[handlerType];
|
|
942
|
+
(0, _utils.assert)(typeof permissionName === 'string' || permissionName === null, "'permissionName' must be either a string or null.");
|
|
943
|
+
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
944
|
+
// If permissionName is null, the handler does not require a permission.
|
|
945
|
+
if (permissionName !== null && (!permissions || !(0, _utils.hasProperty)(permissions, permissionName))) {
|
|
924
946
|
throw new Error(`Snap "${snapId}" is not permitted to use "${permissionName}".`);
|
|
925
947
|
}
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
929
|
-
const handlerPermissions = permissions?.[permissionName];
|
|
948
|
+
const handlerPermissions = permissionName ? permissions[permissionName] : undefined;
|
|
949
|
+
if (permissionName === _snapsrpcmethods.SnapEndowments.Rpc || permissionName === _snapsrpcmethods.SnapEndowments.Keyring) {
|
|
930
950
|
(0, _utils.assert)(handlerPermissions);
|
|
931
|
-
const
|
|
951
|
+
const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
|
|
952
|
+
const origins = permissionName === _snapsrpcmethods.SnapEndowments.Rpc ? (0, _snapsrpcmethods.getRpcCaveatOrigins)(handlerPermissions) : (0, _snapsrpcmethods.getKeyringCaveatOrigins)(handlerPermissions);
|
|
932
953
|
(0, _utils.assert)(origins);
|
|
933
954
|
if (!(0, _snapsutils.isOriginAllowed)(origins, subject?.subjectType ?? _permissioncontroller.SubjectType.Website, origin)) {
|
|
934
955
|
throw new Error(`Snap "${snapId}" is not permitted to handle requests from "${origin}".`);
|
|
935
956
|
}
|
|
936
957
|
}
|
|
937
|
-
const handler =
|
|
958
|
+
const handler = _class_private_method_get(this, _getRpcRequestHandler, getRpcRequestHandler).call(this, snapId);
|
|
938
959
|
if (!handler) {
|
|
939
960
|
throw new Error(`Snap RPC message handler not found for snap "${snapId}".`);
|
|
940
961
|
}
|
|
962
|
+
const timeout = _class_private_method_get(this, _getExecutionTimeout, getExecutionTimeout).call(this, handlerPermissions);
|
|
941
963
|
return handler({
|
|
942
964
|
origin,
|
|
943
965
|
handler: handlerType,
|
|
944
|
-
request
|
|
966
|
+
request,
|
|
967
|
+
timeout
|
|
945
968
|
});
|
|
946
969
|
}
|
|
947
970
|
constructor({ closeAllConnections, messenger, state, dynamicPermissions = [
|
|
948
971
|
'eth_accounts'
|
|
949
|
-
], environmentEndowmentPermissions = [], excludedPermissions = {}, idleTimeCheckInterval = (0, _utils.inMilliseconds)(5, _utils.Duration.Second), maxIdleTime = (0, _utils.inMilliseconds)(30, _utils.Duration.Second), maxRequestTime = (0, _utils.inMilliseconds)(60, _utils.Duration.Second), fetchFunction = globalThis.fetch.bind(globalThis), featureFlags = {}, detectSnapLocation: detectSnapLocationFunction = _location.detectSnapLocation }){
|
|
972
|
+
], environmentEndowmentPermissions = [], excludedPermissions = {}, idleTimeCheckInterval = (0, _utils.inMilliseconds)(5, _utils.Duration.Second), maxIdleTime = (0, _utils.inMilliseconds)(30, _utils.Duration.Second), maxRequestTime = (0, _utils.inMilliseconds)(60, _utils.Duration.Second), fetchFunction = globalThis.fetch.bind(globalThis), featureFlags = {}, detectSnapLocation: detectSnapLocationFunction = _location.detectSnapLocation, preinstalledSnaps }){
|
|
950
973
|
super({
|
|
951
974
|
messenger,
|
|
952
975
|
metadata: {
|
|
@@ -984,6 +1007,7 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
984
1007
|
});
|
|
985
1008
|
_class_private_method_init(this, _initializeStateMachine);
|
|
986
1009
|
_class_private_method_init(this, _registerMessageHandlers);
|
|
1010
|
+
_class_private_method_init(this, _handlePreinstalledSnaps);
|
|
987
1011
|
_class_private_method_init(this, _pollForLastRequestStatus);
|
|
988
1012
|
/**
|
|
989
1013
|
* Blocks an installed snap and prevents it from being started again. Emits
|
|
@@ -1001,6 +1025,8 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
1001
1025
|
*
|
|
1002
1026
|
* @param snapId - The snap to terminate.
|
|
1003
1027
|
*/ _class_private_method_init(this, _terminateSnap);
|
|
1028
|
+
_class_private_method_init(this, _handleInitialConnections);
|
|
1029
|
+
_class_private_method_init(this, _addSnapToSubject);
|
|
1004
1030
|
_class_private_method_init(this, _removeSnapFromSubjects);
|
|
1005
1031
|
_class_private_method_init(this, _revokeAllSnapPermissions);
|
|
1006
1032
|
_class_private_method_init(this, _createApproval);
|
|
@@ -1028,20 +1054,29 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
1028
1054
|
* @returns An array of the names of the endowments.
|
|
1029
1055
|
*/ _class_private_method_init(this, _getEndowments);
|
|
1030
1056
|
_class_private_method_init(this, _set);
|
|
1031
|
-
/**
|
|
1032
|
-
* Fetches the manifest and source code of a snap.
|
|
1033
|
-
*
|
|
1034
|
-
* @param snapId - The id of the Snap.
|
|
1035
|
-
* @param location - Source from which snap will be fetched.
|
|
1036
|
-
* @returns A tuple of the Snap manifest object and the Snap source code.
|
|
1037
|
-
*/ _class_private_method_init(this, _fetchSnap);
|
|
1038
1057
|
_class_private_method_init(this, _validateSnapPermissions);
|
|
1058
|
+
_class_private_method_init(this, _getExecutionTimeout);
|
|
1039
1059
|
_class_private_method_init(this, _getRpcRequestHandler);
|
|
1040
|
-
_class_private_method_init(this, _triggerPhishingListUpdate);
|
|
1041
|
-
_class_private_method_init(this, _checkPhishingList);
|
|
1042
1060
|
/**
|
|
1043
|
-
*
|
|
1061
|
+
* Create a dynamic interface in the SnapInterfaceController.
|
|
1062
|
+
*
|
|
1063
|
+
* @param snapId - The snap ID.
|
|
1064
|
+
* @param content - The initial interface content.
|
|
1065
|
+
* @returns An identifier that can be used to identify the interface.
|
|
1066
|
+
*/ _class_private_method_init(this, _createInterface);
|
|
1067
|
+
_class_private_method_init(this, _assertInterfaceExists);
|
|
1068
|
+
/**
|
|
1069
|
+
* Transform a RPC request result if necessary.
|
|
1070
|
+
*
|
|
1071
|
+
* @param snapId - The snap ID of the snap that produced the result.
|
|
1072
|
+
* @param handlerType - The handler type that produced the result.
|
|
1073
|
+
* @param result - The result.
|
|
1074
|
+
* @returns The transformed result if applicable, otherwise the original result.
|
|
1075
|
+
*/ _class_private_method_init(this, _transformSnapRpcRequestResult);
|
|
1076
|
+
/**
|
|
1077
|
+
* Assert that the returned result of a Snap RPC call is the expected shape.
|
|
1044
1078
|
*
|
|
1079
|
+
* @param snapId - The snap ID.
|
|
1045
1080
|
* @param handlerType - The handler type of the RPC Request.
|
|
1046
1081
|
* @param result - The result of the RPC request.
|
|
1047
1082
|
*/ _class_private_method_init(this, _assertSnapRpcRequestResult);
|
|
@@ -1079,6 +1114,7 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
1079
1114
|
_class_private_method_init(this, _getRuntimeExpect);
|
|
1080
1115
|
_class_private_method_init(this, _setupRuntime);
|
|
1081
1116
|
_class_private_method_init(this, _calculatePermissionsChange);
|
|
1117
|
+
_class_private_method_init(this, _updatePermissions);
|
|
1082
1118
|
_class_private_method_init(this, _isValidUpdate);
|
|
1083
1119
|
/**
|
|
1084
1120
|
* Call a lifecycle hook on a snap, if the snap has the
|
|
@@ -1175,7 +1211,10 @@ class SnapController extends _basecontroller.BaseController {
|
|
|
1175
1211
|
});
|
|
1176
1212
|
_class_private_method_get(this, _initializeStateMachine, initializeStateMachine).call(this);
|
|
1177
1213
|
_class_private_method_get(this, _registerMessageHandlers, registerMessageHandlers).call(this);
|
|
1178
|
-
|
|
1214
|
+
if (preinstalledSnaps) {
|
|
1215
|
+
_class_private_method_get(this, _handlePreinstalledSnaps, handlePreinstalledSnaps).call(this, preinstalledSnaps);
|
|
1216
|
+
}
|
|
1217
|
+
Object.values(this.state?.snaps ?? {}).forEach((snap)=>_class_private_method_get(this, _setupRuntime, setupRuntime).call(this, snap.id));
|
|
1179
1218
|
}
|
|
1180
1219
|
}
|
|
1181
1220
|
function initializeStateMachine() {
|
|
@@ -1252,6 +1291,63 @@ function registerMessageHandlers() {
|
|
|
1252
1291
|
this.messagingSystem.registerActionHandler(`${controllerName}:revokeDynamicPermissions`, (...args)=>this.revokeDynamicSnapPermissions(...args));
|
|
1253
1292
|
this.messagingSystem.registerActionHandler(`${controllerName}:getFile`, async (...args)=>this.getSnapFile(...args));
|
|
1254
1293
|
}
|
|
1294
|
+
function handlePreinstalledSnaps(preinstalledSnaps) {
|
|
1295
|
+
for (const { snapId, manifest, files, removable } of preinstalledSnaps){
|
|
1296
|
+
const existingSnap = this.get(snapId);
|
|
1297
|
+
const isAlreadyInstalled = existingSnap !== undefined;
|
|
1298
|
+
const isUpdate = isAlreadyInstalled && (0, _utils.gtVersion)(manifest.version, existingSnap.version);
|
|
1299
|
+
// Disallow downgrades and overwriting non preinstalled snaps
|
|
1300
|
+
if (isAlreadyInstalled && (!isUpdate || existingSnap.preinstalled !== true)) {
|
|
1301
|
+
continue;
|
|
1302
|
+
}
|
|
1303
|
+
const manifestFile = new _snapsutils.VirtualFile({
|
|
1304
|
+
path: _snapsutils.NpmSnapFileNames.Manifest,
|
|
1305
|
+
value: JSON.stringify(manifest),
|
|
1306
|
+
result: manifest
|
|
1307
|
+
});
|
|
1308
|
+
const virtualFiles = files.map(({ path, value })=>new _snapsutils.VirtualFile({
|
|
1309
|
+
value,
|
|
1310
|
+
path
|
|
1311
|
+
}));
|
|
1312
|
+
const { filePath, iconPath } = manifest.source.location.npm;
|
|
1313
|
+
const sourceCode = virtualFiles.find((file)=>file.path === filePath);
|
|
1314
|
+
const svgIcon = iconPath ? virtualFiles.find((file)=>file.path === iconPath) : undefined;
|
|
1315
|
+
(0, _utils.assert)(sourceCode, 'Source code not provided for preinstalled snap.');
|
|
1316
|
+
(0, _utils.assert)(!iconPath || iconPath && svgIcon, 'Icon not provided for preinstalled snap.');
|
|
1317
|
+
(0, _utils.assert)(manifest.source.files === undefined, 'Auxiliary files are not currently supported for preinstalled snaps.');
|
|
1318
|
+
const localizationFiles = manifest.source.locales?.map((path)=>virtualFiles.find((file)=>file.path === path)) ?? [];
|
|
1319
|
+
const validatedLocalizationFiles = (0, _snapsutils.getValidatedLocalizationFiles)(localizationFiles.filter(Boolean));
|
|
1320
|
+
(0, _utils.assert)(localizationFiles.length === validatedLocalizationFiles.length, 'Missing localization files for preinstalled snap.');
|
|
1321
|
+
const filesObject = {
|
|
1322
|
+
manifest: manifestFile,
|
|
1323
|
+
sourceCode,
|
|
1324
|
+
svgIcon,
|
|
1325
|
+
auxiliaryFiles: [],
|
|
1326
|
+
localizationFiles: validatedLocalizationFiles
|
|
1327
|
+
};
|
|
1328
|
+
// Add snap to the SnapController state
|
|
1329
|
+
_class_private_method_get(this, _set, set).call(this, {
|
|
1330
|
+
id: snapId,
|
|
1331
|
+
origin: 'metamask',
|
|
1332
|
+
files: filesObject,
|
|
1333
|
+
removable,
|
|
1334
|
+
preinstalled: true
|
|
1335
|
+
});
|
|
1336
|
+
// Setup permissions
|
|
1337
|
+
const processedPermissions = (0, _snapsrpcmethods.processSnapPermissions)(manifest.initialPermissions);
|
|
1338
|
+
_class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
|
|
1339
|
+
const { newPermissions, unusedPermissions } = _class_private_method_get(this, _calculatePermissionsChange, calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
1340
|
+
_class_private_method_get(this, _updatePermissions, updatePermissions).call(this, {
|
|
1341
|
+
snapId,
|
|
1342
|
+
newPermissions,
|
|
1343
|
+
unusedPermissions
|
|
1344
|
+
});
|
|
1345
|
+
// Set status
|
|
1346
|
+
this.update((state)=>{
|
|
1347
|
+
state.snaps[snapId].status = _snapsutils.SnapStatus.Stopped;
|
|
1348
|
+
});
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1255
1351
|
function pollForLastRequestStatus() {
|
|
1256
1352
|
_class_private_field_set(this, _timeoutForLastRequestStatus, setTimeout(()=>{
|
|
1257
1353
|
_class_private_method_get(this, _stopSnapsLastRequestPastMax, stopSnapsLastRequestPastMax).call(this).catch((error)=>{
|
|
@@ -1293,7 +1389,9 @@ async function assertIsInstallAllowed(snapId, snapInfo) {
|
|
|
1293
1389
|
const result = results[snapId];
|
|
1294
1390
|
if (result.status === _registry.SnapsRegistryStatus.Blocked) {
|
|
1295
1391
|
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${result.reason?.explanation ?? ''}`);
|
|
1296
|
-
}
|
|
1392
|
+
}
|
|
1393
|
+
const isAllowlistingRequired = Object.keys(snapInfo.permissions).some((permission)=>!_constants.ALLOWED_PERMISSIONS.includes(permission));
|
|
1394
|
+
if (_class_private_field_get(this, _featureFlags).requireAllowlist && isAllowlistingRequired && result.status !== _registry.SnapsRegistryStatus.Verified) {
|
|
1297
1395
|
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The snap is not on the allowlist.`);
|
|
1298
1396
|
}
|
|
1299
1397
|
}
|
|
@@ -1314,6 +1412,52 @@ async function terminateSnap(snapId) {
|
|
|
1314
1412
|
await this.messagingSystem.call('ExecutionService:terminateSnap', snapId);
|
|
1315
1413
|
this.messagingSystem.publish('SnapController:snapTerminated', this.getTruncatedExpect(snapId));
|
|
1316
1414
|
}
|
|
1415
|
+
function handleInitialConnections(snapId, previousInitialConnections, initialConnections) {
|
|
1416
|
+
if (previousInitialConnections) {
|
|
1417
|
+
const revokedInitialConnections = (0, _utils1.setDiff)(previousInitialConnections, initialConnections);
|
|
1418
|
+
for (const origin of Object.keys(revokedInitialConnections)){
|
|
1419
|
+
this.removeSnapFromSubject(origin, snapId);
|
|
1420
|
+
}
|
|
1421
|
+
}
|
|
1422
|
+
for (const origin of Object.keys(initialConnections)){
|
|
1423
|
+
_class_private_method_get(this, _addSnapToSubject, addSnapToSubject).call(this, origin, snapId);
|
|
1424
|
+
}
|
|
1425
|
+
}
|
|
1426
|
+
function addSnapToSubject(origin, snapId) {
|
|
1427
|
+
const subjectPermissions = this.messagingSystem.call('PermissionController:getPermissions', origin);
|
|
1428
|
+
const existingCaveat = subjectPermissions?.[_snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat)=>caveat.type === _snapsutils.SnapCaveatType.SnapIds);
|
|
1429
|
+
const subjectHasSnap = Boolean((existingCaveat?.value)?.[snapId]);
|
|
1430
|
+
// If the subject is already connected to the snap, this is a no-op.
|
|
1431
|
+
if (subjectHasSnap) {
|
|
1432
|
+
return;
|
|
1433
|
+
}
|
|
1434
|
+
// If an existing caveat exists, we add the snap to that.
|
|
1435
|
+
if (existingCaveat) {
|
|
1436
|
+
this.messagingSystem.call('PermissionController:updateCaveat', origin, _snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY, _snapsutils.SnapCaveatType.SnapIds, {
|
|
1437
|
+
...existingCaveat,
|
|
1438
|
+
[snapId]: {}
|
|
1439
|
+
});
|
|
1440
|
+
return;
|
|
1441
|
+
}
|
|
1442
|
+
const approvedPermissions = {
|
|
1443
|
+
[_snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY]: {
|
|
1444
|
+
caveats: [
|
|
1445
|
+
{
|
|
1446
|
+
type: _snapsutils.SnapCaveatType.SnapIds,
|
|
1447
|
+
value: {
|
|
1448
|
+
[snapId]: {}
|
|
1449
|
+
}
|
|
1450
|
+
}
|
|
1451
|
+
]
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
1455
|
+
approvedPermissions,
|
|
1456
|
+
subject: {
|
|
1457
|
+
origin
|
|
1458
|
+
}
|
|
1459
|
+
});
|
|
1460
|
+
}
|
|
1317
1461
|
function removeSnapFromSubjects(snapId) {
|
|
1318
1462
|
const subjects = this.messagingSystem.call('PermissionController:getSubjectNames');
|
|
1319
1463
|
for (const subject of subjects){
|
|
@@ -1371,18 +1515,19 @@ async function add(args) {
|
|
|
1371
1515
|
// If fetching and setting the snap succeeds, this property will be set
|
|
1372
1516
|
// to null in the authorize() method.
|
|
1373
1517
|
runtime.installPromise = (async ()=>{
|
|
1374
|
-
const fetchedSnap = await
|
|
1375
|
-
const manifest = fetchedSnap.
|
|
1518
|
+
const fetchedSnap = await (0, _utils1.fetchSnap)(snapId, location);
|
|
1519
|
+
const manifest = fetchedSnap.manifest.result;
|
|
1376
1520
|
if (!(0, _utils.satisfiesVersionRange)(manifest.version, versionRange)) {
|
|
1377
1521
|
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${manifest.version}" which doesn't satisfy requested version range "${versionRange}".`);
|
|
1378
1522
|
}
|
|
1379
1523
|
await _class_private_method_get(this, _assertIsInstallAllowed, assertIsInstallAllowed).call(this, snapId, {
|
|
1380
1524
|
version: manifest.version,
|
|
1381
|
-
checksum: manifest.source.shasum
|
|
1525
|
+
checksum: manifest.source.shasum,
|
|
1526
|
+
permissions: manifest.initialPermissions
|
|
1382
1527
|
});
|
|
1383
1528
|
return _class_private_method_get(this, _set, set).call(this, {
|
|
1384
1529
|
...args,
|
|
1385
|
-
|
|
1530
|
+
files: fetchedSnap,
|
|
1386
1531
|
id: snapId
|
|
1387
1532
|
});
|
|
1388
1533
|
})();
|
|
@@ -1445,10 +1590,10 @@ async function getEndowments(snapId) {
|
|
|
1445
1590
|
return dedupedEndowments;
|
|
1446
1591
|
}
|
|
1447
1592
|
function set(args) {
|
|
1448
|
-
const { id: snapId, origin, files, isUpdate = false } = args;
|
|
1593
|
+
const { id: snapId, origin, files, isUpdate = false, removable, preinstalled } = args;
|
|
1449
1594
|
const { manifest, sourceCode: sourceCodeFile, svgIcon, auxiliaryFiles: rawAuxiliaryFiles, localizationFiles } = files;
|
|
1450
1595
|
(0, _snapsutils.assertIsSnapManifest)(manifest.result);
|
|
1451
|
-
const { version
|
|
1596
|
+
const { version } = manifest.result;
|
|
1452
1597
|
const sourceCode = sourceCodeFile.toString();
|
|
1453
1598
|
(0, _utils.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
|
|
1454
1599
|
const auxiliaryFiles = rawAuxiliaryFiles.map((file)=>{
|
|
@@ -1469,6 +1614,7 @@ function set(args) {
|
|
|
1469
1614
|
origin
|
|
1470
1615
|
}
|
|
1471
1616
|
];
|
|
1617
|
+
const localizedFiles = localizationFiles.map((file)=>file.result);
|
|
1472
1618
|
const snap = {
|
|
1473
1619
|
// Restore relevant snap state if it exists
|
|
1474
1620
|
...existingSnap,
|
|
@@ -1476,6 +1622,8 @@ function set(args) {
|
|
|
1476
1622
|
// previous state.
|
|
1477
1623
|
blocked: false,
|
|
1478
1624
|
enabled: true,
|
|
1625
|
+
removable,
|
|
1626
|
+
preinstalled,
|
|
1479
1627
|
id: snapId,
|
|
1480
1628
|
initialPermissions: manifest.result.initialPermissions,
|
|
1481
1629
|
manifest: manifest.result,
|
|
@@ -1484,7 +1632,7 @@ function set(args) {
|
|
|
1484
1632
|
version,
|
|
1485
1633
|
versionHistory,
|
|
1486
1634
|
auxiliaryFiles,
|
|
1487
|
-
localizationFiles:
|
|
1635
|
+
localizationFiles: localizedFiles
|
|
1488
1636
|
};
|
|
1489
1637
|
// If the snap was blocked, it isn't any longer
|
|
1490
1638
|
delete snap.blockInformation;
|
|
@@ -1500,6 +1648,9 @@ function set(args) {
|
|
|
1500
1648
|
rollbackSnapshot.statePatches = inversePatches;
|
|
1501
1649
|
}
|
|
1502
1650
|
}
|
|
1651
|
+
// In case the Snap uses a localized manifest, we need to get the
|
|
1652
|
+
// proposed name from the localized manifest.
|
|
1653
|
+
const { proposedName } = (0, _snapsutils.getLocalizedSnapManifest)(manifest.result, 'en', localizedFiles);
|
|
1503
1654
|
this.messagingSystem.call('SubjectMetadataController:addSubjectMetadata', {
|
|
1504
1655
|
subjectType: _permissioncontroller.SubjectType.Snap,
|
|
1505
1656
|
name: proposedName,
|
|
@@ -1512,40 +1663,10 @@ function set(args) {
|
|
|
1512
1663
|
sourceCode
|
|
1513
1664
|
};
|
|
1514
1665
|
}
|
|
1515
|
-
async function fetchSnap(snapId, location) {
|
|
1516
|
-
try {
|
|
1517
|
-
const manifest = await location.manifest();
|
|
1518
|
-
const sourceCode = await location.fetch(manifest.result.source.location.npm.filePath);
|
|
1519
|
-
const { iconPath } = manifest.result.source.location.npm;
|
|
1520
|
-
const svgIcon = iconPath ? await location.fetch(iconPath) : undefined;
|
|
1521
|
-
const auxiliaryFiles = await (0, _utils1.getSnapFiles)(location, manifest.result.source.files);
|
|
1522
|
-
await Promise.all(auxiliaryFiles.map(async (file)=>{
|
|
1523
|
-
// This should still be safe
|
|
1524
|
-
// eslint-disable-next-line require-atomic-updates
|
|
1525
|
-
file.data.base64 = await (0, _snapsutils.encodeBase64)(file);
|
|
1526
|
-
}));
|
|
1527
|
-
const localizationFiles = await (0, _utils1.getSnapFiles)(location, manifest.result.source.locales);
|
|
1528
|
-
const validatedLocalizationFiles = (0, _snapsutils.getValidatedLocalizationFiles)(localizationFiles);
|
|
1529
|
-
const files = {
|
|
1530
|
-
manifest,
|
|
1531
|
-
sourceCode,
|
|
1532
|
-
svgIcon,
|
|
1533
|
-
auxiliaryFiles,
|
|
1534
|
-
localizationFiles: validatedLocalizationFiles
|
|
1535
|
-
};
|
|
1536
|
-
await (0, _snapsutils.validateFetchedSnap)(files);
|
|
1537
|
-
return {
|
|
1538
|
-
files,
|
|
1539
|
-
location
|
|
1540
|
-
};
|
|
1541
|
-
} catch (error) {
|
|
1542
|
-
throw new Error(`Failed to fetch snap "${snapId}": ${(0, _snapssdk.getErrorMessage)(error)}.`);
|
|
1543
|
-
}
|
|
1544
|
-
}
|
|
1545
1666
|
function validateSnapPermissions(processedPermissions) {
|
|
1546
1667
|
const permissionKeys = Object.keys(processedPermissions);
|
|
1547
|
-
const handlerPermissions = Array.from(new Set(Object.values(
|
|
1548
|
-
(0, _utils.assert)(permissionKeys.some((key)=>handlerPermissions.includes(key)), `A snap must request at least one of the following permissions: ${handlerPermissions.join(', ')}.`);
|
|
1668
|
+
const handlerPermissions = Array.from(new Set(Object.values(_snapsrpcmethods.handlerEndowments)));
|
|
1669
|
+
(0, _utils.assert)(permissionKeys.some((key)=>handlerPermissions.includes(key)), `A snap must request at least one of the following permissions: ${handlerPermissions.filter((handler)=>handler !== null).join(', ')}.`);
|
|
1549
1670
|
const excludedPermissionErrors = permissionKeys.reduce((errors, permission)=>{
|
|
1550
1671
|
if ((0, _utils.hasProperty)(_class_private_field_get(this, _excludedPermissions), permission)) {
|
|
1551
1672
|
errors.push(_class_private_field_get(this, _excludedPermissions)[permission]);
|
|
@@ -1554,6 +1675,9 @@ function validateSnapPermissions(processedPermissions) {
|
|
|
1554
1675
|
}, []);
|
|
1555
1676
|
(0, _utils.assert)(excludedPermissionErrors.length === 0, `One or more permissions are not allowed:\n${excludedPermissionErrors.join('\n')}`);
|
|
1556
1677
|
}
|
|
1678
|
+
function getExecutionTimeout(permission) {
|
|
1679
|
+
return (0, _snapsrpcmethods.getMaxRequestTimeCaveat)(permission) ?? this.maxRequestTime;
|
|
1680
|
+
}
|
|
1557
1681
|
function getRpcRequestHandler(snapId) {
|
|
1558
1682
|
const runtime = _class_private_method_get(this, _getRuntimeExpect, getRuntimeExpect).call(this, snapId);
|
|
1559
1683
|
const existingHandler = runtime.rpcHandler;
|
|
@@ -1564,7 +1688,7 @@ function getRpcRequestHandler(snapId) {
|
|
|
1564
1688
|
// We need to set up this promise map to map snapIds to their respective startPromises,
|
|
1565
1689
|
// because otherwise we would lose context on the correct startPromise.
|
|
1566
1690
|
const startPromises = new Map();
|
|
1567
|
-
const rpcHandler = async ({ origin, handler: handlerType, request })=>{
|
|
1691
|
+
const rpcHandler = async ({ origin, handler: handlerType, request, timeout })=>{
|
|
1568
1692
|
if (this.state.snaps[snapId].enabled === false) {
|
|
1569
1693
|
throw new Error(`Snap "${snapId}" is disabled.`);
|
|
1570
1694
|
}
|
|
@@ -1590,7 +1714,7 @@ function getRpcRequestHandler(snapId) {
|
|
|
1590
1714
|
}
|
|
1591
1715
|
}
|
|
1592
1716
|
}
|
|
1593
|
-
const timer = new _Timer.Timer(
|
|
1717
|
+
const timer = new _Timer.Timer(timeout);
|
|
1594
1718
|
_class_private_method_get(this, _recordSnapRpcRequestStart, recordSnapRpcRequestStart).call(this, snapId, request.id, timer);
|
|
1595
1719
|
const handleRpcRequestPromise = this.messagingSystem.call('ExecutionService:handleRpcRequest', snapId, {
|
|
1596
1720
|
origin,
|
|
@@ -1600,8 +1724,8 @@ function getRpcRequestHandler(snapId) {
|
|
|
1600
1724
|
// This will either get the result or reject due to the timeout.
|
|
1601
1725
|
try {
|
|
1602
1726
|
const result = await _class_private_method_get(this, _executeWithTimeout, executeWithTimeout).call(this, handleRpcRequestPromise, timer);
|
|
1603
|
-
await _class_private_method_get(this, _assertSnapRpcRequestResult, assertSnapRpcRequestResult).call(this, handlerType, result);
|
|
1604
|
-
return result;
|
|
1727
|
+
await _class_private_method_get(this, _assertSnapRpcRequestResult, assertSnapRpcRequestResult).call(this, snapId, handlerType, result);
|
|
1728
|
+
return _class_private_method_get(this, _transformSnapRpcRequestResult, transformSnapRpcRequestResult).call(this, snapId, handlerType, result);
|
|
1605
1729
|
} catch (error) {
|
|
1606
1730
|
const [jsonRpcError, handled] = (0, _snapsutils.unwrapError)(error);
|
|
1607
1731
|
if (!handled) {
|
|
@@ -1615,29 +1739,64 @@ function getRpcRequestHandler(snapId) {
|
|
|
1615
1739
|
runtime.rpcHandler = rpcHandler;
|
|
1616
1740
|
return rpcHandler;
|
|
1617
1741
|
}
|
|
1618
|
-
async function
|
|
1619
|
-
return this.messagingSystem.call('
|
|
1742
|
+
async function createInterface(snapId, content) {
|
|
1743
|
+
return this.messagingSystem.call('SnapInterfaceController:createInterface', snapId, content);
|
|
1744
|
+
}
|
|
1745
|
+
function assertInterfaceExists(snapId, id) {
|
|
1746
|
+
// This will throw if the interface isn't accessible, but we assert nevertheless.
|
|
1747
|
+
(0, _utils.assert)(this.messagingSystem.call('SnapInterfaceController:getInterface', snapId, id));
|
|
1620
1748
|
}
|
|
1621
|
-
function
|
|
1622
|
-
|
|
1749
|
+
async function transformSnapRpcRequestResult(snapId, handlerType, result) {
|
|
1750
|
+
switch(handlerType){
|
|
1751
|
+
case _snapsutils.HandlerType.OnTransaction:
|
|
1752
|
+
case _snapsutils.HandlerType.OnSignature:
|
|
1753
|
+
case _snapsutils.HandlerType.OnHomePage:
|
|
1754
|
+
{
|
|
1755
|
+
// Since this type has been asserted earlier we can cast
|
|
1756
|
+
const castResult = result;
|
|
1757
|
+
// If a handler returns static content, we turn it into a dynamic UI
|
|
1758
|
+
if (castResult && (0, _utils.hasProperty)(castResult, 'content')) {
|
|
1759
|
+
const { content, ...rest } = castResult;
|
|
1760
|
+
const id = await _class_private_method_get(this, _createInterface, createInterface).call(this, snapId, content);
|
|
1761
|
+
return {
|
|
1762
|
+
...rest,
|
|
1763
|
+
id
|
|
1764
|
+
};
|
|
1765
|
+
}
|
|
1766
|
+
return result;
|
|
1767
|
+
}
|
|
1768
|
+
default:
|
|
1769
|
+
return result;
|
|
1770
|
+
}
|
|
1623
1771
|
}
|
|
1624
|
-
async function assertSnapRpcRequestResult(handlerType, result) {
|
|
1772
|
+
async function assertSnapRpcRequestResult(snapId, handlerType, result) {
|
|
1625
1773
|
switch(handlerType){
|
|
1626
1774
|
case _snapsutils.HandlerType.OnTransaction:
|
|
1627
1775
|
{
|
|
1628
1776
|
(0, _utils.assertStruct)(result, _snapsutils.OnTransactionResponseStruct);
|
|
1629
|
-
|
|
1630
|
-
|
|
1631
|
-
|
|
1777
|
+
if (result && (0, _utils.hasProperty)(result, 'id')) {
|
|
1778
|
+
_class_private_method_get(this, _assertInterfaceExists, assertInterfaceExists).call(this, snapId, result.id);
|
|
1779
|
+
}
|
|
1780
|
+
break;
|
|
1781
|
+
}
|
|
1782
|
+
case _snapsutils.HandlerType.OnSignature:
|
|
1783
|
+
{
|
|
1784
|
+
(0, _utils.assertStruct)(result, _snapsutils.OnSignatureResponseStruct);
|
|
1785
|
+
if (result && (0, _utils.hasProperty)(result, 'id')) {
|
|
1786
|
+
_class_private_method_get(this, _assertInterfaceExists, assertInterfaceExists).call(this, snapId, result.id);
|
|
1632
1787
|
}
|
|
1633
|
-
await _class_private_method_get(this, _triggerPhishingListUpdate, triggerPhishingListUpdate).call(this);
|
|
1634
|
-
(0, _snapsutils.validateComponentLinks)(result.content, _class_private_method_get(this, _checkPhishingList, checkPhishingList).bind(this));
|
|
1635
1788
|
break;
|
|
1636
1789
|
}
|
|
1637
1790
|
case _snapsutils.HandlerType.OnHomePage:
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1791
|
+
{
|
|
1792
|
+
(0, _utils.assertStruct)(result, _snapsutils.OnHomePageResponseStruct);
|
|
1793
|
+
if (result && (0, _utils.hasProperty)(result, 'id')) {
|
|
1794
|
+
_class_private_method_get(this, _assertInterfaceExists, assertInterfaceExists).call(this, snapId, result.id);
|
|
1795
|
+
}
|
|
1796
|
+
break;
|
|
1797
|
+
}
|
|
1798
|
+
case _snapsutils.HandlerType.OnNameLookup:
|
|
1799
|
+
(0, _utils.assertStruct)(result, _snapsutils.OnNameLookupResponseStruct);
|
|
1641
1800
|
break;
|
|
1642
1801
|
default:
|
|
1643
1802
|
break;
|
|
@@ -1672,11 +1831,7 @@ function createRollbackSnapshot(snapId) {
|
|
|
1672
1831
|
(0, _utils.assert)(_class_private_field_get(this, _rollbackSnapshots).get(snapId) === undefined, new Error(`Snap "${snapId}" rollback snapshot already exists.`));
|
|
1673
1832
|
_class_private_field_get(this, _rollbackSnapshots).set(snapId, {
|
|
1674
1833
|
statePatches: [],
|
|
1675
|
-
permissions: {
|
|
1676
|
-
revoked: null,
|
|
1677
|
-
granted: [],
|
|
1678
|
-
requestData: null
|
|
1679
|
-
},
|
|
1834
|
+
permissions: {},
|
|
1680
1835
|
newVersion: ''
|
|
1681
1836
|
});
|
|
1682
1837
|
const newRollbackSnapshot = _class_private_field_get(this, _rollbackSnapshots).get(snapId);
|
|
@@ -1704,20 +1859,12 @@ async function rollbackSnap(snapId) {
|
|
|
1704
1859
|
state.snaps[snapId].status = _snapsutils.SnapStatus.Stopped;
|
|
1705
1860
|
});
|
|
1706
1861
|
}
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
requestData: permissions.requestData
|
|
1714
|
-
});
|
|
1715
|
-
}
|
|
1716
|
-
if (permissions.granted?.length) {
|
|
1717
|
-
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
1718
|
-
[snapId]: permissions.granted
|
|
1719
|
-
});
|
|
1720
|
-
}
|
|
1862
|
+
_class_private_method_get(this, _updatePermissions, updatePermissions).call(this, {
|
|
1863
|
+
snapId,
|
|
1864
|
+
unusedPermissions: permissions.granted,
|
|
1865
|
+
newPermissions: permissions.revoked,
|
|
1866
|
+
requestData: permissions.requestData
|
|
1867
|
+
});
|
|
1721
1868
|
const truncatedSnap = this.getTruncatedExpect(snapId);
|
|
1722
1869
|
this.messagingSystem.publish('SnapController:snapRolledback', truncatedSnap, rollbackSnapshot.newVersion);
|
|
1723
1870
|
_class_private_field_get(this, _rollbackSnapshots).delete(snapId);
|
|
@@ -1773,6 +1920,23 @@ function calculatePermissionsChange(snapId, desiredPermissionsSet) {
|
|
|
1773
1920
|
approvedPermissions
|
|
1774
1921
|
};
|
|
1775
1922
|
}
|
|
1923
|
+
function updatePermissions({ snapId, unusedPermissions = {}, newPermissions = {}, requestData }) {
|
|
1924
|
+
const unusedPermissionsKeys = Object.keys(unusedPermissions);
|
|
1925
|
+
if ((0, _utils.isNonEmptyArray)(unusedPermissionsKeys)) {
|
|
1926
|
+
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
1927
|
+
[snapId]: unusedPermissionsKeys
|
|
1928
|
+
});
|
|
1929
|
+
}
|
|
1930
|
+
if ((0, _utils.isNonEmptyArray)(Object.keys(newPermissions))) {
|
|
1931
|
+
this.messagingSystem.call('PermissionController:grantPermissions', {
|
|
1932
|
+
approvedPermissions: newPermissions,
|
|
1933
|
+
subject: {
|
|
1934
|
+
origin: snapId
|
|
1935
|
+
},
|
|
1936
|
+
requestData
|
|
1937
|
+
});
|
|
1938
|
+
}
|
|
1939
|
+
}
|
|
1776
1940
|
function isValidUpdate(snapId, newVersionRange) {
|
|
1777
1941
|
const existingSnap = this.getExpect(snapId);
|
|
1778
1942
|
if ((0, _utils.satisfiesVersionRange)(existingSnap.version, newVersionRange)) {
|
|
@@ -1784,7 +1948,8 @@ function isValidUpdate(snapId, newVersionRange) {
|
|
|
1784
1948
|
return true;
|
|
1785
1949
|
}
|
|
1786
1950
|
async function callLifecycleHook(snapId, handler) {
|
|
1787
|
-
const permissionName =
|
|
1951
|
+
const permissionName = _snapsrpcmethods.handlerEndowments[handler];
|
|
1952
|
+
(0, _utils.assert)(permissionName, 'Lifecycle hook must have an endowment.');
|
|
1788
1953
|
const hasPermission = this.messagingSystem.call('PermissionController:hasPermission', snapId, permissionName);
|
|
1789
1954
|
if (!hasPermission) {
|
|
1790
1955
|
return;
|