@metamask/snaps-controllers 2.0.2 → 3.1.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 +30 -1
- package/dist/cjs/cronjob/CronjobController.js +1 -1
- package/dist/cjs/cronjob/CronjobController.js.map +1 -1
- package/dist/cjs/fsm.js.map +1 -1
- package/dist/cjs/services/AbstractExecutionService.js +6 -7
- package/dist/cjs/services/AbstractExecutionService.js.map +1 -1
- package/dist/cjs/snaps/SnapController.js +80 -89
- package/dist/cjs/snaps/SnapController.js.map +1 -1
- package/dist/cjs/snaps/endowments/cronjob.js +4 -4
- package/dist/cjs/snaps/endowments/cronjob.js.map +1 -1
- package/dist/cjs/snaps/endowments/enum.js +1 -0
- package/dist/cjs/snaps/endowments/enum.js.map +1 -1
- package/dist/cjs/snaps/endowments/index.js +12 -4
- package/dist/cjs/snaps/endowments/index.js.map +1 -1
- package/dist/cjs/snaps/endowments/keyring.js +100 -0
- package/dist/cjs/snaps/endowments/keyring.js.map +1 -0
- package/dist/cjs/snaps/endowments/name-lookup.js +3 -3
- package/dist/cjs/snaps/endowments/name-lookup.js.map +1 -1
- package/dist/cjs/snaps/endowments/rpc.js +4 -4
- package/dist/cjs/snaps/endowments/rpc.js.map +1 -1
- package/dist/cjs/snaps/endowments/transaction-insight.js +3 -3
- package/dist/cjs/snaps/endowments/transaction-insight.js.map +1 -1
- package/dist/cjs/snaps/location/npm.js +41 -14
- package/dist/cjs/snaps/location/npm.js.map +1 -1
- package/dist/cjs/snaps/permissions.js +5 -5
- package/dist/cjs/snaps/permissions.js.map +1 -1
- package/dist/cjs/snaps/registry/json.js +30 -1
- package/dist/cjs/snaps/registry/json.js.map +1 -1
- package/dist/cjs/snaps/registry/registry.js.map +1 -1
- package/dist/esm/cronjob/CronjobController.js +1 -1
- package/dist/esm/cronjob/CronjobController.js.map +1 -1
- package/dist/esm/fsm.js.map +1 -1
- package/dist/esm/services/AbstractExecutionService.js +6 -7
- package/dist/esm/services/AbstractExecutionService.js.map +1 -1
- package/dist/esm/snaps/SnapController.js +77 -86
- package/dist/esm/snaps/SnapController.js.map +1 -1
- package/dist/esm/snaps/endowments/cronjob.js +4 -4
- package/dist/esm/snaps/endowments/cronjob.js.map +1 -1
- package/dist/esm/snaps/endowments/enum.js +1 -0
- package/dist/esm/snaps/endowments/enum.js.map +1 -1
- package/dist/esm/snaps/endowments/index.js +10 -4
- package/dist/esm/snaps/endowments/index.js.map +1 -1
- package/dist/esm/snaps/endowments/keyring.js +91 -0
- package/dist/esm/snaps/endowments/keyring.js.map +1 -0
- package/dist/esm/snaps/endowments/name-lookup.js +3 -3
- package/dist/esm/snaps/endowments/name-lookup.js.map +1 -1
- package/dist/esm/snaps/endowments/rpc.js +4 -4
- package/dist/esm/snaps/endowments/rpc.js.map +1 -1
- package/dist/esm/snaps/endowments/transaction-insight.js +3 -3
- package/dist/esm/snaps/endowments/transaction-insight.js.map +1 -1
- package/dist/esm/snaps/location/npm.js +42 -15
- package/dist/esm/snaps/location/npm.js.map +1 -1
- package/dist/esm/snaps/permissions.js +1 -1
- package/dist/esm/snaps/permissions.js.map +1 -1
- package/dist/esm/snaps/registry/json.js +31 -2
- package/dist/esm/snaps/registry/json.js.map +1 -1
- package/dist/esm/snaps/registry/registry.js.map +1 -1
- package/dist/types/cronjob/CronjobController.d.ts +1 -1
- package/dist/types/services/AbstractExecutionService.d.ts +1 -1
- package/dist/types/snaps/SnapController.d.ts +20 -32
- package/dist/types/snaps/endowments/enum.d.ts +2 -1
- package/dist/types/snaps/endowments/index.d.ts +13 -0
- package/dist/types/snaps/endowments/keyring.d.ts +39 -0
- package/dist/types/snaps/location/npm.d.ts +1 -1
- package/dist/types/snaps/registry/json.d.ts +5 -1
- package/dist/types/snaps/registry/registry.d.ts +11 -1
- package/package.json +32 -25
|
@@ -27,16 +27,17 @@ _export(exports, {
|
|
|
27
27
|
});
|
|
28
28
|
const _basecontroller = require("@metamask/base-controller");
|
|
29
29
|
const _permissioncontroller = require("@metamask/permission-controller");
|
|
30
|
-
const
|
|
30
|
+
const _rpcerrors = require("@metamask/rpc-errors");
|
|
31
|
+
const _snapsrpcmethods = require("@metamask/snaps-rpc-methods");
|
|
31
32
|
const _snapsutils = require("@metamask/snaps-utils");
|
|
32
33
|
const _utils = require("@metamask/utils");
|
|
33
34
|
const _fsm = require("@xstate/fsm");
|
|
34
|
-
const _ethrpcerrors = require("eth-rpc-errors");
|
|
35
35
|
const _nanoid = require("nanoid");
|
|
36
36
|
const _fsm1 = require("../fsm");
|
|
37
37
|
const _logging = require("../logging");
|
|
38
38
|
const _utils1 = require("../utils");
|
|
39
39
|
const _endowments = require("./endowments");
|
|
40
|
+
const _keyring = require("./endowments/keyring");
|
|
40
41
|
const _rpc = require("./endowments/rpc");
|
|
41
42
|
const _location = require("./location");
|
|
42
43
|
const _permissions = require("./permissions");
|
|
@@ -118,7 +119,6 @@ const TRUNCATED_SNAP_PROPERTIES = new Set([
|
|
|
118
119
|
'blocked'
|
|
119
120
|
]);
|
|
120
121
|
const defaultState = {
|
|
121
|
-
snapErrors: {},
|
|
122
122
|
snaps: {},
|
|
123
123
|
snapStates: {}
|
|
124
124
|
};
|
|
@@ -174,7 +174,7 @@ _initializeStateMachine = /*#__PURE__*/ new WeakSet(), /**
|
|
|
174
174
|
* Safely revokes all permissions granted to a Snap.
|
|
175
175
|
*
|
|
176
176
|
* @param snapId - The snap ID.
|
|
177
|
-
*/ _revokeAllSnapPermissions = /*#__PURE__*/ new WeakSet(), _createApproval = /*#__PURE__*/ new WeakSet(), _updateApproval = /*#__PURE__*/ new WeakSet(), _add = /*#__PURE__*/ new WeakSet(), _startSnap = /*#__PURE__*/ new WeakSet(), _getEndowments = /*#__PURE__*/ new WeakSet(), /**
|
|
177
|
+
*/ _revokeAllSnapPermissions = /*#__PURE__*/ new WeakSet(), _createApproval = /*#__PURE__*/ new WeakSet(), _updateApproval = /*#__PURE__*/ new WeakSet(), _resolveAllowlistVersion = /*#__PURE__*/ new WeakSet(), _add = /*#__PURE__*/ new WeakSet(), _startSnap = /*#__PURE__*/ new WeakSet(), _getEndowments = /*#__PURE__*/ new WeakSet(), /**
|
|
178
178
|
* Sets a snap in state. Called when a snap is installed or updated. Performs
|
|
179
179
|
* various validation checks on the received arguments, and will throw if
|
|
180
180
|
* validation fails.
|
|
@@ -240,8 +240,8 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
240
240
|
return _class_private_method_get(this, _unblockSnap, unblockSnap).call(this, snapId);
|
|
241
241
|
}));
|
|
242
242
|
}
|
|
243
|
-
_onUnhandledSnapError(snapId,
|
|
244
|
-
this.stopSnap(snapId, _snapsutils.SnapStatusEvents.Crash).
|
|
243
|
+
_onUnhandledSnapError(snapId, _error) {
|
|
244
|
+
this.stopSnap(snapId, _snapsutils.SnapStatusEvents.Crash).catch((stopSnapError)=>{
|
|
245
245
|
// TODO: Decide how to handle errors.
|
|
246
246
|
(0, _snapsutils.logError)(stopSnapError);
|
|
247
247
|
});
|
|
@@ -417,35 +417,6 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
417
417
|
});
|
|
418
418
|
}
|
|
419
419
|
/**
|
|
420
|
-
* Adds error from a snap to the SnapController state.
|
|
421
|
-
*
|
|
422
|
-
* @param snapError - The error to store on the SnapController.
|
|
423
|
-
*/ addSnapError(snapError) {
|
|
424
|
-
this.update((state)=>{
|
|
425
|
-
const id = (0, _nanoid.nanoid)();
|
|
426
|
-
state.snapErrors[id] = {
|
|
427
|
-
...snapError,
|
|
428
|
-
internalID: id
|
|
429
|
-
};
|
|
430
|
-
});
|
|
431
|
-
}
|
|
432
|
-
/**
|
|
433
|
-
* Removes an error by internalID from the SnapControllers state.
|
|
434
|
-
*
|
|
435
|
-
* @param internalID - The internal error ID to remove on the SnapController.
|
|
436
|
-
*/ removeSnapError(internalID) {
|
|
437
|
-
this.update((state)=>{
|
|
438
|
-
delete state.snapErrors[internalID];
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
/**
|
|
442
|
-
* Clears all errors from the SnapControllers state.
|
|
443
|
-
*/ clearSnapErrors() {
|
|
444
|
-
this.update((state)=>{
|
|
445
|
-
state.snapErrors = {};
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
/**
|
|
449
420
|
* Gets the own state of the snap with the given id.
|
|
450
421
|
* This is distinct from the state MetaMask uses to manage snaps.
|
|
451
422
|
*
|
|
@@ -457,6 +428,22 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
457
428
|
return state ?? null;
|
|
458
429
|
}
|
|
459
430
|
/**
|
|
431
|
+
* Gets a static auxiliary snap file in a chosen file encoding.
|
|
432
|
+
*
|
|
433
|
+
* @param snapId - The id of the Snap whose state to get.
|
|
434
|
+
* @param path - The path to the requested file.
|
|
435
|
+
* @param encoding - An optional requested file encoding.
|
|
436
|
+
* @returns The file requested in the chosen file encoding or null if the file is not found.
|
|
437
|
+
*/ getSnapFile(snapId, path, encoding = _snapsutils.AuxiliaryFileEncoding.Base64) {
|
|
438
|
+
const snap = this.getExpect(snapId);
|
|
439
|
+
const normalizedPath = (0, _snapsutils.normalizeRelative)(path);
|
|
440
|
+
const value = snap.auxiliaryFiles?.find((file)=>file.path === normalizedPath)?.value;
|
|
441
|
+
if (!value) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
return (0, _snapsutils.encodeAuxiliaryFile)(value, encoding);
|
|
445
|
+
}
|
|
446
|
+
/**
|
|
460
447
|
* Completely clear the controller's state: delete all associated data,
|
|
461
448
|
* handlers, event listeners, and permissions; tear down all snap providers.
|
|
462
449
|
*/ async clearState() {
|
|
@@ -519,7 +506,7 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
519
506
|
* @param snapId - The id of the snap to remove.
|
|
520
507
|
*/ removeSnapFromSubject(origin, snapId) {
|
|
521
508
|
const subjectPermissions = this.messagingSystem.call('PermissionController:getPermissions', origin);
|
|
522
|
-
const snapIdsCaveat = subjectPermissions?.[
|
|
509
|
+
const snapIdsCaveat = subjectPermissions?.[_snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat)=>caveat.type === _snapsutils.SnapCaveatType.SnapIds);
|
|
523
510
|
if (!snapIdsCaveat) {
|
|
524
511
|
return;
|
|
525
512
|
}
|
|
@@ -530,11 +517,11 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
530
517
|
};
|
|
531
518
|
delete newCaveatValue[snapId];
|
|
532
519
|
if (Object.keys(newCaveatValue).length > 0) {
|
|
533
|
-
this.messagingSystem.call('PermissionController:updateCaveat', origin,
|
|
520
|
+
this.messagingSystem.call('PermissionController:updateCaveat', origin, _snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY, _snapsutils.SnapCaveatType.SnapIds, newCaveatValue);
|
|
534
521
|
} else {
|
|
535
522
|
this.messagingSystem.call('PermissionController:revokePermissions', {
|
|
536
523
|
[origin]: [
|
|
537
|
-
|
|
524
|
+
_snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY
|
|
538
525
|
]
|
|
539
526
|
});
|
|
540
527
|
}
|
|
@@ -583,7 +570,7 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
583
570
|
* @returns The serialized permitted snaps for the origin.
|
|
584
571
|
*/ getPermittedSnaps(origin) {
|
|
585
572
|
const permissions = this.messagingSystem.call('PermissionController:getPermissions', origin) ?? {};
|
|
586
|
-
const snaps = permissions[
|
|
573
|
+
const snaps = permissions[_snapsrpcmethods.WALLET_SNAP_PERMISSION_KEY]?.caveats?.find((caveat)=>caveat.type === _snapsutils.SnapCaveatType.SnapIds)?.value ?? {};
|
|
587
574
|
return Object.keys(snaps).reduce((permittedSnaps, snapId)=>{
|
|
588
575
|
const snap = this.get(snapId);
|
|
589
576
|
const truncatedSnap = this.getTruncated(snapId);
|
|
@@ -610,10 +597,12 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
610
597
|
try {
|
|
611
598
|
for (const [snapId, { version: rawVersion }] of Object.entries(requestedSnaps)){
|
|
612
599
|
(0, _snapsutils.assertIsValidSnapId)(snapId);
|
|
613
|
-
const [error,
|
|
600
|
+
const [error, resolvedVersion] = (0, _snapsutils.resolveVersionRange)(rawVersion);
|
|
614
601
|
if (error) {
|
|
615
|
-
throw
|
|
602
|
+
throw _rpcerrors.rpcErrors.invalidParams(`The "version" field must be a valid SemVer version range if specified. Received: "${rawVersion}".`);
|
|
616
603
|
}
|
|
604
|
+
// If we are running in allowlist mode, try to match the version with an allowlist version.
|
|
605
|
+
const version = _class_private_field_get(this, _featureFlags).requireAllowlist ? await _class_private_method_get(this, _resolveAllowlistVersion, resolveAllowlistVersion).call(this, snapId, resolvedVersion) : resolvedVersion;
|
|
617
606
|
const location = _class_private_field_get(this, _detectSnapLocation).call(this, snapId, {
|
|
618
607
|
versionRange: version,
|
|
619
608
|
fetch: _class_private_field_get(this, _fetchFunction),
|
|
@@ -641,8 +630,8 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
641
630
|
result[snapId] = await this.processRequestedSnap(origin, snapId, location, version);
|
|
642
631
|
}
|
|
643
632
|
// Once we finish all installs / updates, emit events.
|
|
644
|
-
pendingInstalls.forEach((snapId)=>this.messagingSystem.publish(`SnapController:snapInstalled`, this.getTruncatedExpect(snapId)));
|
|
645
|
-
pendingUpdates.forEach(({ snapId, oldVersion })=>this.messagingSystem.publish(`SnapController:snapUpdated`, this.getTruncatedExpect(snapId), oldVersion));
|
|
633
|
+
pendingInstalls.forEach((snapId)=>this.messagingSystem.publish(`SnapController:snapInstalled`, this.getTruncatedExpect(snapId), origin));
|
|
634
|
+
pendingUpdates.forEach(({ snapId, oldVersion })=>this.messagingSystem.publish(`SnapController:snapUpdated`, this.getTruncatedExpect(snapId), oldVersion, origin));
|
|
646
635
|
snapIds.forEach((snapId)=>_class_private_field_get(this, _rollbackSnapshots).delete(snapId));
|
|
647
636
|
} catch (error) {
|
|
648
637
|
const installed = pendingInstalls.filter((snapId)=>this.has(snapId));
|
|
@@ -675,7 +664,7 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
675
664
|
return await this.updateSnap(origin, snapId, location, versionRange, // Since we are requesting an update from within processRequestedSnap,
|
|
676
665
|
// we disable the emitting of the snapUpdated event and rely on the caller
|
|
677
666
|
// to publish this event after the update is complete.
|
|
678
|
-
// This is
|
|
667
|
+
// This is necessary as installSnaps may be installing multiple snaps
|
|
679
668
|
// and we don't want to emit events prematurely.
|
|
680
669
|
false);
|
|
681
670
|
}
|
|
@@ -755,23 +744,25 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
755
744
|
try {
|
|
756
745
|
const snap = this.getExpect(snapId);
|
|
757
746
|
const newSnap = await _class_private_method_get(this, _fetchSnap, fetchSnap).call(this, snapId, location);
|
|
758
|
-
const
|
|
747
|
+
const { sourceCode: sourceCodeFile, manifest: manifestFile } = newSnap.files;
|
|
748
|
+
const manifest = manifestFile.result;
|
|
749
|
+
const newVersion = manifest.version;
|
|
759
750
|
if (!(0, _utils.gtVersion)(newVersion, snap.version)) {
|
|
760
|
-
throw
|
|
751
|
+
throw _rpcerrors.rpcErrors.invalidParams(`Snap "${snapId}@${snap.version}" is already installed. Couldn't update to a version inside requested "${newVersionRange}" range.`);
|
|
761
752
|
}
|
|
762
753
|
if (!(0, _utils.satisfiesVersionRange)(newVersion, newVersionRange)) {
|
|
763
754
|
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${newVersion}" which doesn't satisfy requested version range "${newVersionRange}".`);
|
|
764
755
|
}
|
|
765
756
|
await _class_private_method_get(this, _assertIsInstallAllowed, assertIsInstallAllowed).call(this, snapId, {
|
|
766
757
|
version: newVersion,
|
|
767
|
-
checksum:
|
|
758
|
+
checksum: manifest.source.shasum
|
|
768
759
|
});
|
|
769
|
-
const processedPermissions = (0, _permissions.processSnapPermissions)(
|
|
760
|
+
const processedPermissions = (0, _permissions.processSnapPermissions)(manifest.initialPermissions);
|
|
770
761
|
_class_private_method_get(this, _validateSnapPermissions, validateSnapPermissions).call(this, processedPermissions);
|
|
771
762
|
const { newPermissions, unusedPermissions, approvedPermissions } = _class_private_method_get(this, _calculatePermissionsChange, calculatePermissionsChange).call(this, snapId, processedPermissions);
|
|
772
763
|
_class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
|
|
773
764
|
permissions: newPermissions,
|
|
774
|
-
newVersion:
|
|
765
|
+
newVersion: manifest.version,
|
|
775
766
|
newPermissions,
|
|
776
767
|
approvedPermissions,
|
|
777
768
|
unusedPermissions,
|
|
@@ -790,7 +781,6 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
790
781
|
_class_private_method_get(this, _set, set).call(this, {
|
|
791
782
|
origin,
|
|
792
783
|
id: snapId,
|
|
793
|
-
manifest: newSnap.manifest,
|
|
794
784
|
files: newSnap.files,
|
|
795
785
|
isUpdate: true
|
|
796
786
|
});
|
|
@@ -815,8 +805,7 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
815
805
|
rollbackSnapshot.permissions.granted = Object.keys(approvedNewPermissions);
|
|
816
806
|
rollbackSnapshot.permissions.requestData = requestData;
|
|
817
807
|
}
|
|
818
|
-
const
|
|
819
|
-
const sourceCode = newSnap.files.find((file)=>file.path === normalizedSourcePath)?.toString();
|
|
808
|
+
const sourceCode = sourceCodeFile.toString();
|
|
820
809
|
(0, _utils.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
|
|
821
810
|
try {
|
|
822
811
|
await _class_private_method_get(this, _startSnap, startSnap).call(this, {
|
|
@@ -828,7 +817,7 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
828
817
|
}
|
|
829
818
|
const truncatedSnap = this.getTruncatedExpect(snapId);
|
|
830
819
|
if (emitEvent) {
|
|
831
|
-
this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version);
|
|
820
|
+
this.messagingSystem.publish('SnapController:snapUpdated', truncatedSnap, snap.version, origin);
|
|
832
821
|
}
|
|
833
822
|
_class_private_method_get(this, _updateApproval, updateApproval).call(this, pendingApproval.id, {
|
|
834
823
|
loading: false,
|
|
@@ -898,6 +887,8 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
898
887
|
/* eslint-disable @typescript-eslint/unbound-method */ this.messagingSystem.unsubscribe('ExecutionService:unhandledError', this._onUnhandledSnapError);
|
|
899
888
|
this.messagingSystem.unsubscribe('ExecutionService:outboundRequest', this._onOutboundRequest);
|
|
900
889
|
this.messagingSystem.unsubscribe('ExecutionService:outboundResponse', this._onOutboundResponse);
|
|
890
|
+
this.messagingSystem.clearEventSubscriptions('SnapController:snapInstalled');
|
|
891
|
+
this.messagingSystem.clearEventSubscriptions('SnapController:snapUpdated');
|
|
901
892
|
/* eslint-enable @typescript-eslint/unbound-method */ }
|
|
902
893
|
/**
|
|
903
894
|
* Passes a JSON-RPC request object to the RPC handler function of a snap.
|
|
@@ -920,16 +911,15 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
920
911
|
if (!hasPermission) {
|
|
921
912
|
throw new Error(`Snap "${snapId}" is not permitted to use "${permissionName}".`);
|
|
922
913
|
}
|
|
923
|
-
if (permissionName === _endowments.SnapEndowments.Rpc) {
|
|
914
|
+
if (permissionName === _endowments.SnapEndowments.Rpc || permissionName === _endowments.SnapEndowments.Keyring) {
|
|
924
915
|
const subject = this.messagingSystem.call('SubjectMetadataController:getSubjectMetadata', origin);
|
|
925
|
-
const isSnap = subject?.subjectType === _permissioncontroller.SubjectType.Snap;
|
|
926
916
|
const permissions = this.messagingSystem.call('PermissionController:getPermissions', snapId);
|
|
927
|
-
const
|
|
928
|
-
(0, _utils.assert)(
|
|
929
|
-
const origins = (0, _rpc.getRpcCaveatOrigins)(
|
|
917
|
+
const handlerPermissions = permissions?.[permissionName];
|
|
918
|
+
(0, _utils.assert)(handlerPermissions);
|
|
919
|
+
const origins = permissionName === _endowments.SnapEndowments.Rpc ? (0, _rpc.getRpcCaveatOrigins)(handlerPermissions) : (0, _keyring.getKeyringCaveatOrigins)(handlerPermissions);
|
|
930
920
|
(0, _utils.assert)(origins);
|
|
931
|
-
if (
|
|
932
|
-
throw new Error(`Snap "${snapId}" is not permitted to handle
|
|
921
|
+
if (!(0, _snapsutils.isOriginAllowed)(origins, subject?.subjectType ?? _permissioncontroller.SubjectType.Website, origin)) {
|
|
922
|
+
throw new Error(`Snap "${snapId}" is not permitted to handle requests from "${origin}".`);
|
|
933
923
|
}
|
|
934
924
|
}
|
|
935
925
|
const handler = await _class_private_method_get(this, _getRpcRequestHandler, getRpcRequestHandler).call(this, snapId);
|
|
@@ -948,17 +938,15 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
948
938
|
super({
|
|
949
939
|
messenger,
|
|
950
940
|
metadata: {
|
|
951
|
-
snapErrors: {
|
|
952
|
-
persist: false,
|
|
953
|
-
anonymous: false
|
|
954
|
-
},
|
|
955
941
|
snapStates: {
|
|
956
942
|
persist: true,
|
|
957
943
|
anonymous: false
|
|
958
944
|
},
|
|
959
945
|
snaps: {
|
|
960
946
|
persist: (snaps)=>{
|
|
961
|
-
return Object.values(snaps)
|
|
947
|
+
return Object.values(snaps)// We should not persist snaps that are in the installing state,
|
|
948
|
+
// since they haven't completed installation and would be unusable
|
|
949
|
+
.filter((snap)=>snap.status !== _snapsutils.SnapStatus.Installing).map((snap)=>{
|
|
962
950
|
return {
|
|
963
951
|
...snap,
|
|
964
952
|
// At the time state is rehydrated, no snap will be running.
|
|
@@ -1001,6 +989,7 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
1001
989
|
_class_private_method_init(this, _revokeAllSnapPermissions);
|
|
1002
990
|
_class_private_method_init(this, _createApproval);
|
|
1003
991
|
_class_private_method_init(this, _updateApproval);
|
|
992
|
+
_class_private_method_init(this, _resolveAllowlistVersion);
|
|
1004
993
|
/**
|
|
1005
994
|
* Returns a promise representing the complete installation of the requested snap.
|
|
1006
995
|
* If the snap is already being installed, the previously pending promise will be returned.
|
|
@@ -1026,8 +1015,6 @@ class SnapController extends _basecontroller.BaseControllerV2 {
|
|
|
1026
1015
|
/**
|
|
1027
1016
|
* Fetches the manifest and source code of a snap.
|
|
1028
1017
|
*
|
|
1029
|
-
* This function is not hash private yet because of tests.
|
|
1030
|
-
*
|
|
1031
1018
|
* @param snapId - The id of the Snap.
|
|
1032
1019
|
* @param location - Source from which snap will be fetched.
|
|
1033
1020
|
* @returns A tuple of the Snap manifest object and the Snap source code.
|
|
@@ -1236,13 +1223,13 @@ function registerMessageHandlers() {
|
|
|
1236
1223
|
this.messagingSystem.registerActionHandler(`${controllerName}:remove`, async (...args)=>this.removeSnap(...args));
|
|
1237
1224
|
this.messagingSystem.registerActionHandler(`${controllerName}:getPermitted`, (...args)=>this.getPermittedSnaps(...args));
|
|
1238
1225
|
this.messagingSystem.registerActionHandler(`${controllerName}:install`, async (...args)=>this.installSnaps(...args));
|
|
1239
|
-
this.messagingSystem.registerActionHandler(`${controllerName}:removeSnapError`, (...args)=>this.removeSnapError(...args));
|
|
1240
1226
|
this.messagingSystem.registerActionHandler(`${controllerName}:getAll`, (...args)=>this.getAllSnaps(...args));
|
|
1241
1227
|
this.messagingSystem.registerActionHandler(`${controllerName}:incrementActiveReferences`, (...args)=>this.incrementActiveReferences(...args));
|
|
1242
1228
|
this.messagingSystem.registerActionHandler(`${controllerName}:decrementActiveReferences`, (...args)=>this.decrementActiveReferences(...args));
|
|
1243
1229
|
this.messagingSystem.registerActionHandler(`${controllerName}:getRegistryMetadata`, async (...args)=>this.getRegistryMetadata(...args));
|
|
1244
1230
|
this.messagingSystem.registerActionHandler(`${controllerName}:disconnectOrigin`, (...args)=>this.removeSnapFromSubject(...args));
|
|
1245
1231
|
this.messagingSystem.registerActionHandler(`${controllerName}:revokeDynamicPermissions`, (...args)=>this.revokeDynamicSnapPermissions(...args));
|
|
1232
|
+
this.messagingSystem.registerActionHandler(`${controllerName}:getFile`, (...args)=>this.getSnapFile(...args));
|
|
1246
1233
|
}
|
|
1247
1234
|
function pollForLastRequestStatus() {
|
|
1248
1235
|
_class_private_field_set(this, _timeoutForLastRequestStatus, setTimeout(()=>{
|
|
@@ -1286,7 +1273,7 @@ async function assertIsInstallAllowed(snapId, snapInfo) {
|
|
|
1286
1273
|
if (result.status === _registry.SnapsRegistryStatus.Blocked) {
|
|
1287
1274
|
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The version is blocked. ${result.reason?.explanation ?? ''}`);
|
|
1288
1275
|
} else if (_class_private_field_get(this, _featureFlags).requireAllowlist && result.status !== _registry.SnapsRegistryStatus.Verified) {
|
|
1289
|
-
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The snap is not on the
|
|
1276
|
+
throw new Error(`Cannot install version "${snapInfo.version}" of snap "${snapId}": The snap is not on the allowlist.`);
|
|
1290
1277
|
}
|
|
1291
1278
|
}
|
|
1292
1279
|
async function stopSnapsLastRequestPastMax() {
|
|
@@ -1352,6 +1339,9 @@ function updateApproval(id, requestState) {
|
|
|
1352
1339
|
// Do nothing
|
|
1353
1340
|
}
|
|
1354
1341
|
}
|
|
1342
|
+
async function resolveAllowlistVersion(snapId, versionRange) {
|
|
1343
|
+
return await this.messagingSystem.call('SnapsRegistry:resolveVersion', snapId, versionRange);
|
|
1344
|
+
}
|
|
1355
1345
|
async function add(args) {
|
|
1356
1346
|
const { id: snapId, location, versionRange } = args;
|
|
1357
1347
|
_class_private_method_get(this, _setupRuntime, setupRuntime).call(this, snapId, {
|
|
@@ -1365,7 +1355,7 @@ async function add(args) {
|
|
|
1365
1355
|
// to null in the authorize() method.
|
|
1366
1356
|
runtime.installPromise = (async ()=>{
|
|
1367
1357
|
const fetchedSnap = await _class_private_method_get(this, _fetchSnap, fetchSnap).call(this, snapId, location);
|
|
1368
|
-
const manifest = fetchedSnap.manifest.result;
|
|
1358
|
+
const manifest = fetchedSnap.files.manifest.result;
|
|
1369
1359
|
if (!(0, _utils.satisfiesVersionRange)(manifest.version, versionRange)) {
|
|
1370
1360
|
throw new Error(`Version mismatch. Manifest for "${snapId}" specifies version "${manifest.version}" which doesn't satisfy requested version range "${versionRange}".`);
|
|
1371
1361
|
}
|
|
@@ -1435,15 +1425,16 @@ async function getEndowments(snapId) {
|
|
|
1435
1425
|
return dedupedEndowments;
|
|
1436
1426
|
}
|
|
1437
1427
|
function set(args) {
|
|
1438
|
-
const { id: snapId, origin,
|
|
1428
|
+
const { id: snapId, origin, files, isUpdate = false } = args;
|
|
1429
|
+
const { manifest, sourceCode: sourceCodeFile, svgIcon, auxiliaryFiles: rawAuxiliaryFiles } = files;
|
|
1439
1430
|
(0, _snapsutils.assertIsSnapManifest)(manifest.result);
|
|
1440
1431
|
const { version } = manifest.result;
|
|
1441
|
-
const
|
|
1442
|
-
const { iconPath } = manifest.result.source.location.npm;
|
|
1443
|
-
const normalizedIconPath = iconPath && (0, _snapsutils.normalizeRelative)(iconPath);
|
|
1444
|
-
const sourceCode = files.find((file)=>file.path === normalizedSourcePath)?.toString();
|
|
1445
|
-
const svgIcon = normalizedIconPath ? files.find((file)=>file.path === normalizedIconPath) : undefined;
|
|
1432
|
+
const sourceCode = sourceCodeFile.toString();
|
|
1446
1433
|
(0, _utils.assert)(typeof sourceCode === 'string' && sourceCode.length > 0, `Invalid source code for snap "${snapId}".`);
|
|
1434
|
+
const auxiliaryFiles = rawAuxiliaryFiles.map((file)=>({
|
|
1435
|
+
path: file.path,
|
|
1436
|
+
value: file.toString('base64')
|
|
1437
|
+
}));
|
|
1447
1438
|
const snapsState = this.state.snaps;
|
|
1448
1439
|
const existingSnap = snapsState[snapId];
|
|
1449
1440
|
const previousVersionHistory = existingSnap?.versionHistory ?? [];
|
|
@@ -1468,7 +1459,8 @@ function set(args) {
|
|
|
1468
1459
|
status: _class_private_field_get(this, _statusMachine).config.initial,
|
|
1469
1460
|
sourceCode,
|
|
1470
1461
|
version,
|
|
1471
|
-
versionHistory
|
|
1462
|
+
versionHistory,
|
|
1463
|
+
auxiliaryFiles
|
|
1472
1464
|
};
|
|
1473
1465
|
// If the snap was blocked, it isn't any longer
|
|
1474
1466
|
delete snap.blockInformation;
|
|
@@ -1496,19 +1488,15 @@ async function fetchSnap(snapId, location) {
|
|
|
1496
1488
|
const sourceCode = await location.fetch(manifest.result.source.location.npm.filePath);
|
|
1497
1489
|
const { iconPath } = manifest.result.source.location.npm;
|
|
1498
1490
|
const svgIcon = iconPath ? await location.fetch(iconPath) : undefined;
|
|
1499
|
-
const
|
|
1500
|
-
|
|
1501
|
-
];
|
|
1502
|
-
if (svgIcon) {
|
|
1503
|
-
files.push(svgIcon);
|
|
1504
|
-
}
|
|
1505
|
-
(0, _snapsutils.validateFetchedSnap)({
|
|
1491
|
+
const auxiliaryFiles = manifest.result.source.files ? await Promise.all(manifest.result.source.files.map(async (filePath)=>location.fetch(filePath))) : [];
|
|
1492
|
+
const files = {
|
|
1506
1493
|
manifest,
|
|
1507
1494
|
sourceCode,
|
|
1508
|
-
svgIcon
|
|
1509
|
-
|
|
1495
|
+
svgIcon,
|
|
1496
|
+
auxiliaryFiles
|
|
1497
|
+
};
|
|
1498
|
+
(0, _snapsutils.validateFetchedSnap)(files);
|
|
1510
1499
|
return {
|
|
1511
|
-
manifest,
|
|
1512
1500
|
files,
|
|
1513
1501
|
location
|
|
1514
1502
|
};
|
|
@@ -1577,8 +1565,11 @@ function getRpcRequestHandler(snapId) {
|
|
|
1577
1565
|
_class_private_method_get(this, _recordSnapRpcRequestFinish, recordSnapRpcRequestFinish).call(this, snapId, request.id);
|
|
1578
1566
|
return result;
|
|
1579
1567
|
} catch (error) {
|
|
1580
|
-
|
|
1581
|
-
|
|
1568
|
+
const [jsonRpcError, handled] = (0, _snapsutils.unwrapError)(error);
|
|
1569
|
+
if (!handled) {
|
|
1570
|
+
await this.stopSnap(snapId, _snapsutils.SnapStatusEvents.Crash);
|
|
1571
|
+
}
|
|
1572
|
+
throw jsonRpcError;
|
|
1582
1573
|
}
|
|
1583
1574
|
};
|
|
1584
1575
|
runtime.rpcHandler = rpcHandler;
|