@metamask-previews/permission-controller 12.1.1-preview-565dfca2 → 12.1.1-preview-3fa1672
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/Caveat.cjs.map +1 -1
- package/dist/Caveat.mjs.map +1 -1
- package/dist/PermissionController.cjs +406 -643
- package/dist/PermissionController.cjs.map +1 -1
- package/dist/PermissionController.d.cts +0 -267
- package/dist/PermissionController.d.cts.map +1 -1
- package/dist/PermissionController.d.mts +0 -267
- package/dist/PermissionController.d.mts.map +1 -1
- package/dist/PermissionController.mjs +406 -643
- package/dist/PermissionController.mjs.map +1 -1
- package/dist/SubjectMetadataController.cjs +42 -40
- package/dist/SubjectMetadataController.cjs.map +1 -1
- package/dist/SubjectMetadataController.d.cts +1 -17
- package/dist/SubjectMetadataController.d.cts.map +1 -1
- package/dist/SubjectMetadataController.d.mts +1 -17
- package/dist/SubjectMetadataController.d.mts.map +1 -1
- package/dist/SubjectMetadataController.mjs +42 -40
- package/dist/SubjectMetadataController.mjs.map +1 -1
- package/dist/errors.cjs +8 -7
- package/dist/errors.cjs.map +1 -1
- package/dist/errors.d.cts +4 -9
- package/dist/errors.d.cts.map +1 -1
- package/dist/errors.d.mts +4 -9
- package/dist/errors.d.mts.map +1 -1
- package/dist/errors.mjs +1 -0
- package/dist/errors.mjs.map +1 -1
- package/dist/permission-middleware.cjs +1 -1
- package/dist/permission-middleware.cjs.map +1 -1
- package/dist/permission-middleware.d.cts +4 -3
- package/dist/permission-middleware.d.cts.map +1 -1
- package/dist/permission-middleware.d.mts +4 -3
- package/dist/permission-middleware.d.mts.map +1 -1
- package/dist/permission-middleware.mjs +1 -1
- package/dist/permission-middleware.mjs.map +1 -1
- package/dist/utils.cjs.map +1 -1
- package/dist/utils.d.cts.map +1 -1
- package/dist/utils.d.mts.map +1 -1
- package/dist/utils.mjs.map +1 -1
- package/package.json +1 -1
|
@@ -4,10 +4,16 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
|
|
|
4
4
|
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
|
|
5
5
|
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
|
|
6
6
|
};
|
|
7
|
+
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
|
|
8
|
+
if (kind === "m") throw new TypeError("Private method is not writable");
|
|
9
|
+
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
|
|
10
|
+
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
|
|
11
|
+
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
|
|
12
|
+
};
|
|
7
13
|
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
8
14
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
9
15
|
};
|
|
10
|
-
var _PermissionController_instances, _PermissionController_expectGetCaveatMerger, _PermissionController_applyGrantedPermissions, _PermissionController_mergeIncrementalPermissions, _PermissionController_mergePermission, _PermissionController_mergeCaveat, _PermissionController_handleApprovedPermissions;
|
|
16
|
+
var _PermissionController_instances, _PermissionController_caveatSpecifications, _PermissionController_permissionSpecifications, _PermissionController_unrestrictedMethods, _PermissionController_getPermissionSpecification, _PermissionController_getCaveatSpecification, _PermissionController_expectGetCaveatMerger, _PermissionController_validatePermissionSpecifications, _PermissionController_registerMessageHandlers, _PermissionController_getTypedPermissionSpecification, _PermissionController_deletePermission, _PermissionController_setCaveat, _PermissionController_deleteCaveat, _PermissionController_validateModifiedPermission, _PermissionController_targetExists, _PermissionController_applyGrantedPermissions, _PermissionController_validatePermission, _PermissionController_setValidatedPermissions, _PermissionController_constructCaveats, _PermissionController_validateCaveat, _PermissionController_validateRequestedPermissions, _PermissionController_mergeIncrementalPermissions, _PermissionController_mergePermission, _PermissionController_mergeCaveat, _PermissionController_requestUserApproval, _PermissionController_handleApprovedPermissions, _PermissionController_getSideEffects, _PermissionController_executeSideEffects, _PermissionController_validateApprovedPermissions, _PermissionController_hasApprovalRequest, _PermissionController_rejectPermissionsRequest, _PermissionController_executeRestrictedMethod;
|
|
11
17
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
18
|
exports.PermissionController = exports.CaveatMutatorOperation = void 0;
|
|
13
19
|
const base_controller_1 = require("@metamask/base-controller");
|
|
@@ -81,7 +87,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
81
87
|
* @returns The names of all unrestricted JSON-RPC methods
|
|
82
88
|
*/
|
|
83
89
|
get unrestrictedMethods() {
|
|
84
|
-
return this
|
|
90
|
+
return __classPrivateFieldGet(this, _PermissionController_unrestrictedMethods, "f");
|
|
85
91
|
}
|
|
86
92
|
/**
|
|
87
93
|
* Constructs the PermissionController.
|
|
@@ -112,97 +118,22 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
112
118
|
},
|
|
113
119
|
});
|
|
114
120
|
_PermissionController_instances.add(this);
|
|
115
|
-
this
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
this
|
|
121
|
+
_PermissionController_caveatSpecifications.set(this, void 0);
|
|
122
|
+
_PermissionController_permissionSpecifications.set(this, void 0);
|
|
123
|
+
_PermissionController_unrestrictedMethods.set(this, void 0);
|
|
124
|
+
__classPrivateFieldSet(this, _PermissionController_unrestrictedMethods, new Set(unrestrictedMethods), "f");
|
|
125
|
+
__classPrivateFieldSet(this, _PermissionController_caveatSpecifications, (0, deep_freeze_strict_1.default)({ ...caveatSpecifications }), "f");
|
|
126
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validatePermissionSpecifications).call(this, permissionSpecifications, __classPrivateFieldGet(this, _PermissionController_caveatSpecifications, "f"));
|
|
127
|
+
__classPrivateFieldSet(this, _PermissionController_permissionSpecifications, (0, deep_freeze_strict_1.default)({
|
|
119
128
|
...permissionSpecifications,
|
|
120
|
-
});
|
|
121
|
-
this.
|
|
129
|
+
}), "f");
|
|
130
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_registerMessageHandlers).call(this);
|
|
122
131
|
this.createPermissionMiddleware = (0, permission_middleware_1.getPermissionMiddlewareFactory)({
|
|
123
|
-
executeRestrictedMethod: this.
|
|
132
|
+
executeRestrictedMethod: __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_executeRestrictedMethod).bind(this),
|
|
124
133
|
getRestrictedMethod: this.getRestrictedMethod.bind(this),
|
|
125
134
|
isUnrestrictedMethod: this.unrestrictedMethods.has.bind(this.unrestrictedMethods),
|
|
126
135
|
});
|
|
127
136
|
}
|
|
128
|
-
/**
|
|
129
|
-
* Gets a permission specification.
|
|
130
|
-
*
|
|
131
|
-
* @param targetName - The name of the permission specification to get.
|
|
132
|
-
* @returns The permission specification with the specified target name.
|
|
133
|
-
*/
|
|
134
|
-
getPermissionSpecification(targetName) {
|
|
135
|
-
return this._permissionSpecifications[targetName];
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* Gets a caveat specification.
|
|
139
|
-
*
|
|
140
|
-
* @param caveatType - The type of the caveat specification to get.
|
|
141
|
-
* @returns The caveat specification with the specified type.
|
|
142
|
-
*/
|
|
143
|
-
getCaveatSpecification(caveatType) {
|
|
144
|
-
return this._caveatSpecifications[caveatType];
|
|
145
|
-
}
|
|
146
|
-
/**
|
|
147
|
-
* Constructor helper for validating permission specifications.
|
|
148
|
-
*
|
|
149
|
-
* Throws an error if validation fails.
|
|
150
|
-
*
|
|
151
|
-
* @param permissionSpecifications - The permission specifications passed to
|
|
152
|
-
* this controller's constructor.
|
|
153
|
-
* @param caveatSpecifications - The caveat specifications passed to this
|
|
154
|
-
* controller.
|
|
155
|
-
*/
|
|
156
|
-
validatePermissionSpecifications(permissionSpecifications, caveatSpecifications) {
|
|
157
|
-
Object.entries(permissionSpecifications).forEach(([targetName, { permissionType, targetName: innerTargetName, allowedCaveats },]) => {
|
|
158
|
-
if (!permissionType || !(0, utils_1.hasProperty)(Permission_1.PermissionType, permissionType)) {
|
|
159
|
-
throw new Error(`Invalid permission type: "${permissionType}"`);
|
|
160
|
-
}
|
|
161
|
-
if (!targetName) {
|
|
162
|
-
throw new Error(`Invalid permission target name: "${targetName}"`);
|
|
163
|
-
}
|
|
164
|
-
if (targetName !== innerTargetName) {
|
|
165
|
-
throw new Error(`Invalid permission specification: target name "${targetName}" must match specification.targetName value "${innerTargetName}".`);
|
|
166
|
-
}
|
|
167
|
-
if (allowedCaveats) {
|
|
168
|
-
allowedCaveats.forEach((caveatType) => {
|
|
169
|
-
if (!(0, utils_1.hasProperty)(caveatSpecifications, caveatType)) {
|
|
170
|
-
throw new errors_1.UnrecognizedCaveatTypeError(caveatType);
|
|
171
|
-
}
|
|
172
|
-
const specification = caveatSpecifications[caveatType];
|
|
173
|
-
const isRestrictedMethodCaveat = (0, Caveat_1.isRestrictedMethodCaveatSpecification)(specification);
|
|
174
|
-
if ((permissionType === Permission_1.PermissionType.RestrictedMethod &&
|
|
175
|
-
!isRestrictedMethodCaveat) ||
|
|
176
|
-
(permissionType === Permission_1.PermissionType.Endowment &&
|
|
177
|
-
isRestrictedMethodCaveat)) {
|
|
178
|
-
throw new errors_1.CaveatSpecificationMismatchError(specification, permissionType);
|
|
179
|
-
}
|
|
180
|
-
});
|
|
181
|
-
}
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
/**
|
|
185
|
-
* Constructor helper for registering the controller's messenger actions.
|
|
186
|
-
*/
|
|
187
|
-
registerMessageHandlers() {
|
|
188
|
-
this.messenger.registerActionHandler(`${controllerName}:clearPermissions`, () => this.clearState());
|
|
189
|
-
this.messenger.registerActionHandler(`${controllerName}:getEndowments`, (origin, targetName, requestData) => this.getEndowments(origin, targetName, requestData));
|
|
190
|
-
this.messenger.registerActionHandler(`${controllerName}:getSubjectNames`, () => this.getSubjectNames());
|
|
191
|
-
this.messenger.registerActionHandler(`${controllerName}:getPermissions`, (origin) => this.getPermissions(origin));
|
|
192
|
-
this.messenger.registerActionHandler(`${controllerName}:hasPermission`, (origin, targetName) => this.hasPermission(origin, targetName));
|
|
193
|
-
this.messenger.registerActionHandler(`${controllerName}:hasPermissions`, (origin) => this.hasPermissions(origin));
|
|
194
|
-
this.messenger.registerActionHandler(`${controllerName}:grantPermissions`, this.grantPermissions.bind(this));
|
|
195
|
-
this.messenger.registerActionHandler(`${controllerName}:grantPermissionsIncremental`, this.grantPermissionsIncremental.bind(this));
|
|
196
|
-
this.messenger.registerActionHandler(`${controllerName}:requestPermissions`, (subject, permissions) => this.requestPermissions(subject, permissions));
|
|
197
|
-
this.messenger.registerActionHandler(`${controllerName}:requestPermissionsIncremental`, (subject, permissions) => this.requestPermissionsIncremental(subject, permissions));
|
|
198
|
-
this.messenger.registerActionHandler(`${controllerName}:revokeAllPermissions`, (origin) => this.revokeAllPermissions(origin));
|
|
199
|
-
this.messenger.registerActionHandler(`${controllerName}:revokePermissionForAllSubjects`, (target) => this.revokePermissionForAllSubjects(target));
|
|
200
|
-
this.messenger.registerActionHandler(`${controllerName}:revokePermissions`, this.revokePermissions.bind(this));
|
|
201
|
-
this.messenger.registerActionHandler(`${controllerName}:updateCaveat`, (origin, target, caveatType, caveatValue) => {
|
|
202
|
-
this.updateCaveat(origin, target, caveatType, caveatValue);
|
|
203
|
-
});
|
|
204
|
-
this.messenger.registerActionHandler(`${controllerName}:getCaveat`, (origin, target, caveatType) => this.getCaveat(origin, target, caveatType));
|
|
205
|
-
}
|
|
206
137
|
/**
|
|
207
138
|
* Clears the state of the controller.
|
|
208
139
|
*/
|
|
@@ -213,33 +144,6 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
213
144
|
};
|
|
214
145
|
});
|
|
215
146
|
}
|
|
216
|
-
/**
|
|
217
|
-
* Gets the permission specification corresponding to the given permission
|
|
218
|
-
* type and target name. Throws an error if the target name does not
|
|
219
|
-
* correspond to a permission, or if the specification is not of the
|
|
220
|
-
* given permission type.
|
|
221
|
-
*
|
|
222
|
-
* @template Type - The type of the permission specification to get.
|
|
223
|
-
* @param permissionType - The type of the permission specification to get.
|
|
224
|
-
* @param targetName - The name of the permission whose specification to get.
|
|
225
|
-
* @param requestingOrigin - The origin of the requesting subject, if any.
|
|
226
|
-
* Will be added to any thrown errors.
|
|
227
|
-
* @returns The specification object corresponding to the given type and
|
|
228
|
-
* target name.
|
|
229
|
-
*/
|
|
230
|
-
getTypedPermissionSpecification(permissionType, targetName, requestingOrigin) {
|
|
231
|
-
const failureError = permissionType === Permission_1.PermissionType.RestrictedMethod
|
|
232
|
-
? (0, errors_1.methodNotFound)(targetName, requestingOrigin ? { origin: requestingOrigin } : undefined)
|
|
233
|
-
: new errors_1.EndowmentPermissionDoesNotExistError(targetName, requestingOrigin);
|
|
234
|
-
if (!this.targetExists(targetName)) {
|
|
235
|
-
throw failureError;
|
|
236
|
-
}
|
|
237
|
-
const specification = this.getPermissionSpecification(targetName);
|
|
238
|
-
if (!(0, Permission_1.hasSpecificationType)(specification, permissionType)) {
|
|
239
|
-
throw failureError;
|
|
240
|
-
}
|
|
241
|
-
return specification;
|
|
242
|
-
}
|
|
243
147
|
/**
|
|
244
148
|
* Gets the implementation of the specified restricted method.
|
|
245
149
|
*
|
|
@@ -253,7 +157,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
253
157
|
* @returns The restricted method implementation.
|
|
254
158
|
*/
|
|
255
159
|
getRestrictedMethod(method, origin) {
|
|
256
|
-
return this.
|
|
160
|
+
return __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getTypedPermissionSpecification).call(this, Permission_1.PermissionType.RestrictedMethod, method, origin).methodImplementation;
|
|
257
161
|
}
|
|
258
162
|
/**
|
|
259
163
|
* Gets a list of all origins of subjects.
|
|
@@ -351,7 +255,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
351
255
|
if (!(0, utils_1.hasProperty)(permissions, target)) {
|
|
352
256
|
throw new errors_1.PermissionDoesNotExistError(origin, target);
|
|
353
257
|
}
|
|
354
|
-
this.
|
|
258
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_deletePermission).call(this, draftState.subjects, origin, target);
|
|
355
259
|
});
|
|
356
260
|
});
|
|
357
261
|
});
|
|
@@ -370,30 +274,11 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
370
274
|
Object.entries(draftState.subjects).forEach(([origin, subject]) => {
|
|
371
275
|
const { permissions } = subject;
|
|
372
276
|
if ((0, utils_1.hasProperty)(permissions, target)) {
|
|
373
|
-
this.
|
|
277
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_deletePermission).call(this, draftState.subjects, origin, target);
|
|
374
278
|
}
|
|
375
279
|
});
|
|
376
280
|
});
|
|
377
281
|
}
|
|
378
|
-
/**
|
|
379
|
-
* Deletes the permission identified by the given origin and target. If the
|
|
380
|
-
* permission is the single remaining permission of its subject, the subject
|
|
381
|
-
* is also deleted.
|
|
382
|
-
*
|
|
383
|
-
* @param subjects - The draft permission controller subjects.
|
|
384
|
-
* @param origin - The origin of the subject associated with the permission
|
|
385
|
-
* to delete.
|
|
386
|
-
* @param target - The target name of the permission to delete.
|
|
387
|
-
*/
|
|
388
|
-
deletePermission(subjects, origin, target) {
|
|
389
|
-
const { permissions } = subjects[origin];
|
|
390
|
-
if (Object.keys(permissions).length > 1) {
|
|
391
|
-
delete permissions[target];
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
delete subjects[origin];
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
282
|
/**
|
|
398
283
|
* Checks whether the permission of the subject corresponding to the given
|
|
399
284
|
* origin has a caveat of the specified type.
|
|
@@ -457,7 +342,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
457
342
|
if (this.hasCaveat(origin, target, caveatType)) {
|
|
458
343
|
throw new errors_1.CaveatAlreadyExistsError(origin, target, caveatType);
|
|
459
344
|
}
|
|
460
|
-
this.
|
|
345
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_setCaveat).call(this, origin, target, caveatType, caveatValue);
|
|
461
346
|
}
|
|
462
347
|
/**
|
|
463
348
|
* Updates the value of the caveat of the specified type belonging to the
|
|
@@ -481,74 +366,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
481
366
|
if (!this.hasCaveat(origin, target, caveatType)) {
|
|
482
367
|
throw new errors_1.CaveatDoesNotExistError(origin, target, caveatType);
|
|
483
368
|
}
|
|
484
|
-
this.
|
|
485
|
-
}
|
|
486
|
-
/**
|
|
487
|
-
* Sets the specified caveat on the specified permission. Overwrites existing
|
|
488
|
-
* caveats of the same type in-place (preserving array order), and adds the
|
|
489
|
-
* caveat to the end of the array otherwise.
|
|
490
|
-
*
|
|
491
|
-
* Throws an error if the permission does not exist or fails to validate after
|
|
492
|
-
* its caveats have been modified.
|
|
493
|
-
*
|
|
494
|
-
* @see {@link PermissionController.addCaveat}
|
|
495
|
-
* @see {@link PermissionController.updateCaveat}
|
|
496
|
-
* @template TargetName - The permission target name. Should be inferred.
|
|
497
|
-
* @template CaveatType - The valid caveat types for the permission. Should
|
|
498
|
-
* be inferred.
|
|
499
|
-
* @param origin - The origin of the subject.
|
|
500
|
-
* @param target - The target name of the permission.
|
|
501
|
-
* @param caveatType - The type of the caveat to set.
|
|
502
|
-
* @param caveatValue - The value of the caveat to set.
|
|
503
|
-
*/
|
|
504
|
-
setCaveat(origin, target, caveatType, caveatValue) {
|
|
505
|
-
this.update((draftState) => {
|
|
506
|
-
const subject = draftState.subjects[origin];
|
|
507
|
-
// Unreachable because `hasCaveat` is always called before this, and it
|
|
508
|
-
// throws if permissions are missing. TypeScript needs this, however.
|
|
509
|
-
/* istanbul ignore if */
|
|
510
|
-
if (!subject) {
|
|
511
|
-
throw new errors_1.UnrecognizedSubjectError(origin);
|
|
512
|
-
}
|
|
513
|
-
const permission = subject.permissions[target];
|
|
514
|
-
/* istanbul ignore if: practically impossible, but TypeScript wants it */
|
|
515
|
-
if (!permission) {
|
|
516
|
-
throw new errors_1.PermissionDoesNotExistError(origin, target);
|
|
517
|
-
}
|
|
518
|
-
const caveat = {
|
|
519
|
-
type: caveatType,
|
|
520
|
-
value: caveatValue,
|
|
521
|
-
};
|
|
522
|
-
this.validateCaveat(caveat, origin, target);
|
|
523
|
-
let addedCaveat = false;
|
|
524
|
-
if (permission.caveats) {
|
|
525
|
-
const caveatIndex = permission.caveats.findIndex((existingCaveat) => existingCaveat.type === caveat.type);
|
|
526
|
-
if (caveatIndex === -1) {
|
|
527
|
-
permission.caveats.push(caveat);
|
|
528
|
-
addedCaveat = true;
|
|
529
|
-
}
|
|
530
|
-
else {
|
|
531
|
-
permission.caveats.splice(caveatIndex, 1, caveat);
|
|
532
|
-
}
|
|
533
|
-
}
|
|
534
|
-
else {
|
|
535
|
-
// At this point, we don't know if the specific permission is allowed
|
|
536
|
-
// to have caveats, but it should be impossible to call this method
|
|
537
|
-
// for a permission that may not have any caveats. If all else fails,
|
|
538
|
-
// the permission validator is also called.
|
|
539
|
-
// @ts-expect-error See above comment
|
|
540
|
-
permission.caveats = [caveat];
|
|
541
|
-
addedCaveat = true;
|
|
542
|
-
}
|
|
543
|
-
// Mutating a caveat does not warrant permission validation, but mutating
|
|
544
|
-
// the caveat array does.
|
|
545
|
-
if (addedCaveat) {
|
|
546
|
-
this.validateModifiedPermission(permission, origin, {
|
|
547
|
-
invokePermissionValidator: true,
|
|
548
|
-
performCaveatValidation: false, // We just validated the caveat
|
|
549
|
-
});
|
|
550
|
-
}
|
|
551
|
-
});
|
|
369
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_setCaveat).call(this, origin, target, caveatType, caveatValue);
|
|
552
370
|
}
|
|
553
371
|
/**
|
|
554
372
|
* Updates all caveats with the specified type for all subjects and
|
|
@@ -600,13 +418,13 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
600
418
|
// results in an error.
|
|
601
419
|
targetCaveat.value =
|
|
602
420
|
mutatorResult.value;
|
|
603
|
-
this.
|
|
421
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateCaveat).call(this, targetCaveat, subject.origin, permission.parentCapability);
|
|
604
422
|
break;
|
|
605
423
|
case CaveatMutatorOperation.DeleteCaveat:
|
|
606
|
-
this.
|
|
424
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_deleteCaveat).call(this, permission, targetCaveatType, subject.origin);
|
|
607
425
|
break;
|
|
608
426
|
case CaveatMutatorOperation.RevokePermission:
|
|
609
|
-
this.
|
|
427
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_deletePermission).call(this, draftState.subjects, subject.origin, permission.parentCapability);
|
|
610
428
|
break;
|
|
611
429
|
default: {
|
|
612
430
|
// Overriding as `never` is the expected result of exhaustiveness checking,
|
|
@@ -641,70 +459,9 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
641
459
|
if (!permission.caveats) {
|
|
642
460
|
throw new errors_1.CaveatDoesNotExistError(origin, target, caveatType);
|
|
643
461
|
}
|
|
644
|
-
this.
|
|
462
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_deleteCaveat).call(this, permission, caveatType, origin);
|
|
645
463
|
});
|
|
646
464
|
}
|
|
647
|
-
/**
|
|
648
|
-
* Deletes the specified caveat from the specified permission. If no caveats
|
|
649
|
-
* remain after deletion, the permission's caveat property is set to `null`.
|
|
650
|
-
* The permission is validated after being modified.
|
|
651
|
-
*
|
|
652
|
-
* Throws an error if the permission does not have a caveat with the specified
|
|
653
|
-
* type.
|
|
654
|
-
*
|
|
655
|
-
* @param permission - The permission whose caveat to delete.
|
|
656
|
-
* @param caveatType - The type of the caveat to delete.
|
|
657
|
-
* @param origin - The origin the permission subject.
|
|
658
|
-
*/
|
|
659
|
-
deleteCaveat(permission, caveatType, origin) {
|
|
660
|
-
/* istanbul ignore if: not possible in our usage */
|
|
661
|
-
if (!permission.caveats) {
|
|
662
|
-
throw new errors_1.CaveatDoesNotExistError(origin, permission.parentCapability, caveatType);
|
|
663
|
-
}
|
|
664
|
-
const caveatIndex = permission.caveats.findIndex((existingCaveat) => existingCaveat.type === caveatType);
|
|
665
|
-
if (caveatIndex === -1) {
|
|
666
|
-
throw new errors_1.CaveatDoesNotExistError(origin, permission.parentCapability, caveatType);
|
|
667
|
-
}
|
|
668
|
-
if (permission.caveats.length === 1) {
|
|
669
|
-
permission.caveats = null;
|
|
670
|
-
}
|
|
671
|
-
else {
|
|
672
|
-
permission.caveats.splice(caveatIndex, 1);
|
|
673
|
-
}
|
|
674
|
-
this.validateModifiedPermission(permission, origin, {
|
|
675
|
-
invokePermissionValidator: true,
|
|
676
|
-
performCaveatValidation: false, // No caveat object was mutated
|
|
677
|
-
});
|
|
678
|
-
}
|
|
679
|
-
/**
|
|
680
|
-
* Validates the specified modified permission. Should **always** be invoked
|
|
681
|
-
* on a permission when its caveat array has been mutated.
|
|
682
|
-
*
|
|
683
|
-
* Just like {@link PermissionController.validatePermission}, except that the
|
|
684
|
-
* corresponding target name and specification are retrieved first, and an
|
|
685
|
-
* error is thrown if the target name does not exist.
|
|
686
|
-
*
|
|
687
|
-
* @param permission - The modified permission to validate.
|
|
688
|
-
* @param origin - The origin associated with the permission.
|
|
689
|
-
* @param validationFlags - Validation flags. See {@link PermissionController.validatePermission}.
|
|
690
|
-
*/
|
|
691
|
-
validateModifiedPermission(permission, origin, validationFlags) {
|
|
692
|
-
/* istanbul ignore if: this should be impossible */
|
|
693
|
-
if (!this.targetExists(permission.parentCapability)) {
|
|
694
|
-
throw new Error(`Fatal: Existing permission target "${permission.parentCapability}" has no specification.`);
|
|
695
|
-
}
|
|
696
|
-
this.validatePermission(this.getPermissionSpecification(permission.parentCapability), permission, origin, validationFlags);
|
|
697
|
-
}
|
|
698
|
-
/**
|
|
699
|
-
* Verifies the existence the specified permission target, i.e. whether it has
|
|
700
|
-
* a specification.
|
|
701
|
-
*
|
|
702
|
-
* @param target - The requested permission target.
|
|
703
|
-
* @returns Whether the permission target exists.
|
|
704
|
-
*/
|
|
705
|
-
targetExists(target) {
|
|
706
|
-
return (0, utils_1.hasProperty)(this._permissionSpecifications, target);
|
|
707
|
-
}
|
|
708
465
|
/**
|
|
709
466
|
* Grants _approved_ permissions to the specified subject. Every permission and
|
|
710
467
|
* caveat is stringently validated—including by calling their specification
|
|
@@ -761,139 +518,6 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
761
518
|
requestData,
|
|
762
519
|
});
|
|
763
520
|
}
|
|
764
|
-
/**
|
|
765
|
-
* Validates the specified permission by:
|
|
766
|
-
* - Ensuring that if `subjectTypes` is specified, the subject requesting the permission is of a type in the list.
|
|
767
|
-
* - Ensuring that its `caveats` property is either `null` or a non-empty array.
|
|
768
|
-
* - Ensuring that it only includes caveats allowed by its specification.
|
|
769
|
-
* - Ensuring that it includes no duplicate caveats (by caveat type).
|
|
770
|
-
* - Validating each caveat object, if `performCaveatValidation` is `true`.
|
|
771
|
-
* - Calling the validator of its specification, if one exists and `invokePermissionValidator` is `true`.
|
|
772
|
-
*
|
|
773
|
-
* An error is thrown if validation fails.
|
|
774
|
-
*
|
|
775
|
-
* @param specification - The specification of the permission.
|
|
776
|
-
* @param permission - The permission to validate.
|
|
777
|
-
* @param origin - The origin associated with the permission.
|
|
778
|
-
* @param validationOptions - Validation options.
|
|
779
|
-
* @param validationOptions.invokePermissionValidator - Whether to invoke the
|
|
780
|
-
* permission's consumer-specified validator function, if any.
|
|
781
|
-
* @param validationOptions.performCaveatValidation - Whether to invoke
|
|
782
|
-
* {@link PermissionController.validateCaveat} on each of the permission's
|
|
783
|
-
* caveats.
|
|
784
|
-
*/
|
|
785
|
-
validatePermission(specification, permission, origin, { invokePermissionValidator, performCaveatValidation, }) {
|
|
786
|
-
const { allowedCaveats, validator, targetName } = specification;
|
|
787
|
-
if (specification.subjectTypes?.length &&
|
|
788
|
-
specification.subjectTypes.length > 0) {
|
|
789
|
-
const metadata = this.messenger.call('SubjectMetadataController:getSubjectMetadata', origin);
|
|
790
|
-
if (!metadata ||
|
|
791
|
-
metadata.subjectType === null ||
|
|
792
|
-
!specification.subjectTypes.includes(metadata.subjectType)) {
|
|
793
|
-
throw specification.permissionType === Permission_1.PermissionType.RestrictedMethod
|
|
794
|
-
? (0, errors_1.methodNotFound)(targetName, { origin })
|
|
795
|
-
: new errors_1.EndowmentPermissionDoesNotExistError(targetName, origin);
|
|
796
|
-
}
|
|
797
|
-
}
|
|
798
|
-
if ((0, utils_1.hasProperty)(permission, 'caveats')) {
|
|
799
|
-
const { caveats } = permission;
|
|
800
|
-
if (caveats !== null && !(Array.isArray(caveats) && caveats.length > 0)) {
|
|
801
|
-
throw new errors_1.InvalidCaveatsPropertyError(origin, targetName, caveats);
|
|
802
|
-
}
|
|
803
|
-
const seenCaveatTypes = new Set();
|
|
804
|
-
caveats?.forEach((caveat) => {
|
|
805
|
-
if (performCaveatValidation) {
|
|
806
|
-
this.validateCaveat(caveat, origin, targetName);
|
|
807
|
-
}
|
|
808
|
-
if (!allowedCaveats?.includes(caveat.type)) {
|
|
809
|
-
throw new errors_1.ForbiddenCaveatError(caveat.type, origin, targetName);
|
|
810
|
-
}
|
|
811
|
-
if (seenCaveatTypes.has(caveat.type)) {
|
|
812
|
-
throw new errors_1.DuplicateCaveatError(caveat.type, origin, targetName);
|
|
813
|
-
}
|
|
814
|
-
seenCaveatTypes.add(caveat.type);
|
|
815
|
-
});
|
|
816
|
-
}
|
|
817
|
-
if (invokePermissionValidator && validator) {
|
|
818
|
-
validator(permission, origin, targetName);
|
|
819
|
-
}
|
|
820
|
-
}
|
|
821
|
-
/**
|
|
822
|
-
* Assigns the specified permissions to the subject with the given origin.
|
|
823
|
-
* Overwrites all existing permissions, and creates a subject entry if it
|
|
824
|
-
* doesn't already exist.
|
|
825
|
-
*
|
|
826
|
-
* ATTN: Assumes that the new permissions have been validated.
|
|
827
|
-
*
|
|
828
|
-
* @param origin - The origin of the grantee subject.
|
|
829
|
-
* @param permissions - The new permissions for the grantee subject.
|
|
830
|
-
*/
|
|
831
|
-
setValidatedPermissions(origin, permissions) {
|
|
832
|
-
this.update((draftState) => {
|
|
833
|
-
if (!draftState.subjects[origin]) {
|
|
834
|
-
draftState.subjects[origin] = { origin, permissions: {} };
|
|
835
|
-
}
|
|
836
|
-
draftState.subjects[origin].permissions = (0, immer_1.castDraft)(permissions);
|
|
837
|
-
});
|
|
838
|
-
}
|
|
839
|
-
/**
|
|
840
|
-
* Validates the requested caveats for the permission of the specified
|
|
841
|
-
* subject origin and target name and returns the validated caveat array.
|
|
842
|
-
*
|
|
843
|
-
* Throws an error if validation fails.
|
|
844
|
-
*
|
|
845
|
-
* @param origin - The origin of the permission subject.
|
|
846
|
-
* @param target - The permission target name.
|
|
847
|
-
* @param requestedCaveats - The requested caveats to construct.
|
|
848
|
-
* @returns The constructed caveats.
|
|
849
|
-
*/
|
|
850
|
-
constructCaveats(origin, target, requestedCaveats) {
|
|
851
|
-
const caveatArray = requestedCaveats?.map((requestedCaveat) => {
|
|
852
|
-
this.validateCaveat(requestedCaveat, origin, target);
|
|
853
|
-
// Reassign so that we have a fresh object.
|
|
854
|
-
const { type, value } = requestedCaveat;
|
|
855
|
-
return { type, value };
|
|
856
|
-
});
|
|
857
|
-
return caveatArray && (0, controller_utils_1.isNonEmptyArray)(caveatArray)
|
|
858
|
-
? caveatArray
|
|
859
|
-
: undefined;
|
|
860
|
-
}
|
|
861
|
-
/**
|
|
862
|
-
* This methods validates that the specified caveat is an object with the
|
|
863
|
-
* expected properties and types. It also ensures that a caveat specification
|
|
864
|
-
* exists for the requested caveat type, and calls the specification
|
|
865
|
-
* validator, if it exists, on the caveat object.
|
|
866
|
-
*
|
|
867
|
-
* Throws an error if validation fails.
|
|
868
|
-
*
|
|
869
|
-
* @param caveat - The caveat object to validate.
|
|
870
|
-
* @param origin - The origin associated with the subject of the parent
|
|
871
|
-
* permission.
|
|
872
|
-
* @param target - The target name associated with the parent permission.
|
|
873
|
-
*/
|
|
874
|
-
validateCaveat(caveat, origin, target) {
|
|
875
|
-
if (!(0, controller_utils_1.isPlainObject)(caveat)) {
|
|
876
|
-
throw new errors_1.InvalidCaveatError(caveat, origin, target);
|
|
877
|
-
}
|
|
878
|
-
if (Object.keys(caveat).length !== 2) {
|
|
879
|
-
throw new errors_1.InvalidCaveatFieldsError(caveat, origin, target);
|
|
880
|
-
}
|
|
881
|
-
if (typeof caveat.type !== 'string') {
|
|
882
|
-
throw new errors_1.InvalidCaveatTypeError(caveat, origin, target);
|
|
883
|
-
}
|
|
884
|
-
const specification = this.getCaveatSpecification(caveat.type);
|
|
885
|
-
if (!specification) {
|
|
886
|
-
throw new errors_1.UnrecognizedCaveatTypeError(caveat.type, origin, target);
|
|
887
|
-
}
|
|
888
|
-
if (!(0, utils_1.hasProperty)(caveat, 'value') || caveat.value === undefined) {
|
|
889
|
-
throw new errors_1.CaveatMissingValueError(caveat, origin, target);
|
|
890
|
-
}
|
|
891
|
-
if (!(0, controller_utils_1.isValidJson)(caveat.value)) {
|
|
892
|
-
throw new errors_1.CaveatInvalidJsonError(caveat, origin, target);
|
|
893
|
-
}
|
|
894
|
-
// Typecast: TypeScript still believes that the caveat is a PlainObject.
|
|
895
|
-
specification.validator?.(caveat, origin, target);
|
|
896
|
-
}
|
|
897
521
|
/**
|
|
898
522
|
* Initiates a permission request that requires user approval.
|
|
899
523
|
*
|
|
@@ -922,7 +546,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
922
546
|
async requestPermissions(subject, requestedPermissions, options = {}) {
|
|
923
547
|
const { origin } = subject;
|
|
924
548
|
const { id = (0, nanoid_1.nanoid)(), preserveExistingPermissions = true } = options;
|
|
925
|
-
this.
|
|
549
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateRequestedPermissions).call(this, origin, requestedPermissions);
|
|
926
550
|
const metadata = {
|
|
927
551
|
...options.metadata,
|
|
928
552
|
id,
|
|
@@ -932,7 +556,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
932
556
|
metadata,
|
|
933
557
|
permissions: requestedPermissions,
|
|
934
558
|
};
|
|
935
|
-
const approvedRequest = await this.
|
|
559
|
+
const approvedRequest = await __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_requestUserApproval).call(this, permissionsRequest);
|
|
936
560
|
return await __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_handleApprovedPermissions).call(this, {
|
|
937
561
|
subject,
|
|
938
562
|
metadata,
|
|
@@ -974,7 +598,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
974
598
|
async requestPermissionsIncremental(subject, requestedPermissions, options = {}) {
|
|
975
599
|
const { origin } = subject;
|
|
976
600
|
const { id = (0, nanoid_1.nanoid)() } = options;
|
|
977
|
-
this.
|
|
601
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateRequestedPermissions).call(this, origin, requestedPermissions);
|
|
978
602
|
const currentPermissions = this.getPermissions(origin) ?? {};
|
|
979
603
|
const [newPermissions, permissionDiffMap] = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_mergeIncrementalPermissions).call(this, currentPermissions, requestedPermissions);
|
|
980
604
|
// The second undefined check is just for type narrowing purposes. These values
|
|
@@ -986,7 +610,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
986
610
|
// It does not spark joy to run this validation again after the merger operation.
|
|
987
611
|
// But, optimizing this procedure is probably not worth it, especially considering
|
|
988
612
|
// that the worst-case scenario for validation degrades to the below function call.
|
|
989
|
-
this.
|
|
613
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateRequestedPermissions).call(this, origin, newPermissions);
|
|
990
614
|
}
|
|
991
615
|
catch (error) {
|
|
992
616
|
if (error instanceof Error) {
|
|
@@ -1008,7 +632,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1008
632
|
permissionDiffMap,
|
|
1009
633
|
},
|
|
1010
634
|
};
|
|
1011
|
-
const approvedRequest = await this.
|
|
635
|
+
const approvedRequest = await __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_requestUserApproval).call(this, permissionsRequest);
|
|
1012
636
|
return await __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_handleApprovedPermissions).call(this, {
|
|
1013
637
|
subject,
|
|
1014
638
|
metadata,
|
|
@@ -1016,172 +640,6 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1016
640
|
approvedRequest,
|
|
1017
641
|
});
|
|
1018
642
|
}
|
|
1019
|
-
/**
|
|
1020
|
-
* Validates requested permissions. Throws if validation fails.
|
|
1021
|
-
*
|
|
1022
|
-
* This method ensures that the requested permissions are a properly
|
|
1023
|
-
* formatted {@link RequestedPermissions} object, and performs the same
|
|
1024
|
-
* validation as {@link PermissionController.grantPermissions}, except that
|
|
1025
|
-
* consumer-specified permission validator functions are not called, since
|
|
1026
|
-
* they are only called on fully constructed, approved permissions that are
|
|
1027
|
-
* otherwise completely valid.
|
|
1028
|
-
*
|
|
1029
|
-
* Unrecognzied properties on requested permissions are ignored.
|
|
1030
|
-
*
|
|
1031
|
-
* @param origin - The origin of the grantee subject.
|
|
1032
|
-
* @param requestedPermissions - The requested permissions.
|
|
1033
|
-
*/
|
|
1034
|
-
validateRequestedPermissions(origin, requestedPermissions) {
|
|
1035
|
-
if (!(0, controller_utils_1.isPlainObject)(requestedPermissions)) {
|
|
1036
|
-
throw (0, errors_1.invalidParams)({
|
|
1037
|
-
message: `Requested permissions for origin "${origin}" is not a plain object.`,
|
|
1038
|
-
data: { origin, requestedPermissions },
|
|
1039
|
-
});
|
|
1040
|
-
}
|
|
1041
|
-
if (Object.keys(requestedPermissions).length === 0) {
|
|
1042
|
-
throw (0, errors_1.invalidParams)({
|
|
1043
|
-
message: `Permissions request for origin "${origin}" contains no permissions.`,
|
|
1044
|
-
data: { requestedPermissions },
|
|
1045
|
-
});
|
|
1046
|
-
}
|
|
1047
|
-
for (const targetName of Object.keys(requestedPermissions)) {
|
|
1048
|
-
const permission = requestedPermissions[targetName];
|
|
1049
|
-
if (!this.targetExists(targetName)) {
|
|
1050
|
-
throw (0, errors_1.methodNotFound)(targetName, { origin, requestedPermissions });
|
|
1051
|
-
}
|
|
1052
|
-
if (!(0, controller_utils_1.isPlainObject)(permission) ||
|
|
1053
|
-
(permission.parentCapability !== undefined &&
|
|
1054
|
-
targetName !== permission.parentCapability)) {
|
|
1055
|
-
throw (0, errors_1.invalidParams)({
|
|
1056
|
-
message: `Permissions request for origin "${origin}" contains invalid requested permission(s).`,
|
|
1057
|
-
data: { origin, requestedPermissions },
|
|
1058
|
-
});
|
|
1059
|
-
}
|
|
1060
|
-
// Here we validate the permission without invoking its validator, if any.
|
|
1061
|
-
// The validator will be invoked after the permission has been approved.
|
|
1062
|
-
this.validatePermission(this.getPermissionSpecification(targetName),
|
|
1063
|
-
// Typecast: The permission is still a "PlainObject" here.
|
|
1064
|
-
permission, origin, { invokePermissionValidator: false, performCaveatValidation: true });
|
|
1065
|
-
}
|
|
1066
|
-
}
|
|
1067
|
-
/**
|
|
1068
|
-
* Adds a request to the {@link ApprovalController} using the
|
|
1069
|
-
* {@link AddApprovalRequest} action. Also validates the resulting approved
|
|
1070
|
-
* permissions request, and throws an error if validation fails.
|
|
1071
|
-
*
|
|
1072
|
-
* @param permissionsRequest - The permissions request object.
|
|
1073
|
-
* @returns The approved permissions request object.
|
|
1074
|
-
*/
|
|
1075
|
-
async requestUserApproval(permissionsRequest) {
|
|
1076
|
-
const { origin, id } = permissionsRequest.metadata;
|
|
1077
|
-
const approvedRequest = await this.messenger.call('ApprovalController:addRequest', {
|
|
1078
|
-
id,
|
|
1079
|
-
origin,
|
|
1080
|
-
requestData: permissionsRequest,
|
|
1081
|
-
type: utils_2.MethodNames.RequestPermissions,
|
|
1082
|
-
}, true);
|
|
1083
|
-
this.validateApprovedPermissions(approvedRequest, { id, origin });
|
|
1084
|
-
return approvedRequest;
|
|
1085
|
-
}
|
|
1086
|
-
/**
|
|
1087
|
-
* Reunites all the side-effects (onPermitted and onFailure) of the requested permissions inside a record of arrays.
|
|
1088
|
-
*
|
|
1089
|
-
* @param permissions - The approved permissions.
|
|
1090
|
-
* @returns The {@link SideEffects} object containing the handlers arrays.
|
|
1091
|
-
*/
|
|
1092
|
-
getSideEffects(permissions) {
|
|
1093
|
-
return Object.keys(permissions).reduce((sideEffectList, targetName) => {
|
|
1094
|
-
if (this.targetExists(targetName)) {
|
|
1095
|
-
const specification = this.getPermissionSpecification(targetName);
|
|
1096
|
-
if (specification.sideEffect) {
|
|
1097
|
-
sideEffectList.permittedHandlers[targetName] =
|
|
1098
|
-
specification.sideEffect.onPermitted;
|
|
1099
|
-
if (specification.sideEffect.onFailure) {
|
|
1100
|
-
sideEffectList.failureHandlers[targetName] =
|
|
1101
|
-
specification.sideEffect.onFailure;
|
|
1102
|
-
}
|
|
1103
|
-
}
|
|
1104
|
-
}
|
|
1105
|
-
return sideEffectList;
|
|
1106
|
-
}, { permittedHandlers: {}, failureHandlers: {} });
|
|
1107
|
-
}
|
|
1108
|
-
/**
|
|
1109
|
-
* Executes the side-effects of the approved permissions while handling the errors if any.
|
|
1110
|
-
* It will pass an instance of the {@link messenger} and the request data associated with the permission request to the handlers through its params.
|
|
1111
|
-
*
|
|
1112
|
-
* @param sideEffects - the side-effect record created by {@link getSideEffects}
|
|
1113
|
-
* @param requestData - the permissions requestData.
|
|
1114
|
-
* @returns the value returned by all the `onPermitted` handlers in an array.
|
|
1115
|
-
*/
|
|
1116
|
-
async executeSideEffects(sideEffects, requestData) {
|
|
1117
|
-
const { permittedHandlers, failureHandlers } = sideEffects;
|
|
1118
|
-
const params = {
|
|
1119
|
-
requestData,
|
|
1120
|
-
messenger: this.messenger,
|
|
1121
|
-
};
|
|
1122
|
-
const promiseResults = await Promise.allSettled(Object.values(permittedHandlers).map((permittedHandler) => permittedHandler(params)));
|
|
1123
|
-
// lib.es2020.promise.d.ts does not export its types so we're using a simple type.
|
|
1124
|
-
const rejectedHandlers = promiseResults.filter((promise) => promise.status === 'rejected');
|
|
1125
|
-
if (rejectedHandlers.length > 0) {
|
|
1126
|
-
const failureHandlersList = Object.values(failureHandlers);
|
|
1127
|
-
if (failureHandlersList.length > 0) {
|
|
1128
|
-
try {
|
|
1129
|
-
await Promise.all(failureHandlersList.map((failureHandler) => failureHandler(params)));
|
|
1130
|
-
}
|
|
1131
|
-
catch (error) {
|
|
1132
|
-
throw (0, errors_1.internalError)('Unexpected error in side-effects', { error });
|
|
1133
|
-
}
|
|
1134
|
-
}
|
|
1135
|
-
const reasons = rejectedHandlers.map((handler) => handler.reason);
|
|
1136
|
-
reasons.forEach((reason) => {
|
|
1137
|
-
console.error(reason);
|
|
1138
|
-
});
|
|
1139
|
-
throw reasons.length > 1
|
|
1140
|
-
? (0, errors_1.internalError)('Multiple errors occurred during side-effects execution', { errors: reasons })
|
|
1141
|
-
: reasons[0];
|
|
1142
|
-
}
|
|
1143
|
-
// lib.es2020.promise.d.ts does not export its types so we're using a simple type.
|
|
1144
|
-
return promiseResults.map(({ value }) => value);
|
|
1145
|
-
}
|
|
1146
|
-
/**
|
|
1147
|
-
* Validates an approved {@link PermissionsRequest} object. The approved
|
|
1148
|
-
* request must have the required `metadata` and `permissions` properties,
|
|
1149
|
-
* the `id` and `origin` of the `metadata` must match the original request
|
|
1150
|
-
* metadata, and the requested permissions must be valid per
|
|
1151
|
-
* {@link PermissionController.validateRequestedPermissions}. Any extra
|
|
1152
|
-
* metadata properties are ignored.
|
|
1153
|
-
*
|
|
1154
|
-
* An error is thrown if validation fails.
|
|
1155
|
-
*
|
|
1156
|
-
* @param approvedRequest - The approved permissions request object.
|
|
1157
|
-
* @param originalMetadata - The original request metadata.
|
|
1158
|
-
*/
|
|
1159
|
-
validateApprovedPermissions(approvedRequest, originalMetadata) {
|
|
1160
|
-
const { id, origin } = originalMetadata;
|
|
1161
|
-
if (!(0, controller_utils_1.isPlainObject)(approvedRequest) ||
|
|
1162
|
-
!(0, controller_utils_1.isPlainObject)(approvedRequest.metadata)) {
|
|
1163
|
-
throw (0, errors_1.internalError)(`Approved permissions request for subject "${origin}" is invalid.`, { data: { approvedRequest } });
|
|
1164
|
-
}
|
|
1165
|
-
const { metadata: { id: newId, origin: newOrigin }, permissions, } = approvedRequest;
|
|
1166
|
-
if (newId !== id) {
|
|
1167
|
-
throw (0, errors_1.internalError)(`Approved permissions request for subject "${origin}" mutated its id.`, { originalId: id, mutatedId: newId });
|
|
1168
|
-
}
|
|
1169
|
-
if (newOrigin !== origin) {
|
|
1170
|
-
throw (0, errors_1.internalError)(`Approved permissions request for subject "${origin}" mutated its origin.`, { originalOrigin: origin, mutatedOrigin: newOrigin });
|
|
1171
|
-
}
|
|
1172
|
-
try {
|
|
1173
|
-
this.validateRequestedPermissions(origin, permissions);
|
|
1174
|
-
}
|
|
1175
|
-
catch (error) {
|
|
1176
|
-
if (error instanceof Error) {
|
|
1177
|
-
// Re-throw as an internal error; we should never receive invalid approved
|
|
1178
|
-
// permissions.
|
|
1179
|
-
throw (0, errors_1.internalError)(`Invalid approved permissions request: ${error.message}`, error instanceof rpc_errors_1.JsonRpcError ? error.data : undefined);
|
|
1180
|
-
}
|
|
1181
|
-
/* istanbul ignore next: This should be impossible */
|
|
1182
|
-
throw (0, errors_1.internalError)('Unrecognized error type', { error });
|
|
1183
|
-
}
|
|
1184
|
-
}
|
|
1185
643
|
/**
|
|
1186
644
|
* Accepts a permissions request created by
|
|
1187
645
|
* {@link PermissionController.requestPermissions}.
|
|
@@ -1190,11 +648,11 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1190
648
|
*/
|
|
1191
649
|
async acceptPermissionsRequest(request) {
|
|
1192
650
|
const { id } = request.metadata;
|
|
1193
|
-
if (!this.
|
|
651
|
+
if (!__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_hasApprovalRequest).call(this, { id })) {
|
|
1194
652
|
throw new errors_1.PermissionsRequestNotFoundError(id);
|
|
1195
653
|
}
|
|
1196
654
|
if (Object.keys(request.permissions).length === 0) {
|
|
1197
|
-
this.
|
|
655
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_rejectPermissionsRequest).call(this, id, (0, errors_1.invalidParams)({
|
|
1198
656
|
message: 'Must request at least one permission.',
|
|
1199
657
|
}));
|
|
1200
658
|
return;
|
|
@@ -1205,7 +663,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1205
663
|
catch (error) {
|
|
1206
664
|
// If accepting unexpectedly fails, reject the request and re-throw the
|
|
1207
665
|
// error
|
|
1208
|
-
this.
|
|
666
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_rejectPermissionsRequest).call(this, id, error);
|
|
1209
667
|
throw error;
|
|
1210
668
|
}
|
|
1211
669
|
}
|
|
@@ -1216,37 +674,10 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1216
674
|
* @param id - The id of the request to be rejected.
|
|
1217
675
|
*/
|
|
1218
676
|
async rejectPermissionsRequest(id) {
|
|
1219
|
-
if (!this.
|
|
677
|
+
if (!__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_hasApprovalRequest).call(this, { id })) {
|
|
1220
678
|
throw new errors_1.PermissionsRequestNotFoundError(id);
|
|
1221
679
|
}
|
|
1222
|
-
this.
|
|
1223
|
-
}
|
|
1224
|
-
/**
|
|
1225
|
-
* Checks whether the {@link ApprovalController} has a particular permissions
|
|
1226
|
-
* request.
|
|
1227
|
-
*
|
|
1228
|
-
* @see {@link PermissionController.acceptPermissionsRequest} and
|
|
1229
|
-
* {@link PermissionController.rejectPermissionsRequest} for usage.
|
|
1230
|
-
* @param options - The {@link HasApprovalRequest} options.
|
|
1231
|
-
* @param options.id - The id of the approval request to check for.
|
|
1232
|
-
* @returns Whether the specified request exists.
|
|
1233
|
-
*/
|
|
1234
|
-
hasApprovalRequest(options) {
|
|
1235
|
-
return this.messenger.call('ApprovalController:hasRequest', options);
|
|
1236
|
-
}
|
|
1237
|
-
/**
|
|
1238
|
-
* Rejects the permissions request with the specified id, with the specified
|
|
1239
|
-
* error as the reason. This method is effectively a wrapper around a
|
|
1240
|
-
* messenger call for the `ApprovalController:rejectRequest` action.
|
|
1241
|
-
*
|
|
1242
|
-
* @see {@link PermissionController.acceptPermissionsRequest} and
|
|
1243
|
-
* {@link PermissionController.rejectPermissionsRequest} for usage.
|
|
1244
|
-
* @param id - The id of the request to reject.
|
|
1245
|
-
* @param error - The error associated with the rejection.
|
|
1246
|
-
* @returns Nothing
|
|
1247
|
-
*/
|
|
1248
|
-
_rejectPermissionsRequest(id, error) {
|
|
1249
|
-
return this.messenger.call('ApprovalController:rejectRequest', id, error);
|
|
680
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_rejectPermissionsRequest).call(this, id, (0, errors_1.userRejectedRequest)());
|
|
1250
681
|
}
|
|
1251
682
|
/**
|
|
1252
683
|
* Gets the subject's endowments per the specified endowment permission.
|
|
@@ -1264,7 +695,7 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1264
695
|
if (!this.hasPermission(origin, targetName)) {
|
|
1265
696
|
throw (0, errors_1.unauthorized)({ data: { origin, targetName } });
|
|
1266
697
|
}
|
|
1267
|
-
return this.
|
|
698
|
+
return __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getTypedPermissionSpecification).call(this, Permission_1.PermissionType.Endowment, targetName, origin).endowmentGetter({ origin, requestData });
|
|
1268
699
|
}
|
|
1269
700
|
/**
|
|
1270
701
|
* Executes a restricted method as the subject with the given origin.
|
|
@@ -1294,46 +725,164 @@ class PermissionController extends base_controller_1.BaseController {
|
|
|
1294
725
|
async executeRestrictedMethod(origin, targetName, params) {
|
|
1295
726
|
// Throws if the method does not exist
|
|
1296
727
|
const methodImplementation = this.getRestrictedMethod(targetName, origin);
|
|
1297
|
-
const result = await this.
|
|
728
|
+
const result = await __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_executeRestrictedMethod).call(this, methodImplementation, { origin }, targetName, params);
|
|
1298
729
|
if (result === undefined) {
|
|
1299
730
|
throw new Error(`Internal request for method "${targetName}" as origin "${origin}" returned no result.`);
|
|
1300
731
|
}
|
|
1301
732
|
return result;
|
|
1302
733
|
}
|
|
1303
|
-
/**
|
|
1304
|
-
* An internal method used in the controller's `json-rpc-engine` middleware
|
|
1305
|
-
* and {@link PermissionController.executeRestrictedMethod}. Calls the
|
|
1306
|
-
* specified restricted method implementation after decorating it with the
|
|
1307
|
-
* caveats of its permission. Throws if the subject does not have the
|
|
1308
|
-
* requisite permission.
|
|
1309
|
-
*
|
|
1310
|
-
* ATTN: Parameter validation is the responsibility of the caller, or
|
|
1311
|
-
* the restricted method implementation in the case of `params`.
|
|
1312
|
-
*
|
|
1313
|
-
* @see {@link PermissionController.executeRestrictedMethod} and
|
|
1314
|
-
* {@link PermissionController.createPermissionMiddleware} for usage.
|
|
1315
|
-
* @param methodImplementation - The implementation of the method to call.
|
|
1316
|
-
* @param subject - Metadata about the subject that made the request.
|
|
1317
|
-
* @param method - The method name
|
|
1318
|
-
* @param params - Params needed for executing the restricted method
|
|
1319
|
-
* @returns The result of the restricted method implementation
|
|
1320
|
-
*/
|
|
1321
|
-
_executeRestrictedMethod(methodImplementation, subject, method, params = []) {
|
|
1322
|
-
const { origin } = subject;
|
|
1323
|
-
const permission = this.getPermission(origin, method);
|
|
1324
|
-
if (!permission) {
|
|
1325
|
-
throw (0, errors_1.unauthorized)({ data: { origin, method } });
|
|
1326
|
-
}
|
|
1327
|
-
return (0, Caveat_1.decorateWithCaveats)(methodImplementation, permission, this._caveatSpecifications)({ method, params, context: { origin } });
|
|
1328
|
-
}
|
|
1329
734
|
}
|
|
1330
735
|
exports.PermissionController = PermissionController;
|
|
1331
|
-
_PermissionController_instances = new WeakSet(),
|
|
1332
|
-
|
|
736
|
+
_PermissionController_caveatSpecifications = new WeakMap(), _PermissionController_permissionSpecifications = new WeakMap(), _PermissionController_unrestrictedMethods = new WeakMap(), _PermissionController_instances = new WeakSet(), _PermissionController_getPermissionSpecification = function _PermissionController_getPermissionSpecification(targetName) {
|
|
737
|
+
return __classPrivateFieldGet(this, _PermissionController_permissionSpecifications, "f")[targetName];
|
|
738
|
+
}, _PermissionController_getCaveatSpecification = function _PermissionController_getCaveatSpecification(caveatType) {
|
|
739
|
+
return __classPrivateFieldGet(this, _PermissionController_caveatSpecifications, "f")[caveatType];
|
|
740
|
+
}, _PermissionController_expectGetCaveatMerger = function _PermissionController_expectGetCaveatMerger(caveatType) {
|
|
741
|
+
const { merger } = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getCaveatSpecification).call(this, caveatType);
|
|
1333
742
|
if (merger === undefined) {
|
|
1334
743
|
throw new errors_1.CaveatMergerDoesNotExistError(caveatType);
|
|
1335
744
|
}
|
|
1336
745
|
return merger;
|
|
746
|
+
}, _PermissionController_validatePermissionSpecifications = function _PermissionController_validatePermissionSpecifications(permissionSpecifications, caveatSpecifications) {
|
|
747
|
+
Object.entries(permissionSpecifications).forEach(([targetName, { permissionType, targetName: innerTargetName, allowedCaveats },]) => {
|
|
748
|
+
if (!permissionType || !(0, utils_1.hasProperty)(Permission_1.PermissionType, permissionType)) {
|
|
749
|
+
throw new Error(`Invalid permission type: "${permissionType}"`);
|
|
750
|
+
}
|
|
751
|
+
if (!targetName) {
|
|
752
|
+
throw new Error(`Invalid permission target name: "${targetName}"`);
|
|
753
|
+
}
|
|
754
|
+
if (targetName !== innerTargetName) {
|
|
755
|
+
throw new Error(`Invalid permission specification: target name "${targetName}" must match specification.targetName value "${innerTargetName}".`);
|
|
756
|
+
}
|
|
757
|
+
if (allowedCaveats) {
|
|
758
|
+
allowedCaveats.forEach((caveatType) => {
|
|
759
|
+
if (!(0, utils_1.hasProperty)(caveatSpecifications, caveatType)) {
|
|
760
|
+
throw new errors_1.UnrecognizedCaveatTypeError(caveatType);
|
|
761
|
+
}
|
|
762
|
+
const specification = caveatSpecifications[caveatType];
|
|
763
|
+
const isRestrictedMethodCaveat = (0, Caveat_1.isRestrictedMethodCaveatSpecification)(specification);
|
|
764
|
+
if ((permissionType === Permission_1.PermissionType.RestrictedMethod &&
|
|
765
|
+
!isRestrictedMethodCaveat) ||
|
|
766
|
+
(permissionType === Permission_1.PermissionType.Endowment &&
|
|
767
|
+
isRestrictedMethodCaveat)) {
|
|
768
|
+
throw new errors_1.CaveatSpecificationMismatchError(specification, permissionType);
|
|
769
|
+
}
|
|
770
|
+
});
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
}, _PermissionController_registerMessageHandlers = function _PermissionController_registerMessageHandlers() {
|
|
774
|
+
this.messenger.registerActionHandler(`${controllerName}:clearPermissions`, () => this.clearState());
|
|
775
|
+
this.messenger.registerActionHandler(`${controllerName}:getEndowments`, (origin, targetName, requestData) => this.getEndowments(origin, targetName, requestData));
|
|
776
|
+
this.messenger.registerActionHandler(`${controllerName}:getSubjectNames`, () => this.getSubjectNames());
|
|
777
|
+
this.messenger.registerActionHandler(`${controllerName}:getPermissions`, (origin) => this.getPermissions(origin));
|
|
778
|
+
this.messenger.registerActionHandler(`${controllerName}:hasPermission`, (origin, targetName) => this.hasPermission(origin, targetName));
|
|
779
|
+
this.messenger.registerActionHandler(`${controllerName}:hasPermissions`, (origin) => this.hasPermissions(origin));
|
|
780
|
+
this.messenger.registerActionHandler(`${controllerName}:grantPermissions`, this.grantPermissions.bind(this));
|
|
781
|
+
this.messenger.registerActionHandler(`${controllerName}:grantPermissionsIncremental`, this.grantPermissionsIncremental.bind(this));
|
|
782
|
+
this.messenger.registerActionHandler(`${controllerName}:requestPermissions`, (subject, permissions) => this.requestPermissions(subject, permissions));
|
|
783
|
+
this.messenger.registerActionHandler(`${controllerName}:requestPermissionsIncremental`, (subject, permissions) => this.requestPermissionsIncremental(subject, permissions));
|
|
784
|
+
this.messenger.registerActionHandler(`${controllerName}:revokeAllPermissions`, (origin) => this.revokeAllPermissions(origin));
|
|
785
|
+
this.messenger.registerActionHandler(`${controllerName}:revokePermissionForAllSubjects`, (target) => this.revokePermissionForAllSubjects(target));
|
|
786
|
+
this.messenger.registerActionHandler(`${controllerName}:revokePermissions`, this.revokePermissions.bind(this));
|
|
787
|
+
this.messenger.registerActionHandler(`${controllerName}:updateCaveat`, (origin, target, caveatType, caveatValue) => {
|
|
788
|
+
this.updateCaveat(origin, target, caveatType, caveatValue);
|
|
789
|
+
});
|
|
790
|
+
this.messenger.registerActionHandler(`${controllerName}:getCaveat`, (origin, target, caveatType) => this.getCaveat(origin, target, caveatType));
|
|
791
|
+
}, _PermissionController_getTypedPermissionSpecification = function _PermissionController_getTypedPermissionSpecification(permissionType, targetName, requestingOrigin) {
|
|
792
|
+
const failureError = permissionType === Permission_1.PermissionType.RestrictedMethod
|
|
793
|
+
? (0, errors_1.methodNotFound)(targetName, requestingOrigin ? { origin: requestingOrigin } : undefined)
|
|
794
|
+
: new errors_1.EndowmentPermissionDoesNotExistError(targetName, requestingOrigin);
|
|
795
|
+
if (!__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_targetExists).call(this, targetName)) {
|
|
796
|
+
throw failureError;
|
|
797
|
+
}
|
|
798
|
+
const specification = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getPermissionSpecification).call(this, targetName);
|
|
799
|
+
if (!(0, Permission_1.hasSpecificationType)(specification, permissionType)) {
|
|
800
|
+
throw failureError;
|
|
801
|
+
}
|
|
802
|
+
return specification;
|
|
803
|
+
}, _PermissionController_deletePermission = function _PermissionController_deletePermission(subjects, origin, target) {
|
|
804
|
+
const { permissions } = subjects[origin];
|
|
805
|
+
if (Object.keys(permissions).length > 1) {
|
|
806
|
+
delete permissions[target];
|
|
807
|
+
}
|
|
808
|
+
else {
|
|
809
|
+
delete subjects[origin];
|
|
810
|
+
}
|
|
811
|
+
}, _PermissionController_setCaveat = function _PermissionController_setCaveat(origin, target, caveatType, caveatValue) {
|
|
812
|
+
this.update((draftState) => {
|
|
813
|
+
const subject = draftState.subjects[origin];
|
|
814
|
+
// Unreachable because `hasCaveat` is always called before this, and it
|
|
815
|
+
// throws if permissions are missing. TypeScript needs this, however.
|
|
816
|
+
/* istanbul ignore if */
|
|
817
|
+
if (!subject) {
|
|
818
|
+
throw new errors_1.UnrecognizedSubjectError(origin);
|
|
819
|
+
}
|
|
820
|
+
const permission = subject.permissions[target];
|
|
821
|
+
/* istanbul ignore if: practically impossible, but TypeScript wants it */
|
|
822
|
+
if (!permission) {
|
|
823
|
+
throw new errors_1.PermissionDoesNotExistError(origin, target);
|
|
824
|
+
}
|
|
825
|
+
const caveat = {
|
|
826
|
+
type: caveatType,
|
|
827
|
+
value: caveatValue,
|
|
828
|
+
};
|
|
829
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateCaveat).call(this, caveat, origin, target);
|
|
830
|
+
let addedCaveat = false;
|
|
831
|
+
if (permission.caveats) {
|
|
832
|
+
const caveatIndex = permission.caveats.findIndex((existingCaveat) => existingCaveat.type === caveat.type);
|
|
833
|
+
if (caveatIndex === -1) {
|
|
834
|
+
permission.caveats.push(caveat);
|
|
835
|
+
addedCaveat = true;
|
|
836
|
+
}
|
|
837
|
+
else {
|
|
838
|
+
permission.caveats.splice(caveatIndex, 1, caveat);
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
else {
|
|
842
|
+
// At this point, we don't know if the specific permission is allowed
|
|
843
|
+
// to have caveats, but it should be impossible to call this method
|
|
844
|
+
// for a permission that may not have any caveats. If all else fails,
|
|
845
|
+
// the permission validator is also called.
|
|
846
|
+
// @ts-expect-error See above comment
|
|
847
|
+
permission.caveats = [caveat];
|
|
848
|
+
addedCaveat = true;
|
|
849
|
+
}
|
|
850
|
+
// Mutating a caveat does not warrant permission validation, but mutating
|
|
851
|
+
// the caveat array does.
|
|
852
|
+
if (addedCaveat) {
|
|
853
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateModifiedPermission).call(this, permission, origin, {
|
|
854
|
+
invokePermissionValidator: true,
|
|
855
|
+
performCaveatValidation: false, // We just validated the caveat
|
|
856
|
+
});
|
|
857
|
+
}
|
|
858
|
+
});
|
|
859
|
+
}, _PermissionController_deleteCaveat = function _PermissionController_deleteCaveat(permission, caveatType, origin) {
|
|
860
|
+
/* istanbul ignore if: not possible in our usage */
|
|
861
|
+
if (!permission.caveats) {
|
|
862
|
+
throw new errors_1.CaveatDoesNotExistError(origin, permission.parentCapability, caveatType);
|
|
863
|
+
}
|
|
864
|
+
const caveatIndex = permission.caveats.findIndex((existingCaveat) => existingCaveat.type === caveatType);
|
|
865
|
+
if (caveatIndex === -1) {
|
|
866
|
+
throw new errors_1.CaveatDoesNotExistError(origin, permission.parentCapability, caveatType);
|
|
867
|
+
}
|
|
868
|
+
if (permission.caveats.length === 1) {
|
|
869
|
+
permission.caveats = null;
|
|
870
|
+
}
|
|
871
|
+
else {
|
|
872
|
+
permission.caveats.splice(caveatIndex, 1);
|
|
873
|
+
}
|
|
874
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateModifiedPermission).call(this, permission, origin, {
|
|
875
|
+
invokePermissionValidator: true,
|
|
876
|
+
performCaveatValidation: false, // No caveat object was mutated
|
|
877
|
+
});
|
|
878
|
+
}, _PermissionController_validateModifiedPermission = function _PermissionController_validateModifiedPermission(permission, origin, validationFlags) {
|
|
879
|
+
/* istanbul ignore if: this should be impossible */
|
|
880
|
+
if (!__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_targetExists).call(this, permission.parentCapability)) {
|
|
881
|
+
throw new Error(`Fatal: Existing permission target "${permission.parentCapability}" has no specification.`);
|
|
882
|
+
}
|
|
883
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validatePermission).call(this, __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getPermissionSpecification).call(this, permission.parentCapability), permission, origin, validationFlags);
|
|
884
|
+
}, _PermissionController_targetExists = function _PermissionController_targetExists(target) {
|
|
885
|
+
return (0, utils_1.hasProperty)(__classPrivateFieldGet(this, _PermissionController_permissionSpecifications, "f"), target);
|
|
1337
886
|
}, _PermissionController_applyGrantedPermissions = function _PermissionController_applyGrantedPermissions({ approvedPermissions, subject, mergePermissions, preserveExistingPermissions, requestData, }) {
|
|
1338
887
|
const { origin } = subject;
|
|
1339
888
|
if (!origin || typeof origin !== 'string') {
|
|
@@ -1345,7 +894,7 @@ _PermissionController_instances = new WeakSet(), _PermissionController_expectGet
|
|
|
1345
894
|
}
|
|
1346
895
|
: {});
|
|
1347
896
|
for (const [requestedTarget, approvedPermission] of Object.entries(approvedPermissions)) {
|
|
1348
|
-
if (!this.
|
|
897
|
+
if (!__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_targetExists).call(this, requestedTarget)) {
|
|
1349
898
|
throw (0, errors_1.methodNotFound)(requestedTarget);
|
|
1350
899
|
}
|
|
1351
900
|
if (approvedPermission.parentCapability !== undefined &&
|
|
@@ -1355,9 +904,9 @@ _PermissionController_instances = new WeakSet(), _PermissionController_expectGet
|
|
|
1355
904
|
// We have verified that the target exists, and reassign it to change its
|
|
1356
905
|
// type.
|
|
1357
906
|
const targetName = requestedTarget;
|
|
1358
|
-
const specification = this.
|
|
907
|
+
const specification = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getPermissionSpecification).call(this, targetName);
|
|
1359
908
|
// The requested caveats are validated here.
|
|
1360
|
-
const caveats = this.
|
|
909
|
+
const caveats = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_constructCaveats).call(this, origin, targetName, approvedPermission.caveats);
|
|
1361
910
|
const permissionOptions = {
|
|
1362
911
|
caveats,
|
|
1363
912
|
invoker: origin,
|
|
@@ -1373,14 +922,120 @@ _PermissionController_instances = new WeakSet(), _PermissionController_expectGet
|
|
|
1373
922
|
if (mergePermissions) {
|
|
1374
923
|
permission = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_mergePermission).call(this, permissions[targetName], permission)[0];
|
|
1375
924
|
}
|
|
1376
|
-
this.
|
|
925
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validatePermission).call(this, specification, permission, origin, {
|
|
1377
926
|
invokePermissionValidator: true,
|
|
1378
927
|
performCaveatValidation: true,
|
|
1379
928
|
});
|
|
1380
929
|
permissions[targetName] = permission;
|
|
1381
930
|
}
|
|
1382
|
-
this.
|
|
931
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_setValidatedPermissions).call(this, origin, permissions);
|
|
1383
932
|
return permissions;
|
|
933
|
+
}, _PermissionController_validatePermission = function _PermissionController_validatePermission(specification, permission, origin, { invokePermissionValidator, performCaveatValidation, }) {
|
|
934
|
+
const { allowedCaveats, validator, targetName } = specification;
|
|
935
|
+
if (specification.subjectTypes?.length &&
|
|
936
|
+
specification.subjectTypes.length > 0) {
|
|
937
|
+
const metadata = this.messenger.call('SubjectMetadataController:getSubjectMetadata', origin);
|
|
938
|
+
if (!metadata ||
|
|
939
|
+
metadata.subjectType === null ||
|
|
940
|
+
!specification.subjectTypes.includes(metadata.subjectType)) {
|
|
941
|
+
throw specification.permissionType === Permission_1.PermissionType.RestrictedMethod
|
|
942
|
+
? (0, errors_1.methodNotFound)(targetName, { origin })
|
|
943
|
+
: new errors_1.EndowmentPermissionDoesNotExistError(targetName, origin);
|
|
944
|
+
}
|
|
945
|
+
}
|
|
946
|
+
if ((0, utils_1.hasProperty)(permission, 'caveats')) {
|
|
947
|
+
const { caveats } = permission;
|
|
948
|
+
if (caveats !== null && !(Array.isArray(caveats) && caveats.length > 0)) {
|
|
949
|
+
throw new errors_1.InvalidCaveatsPropertyError(origin, targetName, caveats);
|
|
950
|
+
}
|
|
951
|
+
const seenCaveatTypes = new Set();
|
|
952
|
+
caveats?.forEach((caveat) => {
|
|
953
|
+
if (performCaveatValidation) {
|
|
954
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateCaveat).call(this, caveat, origin, targetName);
|
|
955
|
+
}
|
|
956
|
+
if (!allowedCaveats?.includes(caveat.type)) {
|
|
957
|
+
throw new errors_1.ForbiddenCaveatError(caveat.type, origin, targetName);
|
|
958
|
+
}
|
|
959
|
+
if (seenCaveatTypes.has(caveat.type)) {
|
|
960
|
+
throw new errors_1.DuplicateCaveatError(caveat.type, origin, targetName);
|
|
961
|
+
}
|
|
962
|
+
seenCaveatTypes.add(caveat.type);
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
if (invokePermissionValidator && validator) {
|
|
966
|
+
validator(permission, origin, targetName);
|
|
967
|
+
}
|
|
968
|
+
}, _PermissionController_setValidatedPermissions = function _PermissionController_setValidatedPermissions(origin, permissions) {
|
|
969
|
+
this.update((draftState) => {
|
|
970
|
+
if (!draftState.subjects[origin]) {
|
|
971
|
+
draftState.subjects[origin] = { origin, permissions: {} };
|
|
972
|
+
}
|
|
973
|
+
draftState.subjects[origin].permissions = (0, immer_1.castDraft)(permissions);
|
|
974
|
+
});
|
|
975
|
+
}, _PermissionController_constructCaveats = function _PermissionController_constructCaveats(origin, target, requestedCaveats) {
|
|
976
|
+
const caveatArray = requestedCaveats?.map((requestedCaveat) => {
|
|
977
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateCaveat).call(this, requestedCaveat, origin, target);
|
|
978
|
+
// Reassign so that we have a fresh object.
|
|
979
|
+
const { type, value } = requestedCaveat;
|
|
980
|
+
return { type, value };
|
|
981
|
+
});
|
|
982
|
+
return caveatArray && (0, controller_utils_1.isNonEmptyArray)(caveatArray)
|
|
983
|
+
? caveatArray
|
|
984
|
+
: undefined;
|
|
985
|
+
}, _PermissionController_validateCaveat = function _PermissionController_validateCaveat(caveat, origin, target) {
|
|
986
|
+
if (!(0, controller_utils_1.isPlainObject)(caveat)) {
|
|
987
|
+
throw new errors_1.InvalidCaveatError(caveat, origin, target);
|
|
988
|
+
}
|
|
989
|
+
if (Object.keys(caveat).length !== 2) {
|
|
990
|
+
throw new errors_1.InvalidCaveatFieldsError(caveat, origin, target);
|
|
991
|
+
}
|
|
992
|
+
if (typeof caveat.type !== 'string') {
|
|
993
|
+
throw new errors_1.InvalidCaveatTypeError(caveat, origin, target);
|
|
994
|
+
}
|
|
995
|
+
const specification = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getCaveatSpecification).call(this, caveat.type);
|
|
996
|
+
if (!specification) {
|
|
997
|
+
throw new errors_1.UnrecognizedCaveatTypeError(caveat.type, origin, target);
|
|
998
|
+
}
|
|
999
|
+
if (!(0, utils_1.hasProperty)(caveat, 'value') || caveat.value === undefined) {
|
|
1000
|
+
throw new errors_1.CaveatMissingValueError(caveat, origin, target);
|
|
1001
|
+
}
|
|
1002
|
+
if (!(0, controller_utils_1.isValidJson)(caveat.value)) {
|
|
1003
|
+
throw new errors_1.CaveatInvalidJsonError(caveat, origin, target);
|
|
1004
|
+
}
|
|
1005
|
+
// Typecast: TypeScript still believes that the caveat is a PlainObject.
|
|
1006
|
+
specification.validator?.(caveat, origin, target);
|
|
1007
|
+
}, _PermissionController_validateRequestedPermissions = function _PermissionController_validateRequestedPermissions(origin, requestedPermissions) {
|
|
1008
|
+
if (!(0, controller_utils_1.isPlainObject)(requestedPermissions)) {
|
|
1009
|
+
throw (0, errors_1.invalidParams)({
|
|
1010
|
+
message: `Requested permissions for origin "${origin}" is not a plain object.`,
|
|
1011
|
+
data: { origin, requestedPermissions },
|
|
1012
|
+
});
|
|
1013
|
+
}
|
|
1014
|
+
if (Object.keys(requestedPermissions).length === 0) {
|
|
1015
|
+
throw (0, errors_1.invalidParams)({
|
|
1016
|
+
message: `Permissions request for origin "${origin}" contains no permissions.`,
|
|
1017
|
+
data: { requestedPermissions },
|
|
1018
|
+
});
|
|
1019
|
+
}
|
|
1020
|
+
for (const targetName of Object.keys(requestedPermissions)) {
|
|
1021
|
+
const permission = requestedPermissions[targetName];
|
|
1022
|
+
if (!__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_targetExists).call(this, targetName)) {
|
|
1023
|
+
throw (0, errors_1.methodNotFound)(targetName, { origin, requestedPermissions });
|
|
1024
|
+
}
|
|
1025
|
+
if (!(0, controller_utils_1.isPlainObject)(permission) ||
|
|
1026
|
+
(permission.parentCapability !== undefined &&
|
|
1027
|
+
targetName !== permission.parentCapability)) {
|
|
1028
|
+
throw (0, errors_1.invalidParams)({
|
|
1029
|
+
message: `Permissions request for origin "${origin}" contains invalid requested permission(s).`,
|
|
1030
|
+
data: { origin, requestedPermissions },
|
|
1031
|
+
});
|
|
1032
|
+
}
|
|
1033
|
+
// Here we validate the permission without invoking its validator, if any.
|
|
1034
|
+
// The validator will be invoked after the permission has been approved.
|
|
1035
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validatePermission).call(this, __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getPermissionSpecification).call(this, targetName),
|
|
1036
|
+
// Typecast: The permission is still a "PlainObject" here.
|
|
1037
|
+
permission, origin, { invokePermissionValidator: false, performCaveatValidation: true });
|
|
1038
|
+
}
|
|
1384
1039
|
}, _PermissionController_mergeIncrementalPermissions = function _PermissionController_mergeIncrementalPermissions(existingPermissions, incrementalRequestedPermissions) {
|
|
1385
1040
|
const permissionDiffMap = {};
|
|
1386
1041
|
// Use immer's produce as a convenience for calculating the new permissions
|
|
@@ -1458,6 +1113,25 @@ _PermissionController_instances = new WeakSet(), _PermissionController_expectGet
|
|
|
1458
1113
|
diff,
|
|
1459
1114
|
]
|
|
1460
1115
|
: [];
|
|
1116
|
+
}, _PermissionController_requestUserApproval =
|
|
1117
|
+
/**
|
|
1118
|
+
* Adds a request to the {@link ApprovalController} using the
|
|
1119
|
+
* {@link AddApprovalRequest} action. Also validates the resulting approved
|
|
1120
|
+
* permissions request, and throws an error if validation fails.
|
|
1121
|
+
*
|
|
1122
|
+
* @param permissionsRequest - The permissions request object.
|
|
1123
|
+
* @returns The approved permissions request object.
|
|
1124
|
+
*/
|
|
1125
|
+
async function _PermissionController_requestUserApproval(permissionsRequest) {
|
|
1126
|
+
const { origin, id } = permissionsRequest.metadata;
|
|
1127
|
+
const approvedRequest = await this.messenger.call('ApprovalController:addRequest', {
|
|
1128
|
+
id,
|
|
1129
|
+
origin,
|
|
1130
|
+
requestData: permissionsRequest,
|
|
1131
|
+
type: utils_2.MethodNames.RequestPermissions,
|
|
1132
|
+
}, true);
|
|
1133
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateApprovedPermissions).call(this, approvedRequest, { id, origin });
|
|
1134
|
+
return approvedRequest;
|
|
1461
1135
|
}, _PermissionController_handleApprovedPermissions =
|
|
1462
1136
|
/**
|
|
1463
1137
|
* Accepts a permissions request that has been approved by the user. This
|
|
@@ -1475,9 +1149,9 @@ _PermissionController_instances = new WeakSet(), _PermissionController_expectGet
|
|
|
1475
1149
|
async function _PermissionController_handleApprovedPermissions({ subject, metadata, preserveExistingPermissions, approvedRequest, }) {
|
|
1476
1150
|
const { permissions: approvedPermissions, ...requestData } = approvedRequest;
|
|
1477
1151
|
const approvedMetadata = { ...metadata };
|
|
1478
|
-
const sideEffects = this.
|
|
1152
|
+
const sideEffects = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getSideEffects).call(this, approvedPermissions);
|
|
1479
1153
|
if (Object.values(sideEffects.permittedHandlers).length > 0) {
|
|
1480
|
-
const sideEffectsData = await this.
|
|
1154
|
+
const sideEffectsData = await __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_executeSideEffects).call(this, sideEffects, approvedRequest);
|
|
1481
1155
|
approvedMetadata.data = Object.keys(sideEffects.permittedHandlers).reduce((acc, permission, i) => ({ [permission]: sideEffectsData[i], ...acc }), {});
|
|
1482
1156
|
}
|
|
1483
1157
|
return [
|
|
@@ -1489,5 +1163,94 @@ async function _PermissionController_handleApprovedPermissions({ subject, metada
|
|
|
1489
1163
|
}),
|
|
1490
1164
|
approvedMetadata,
|
|
1491
1165
|
];
|
|
1166
|
+
}, _PermissionController_getSideEffects = function _PermissionController_getSideEffects(permissions) {
|
|
1167
|
+
return Object.keys(permissions).reduce((sideEffectList, targetName) => {
|
|
1168
|
+
if (__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_targetExists).call(this, targetName)) {
|
|
1169
|
+
const specification = __classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_getPermissionSpecification).call(this, targetName);
|
|
1170
|
+
if (specification.sideEffect) {
|
|
1171
|
+
sideEffectList.permittedHandlers[targetName] =
|
|
1172
|
+
specification.sideEffect.onPermitted;
|
|
1173
|
+
if (specification.sideEffect.onFailure) {
|
|
1174
|
+
sideEffectList.failureHandlers[targetName] =
|
|
1175
|
+
specification.sideEffect.onFailure;
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1179
|
+
return sideEffectList;
|
|
1180
|
+
}, { permittedHandlers: {}, failureHandlers: {} });
|
|
1181
|
+
}, _PermissionController_executeSideEffects =
|
|
1182
|
+
/**
|
|
1183
|
+
* Executes the side-effects of the approved permissions while handling the errors if any.
|
|
1184
|
+
* It will pass an instance of the {@link messenger} and the request data associated with the permission request to the handlers through its params.
|
|
1185
|
+
*
|
|
1186
|
+
* @param sideEffects - the side-effect record created by {@link #getSideEffects}
|
|
1187
|
+
* @param requestData - the permissions requestData.
|
|
1188
|
+
* @returns the value returned by all the `onPermitted` handlers in an array.
|
|
1189
|
+
*/
|
|
1190
|
+
async function _PermissionController_executeSideEffects(sideEffects, requestData) {
|
|
1191
|
+
const { permittedHandlers, failureHandlers } = sideEffects;
|
|
1192
|
+
const params = {
|
|
1193
|
+
requestData,
|
|
1194
|
+
messenger: this.messenger,
|
|
1195
|
+
};
|
|
1196
|
+
const promiseResults = await Promise.allSettled(Object.values(permittedHandlers).map((permittedHandler) => permittedHandler(params)));
|
|
1197
|
+
// lib.es2020.promise.d.ts does not export its types so we're using a simple type.
|
|
1198
|
+
const rejectedHandlers = promiseResults.filter((promise) => promise.status === 'rejected');
|
|
1199
|
+
if (rejectedHandlers.length > 0) {
|
|
1200
|
+
const failureHandlersList = Object.values(failureHandlers);
|
|
1201
|
+
if (failureHandlersList.length > 0) {
|
|
1202
|
+
try {
|
|
1203
|
+
await Promise.all(failureHandlersList.map((failureHandler) => failureHandler(params)));
|
|
1204
|
+
}
|
|
1205
|
+
catch (error) {
|
|
1206
|
+
throw (0, errors_1.internalError)('Unexpected error in side-effects', { error });
|
|
1207
|
+
}
|
|
1208
|
+
}
|
|
1209
|
+
const reasons = rejectedHandlers.map((handler) => handler.reason);
|
|
1210
|
+
reasons.forEach((reason) => {
|
|
1211
|
+
console.error(reason);
|
|
1212
|
+
});
|
|
1213
|
+
throw reasons.length > 1
|
|
1214
|
+
? (0, errors_1.internalError)('Multiple errors occurred during side-effects execution', { errors: reasons })
|
|
1215
|
+
: reasons[0];
|
|
1216
|
+
}
|
|
1217
|
+
// lib.es2020.promise.d.ts does not export its types so we're using a simple type.
|
|
1218
|
+
return promiseResults.map(({ value }) => value);
|
|
1219
|
+
}, _PermissionController_validateApprovedPermissions = function _PermissionController_validateApprovedPermissions(approvedRequest, originalMetadata) {
|
|
1220
|
+
const { id, origin } = originalMetadata;
|
|
1221
|
+
if (!(0, controller_utils_1.isPlainObject)(approvedRequest) ||
|
|
1222
|
+
!(0, controller_utils_1.isPlainObject)(approvedRequest.metadata)) {
|
|
1223
|
+
throw (0, errors_1.internalError)(`Approved permissions request for subject "${origin}" is invalid.`, { data: { approvedRequest } });
|
|
1224
|
+
}
|
|
1225
|
+
const { metadata: { id: newId, origin: newOrigin }, permissions, } = approvedRequest;
|
|
1226
|
+
if (newId !== id) {
|
|
1227
|
+
throw (0, errors_1.internalError)(`Approved permissions request for subject "${origin}" mutated its id.`, { originalId: id, mutatedId: newId });
|
|
1228
|
+
}
|
|
1229
|
+
if (newOrigin !== origin) {
|
|
1230
|
+
throw (0, errors_1.internalError)(`Approved permissions request for subject "${origin}" mutated its origin.`, { originalOrigin: origin, mutatedOrigin: newOrigin });
|
|
1231
|
+
}
|
|
1232
|
+
try {
|
|
1233
|
+
__classPrivateFieldGet(this, _PermissionController_instances, "m", _PermissionController_validateRequestedPermissions).call(this, origin, permissions);
|
|
1234
|
+
}
|
|
1235
|
+
catch (error) {
|
|
1236
|
+
if (error instanceof Error) {
|
|
1237
|
+
// Re-throw as an internal error; we should never receive invalid approved
|
|
1238
|
+
// permissions.
|
|
1239
|
+
throw (0, errors_1.internalError)(`Invalid approved permissions request: ${error.message}`, error instanceof rpc_errors_1.JsonRpcError ? error.data : undefined);
|
|
1240
|
+
}
|
|
1241
|
+
/* istanbul ignore next: This should be impossible */
|
|
1242
|
+
throw (0, errors_1.internalError)('Unrecognized error type', { error });
|
|
1243
|
+
}
|
|
1244
|
+
}, _PermissionController_hasApprovalRequest = function _PermissionController_hasApprovalRequest(options) {
|
|
1245
|
+
return this.messenger.call('ApprovalController:hasRequest', options);
|
|
1246
|
+
}, _PermissionController_rejectPermissionsRequest = function _PermissionController_rejectPermissionsRequest(id, error) {
|
|
1247
|
+
return this.messenger.call('ApprovalController:rejectRequest', id, error);
|
|
1248
|
+
}, _PermissionController_executeRestrictedMethod = function _PermissionController_executeRestrictedMethod(methodImplementation, subject, method, params = []) {
|
|
1249
|
+
const { origin } = subject;
|
|
1250
|
+
const permission = this.getPermission(origin, method);
|
|
1251
|
+
if (!permission) {
|
|
1252
|
+
throw (0, errors_1.unauthorized)({ data: { origin, method } });
|
|
1253
|
+
}
|
|
1254
|
+
return (0, Caveat_1.decorateWithCaveats)(methodImplementation, permission, __classPrivateFieldGet(this, _PermissionController_caveatSpecifications, "f"))({ method, params, context: { origin } });
|
|
1492
1255
|
};
|
|
1493
1256
|
//# sourceMappingURL=PermissionController.cjs.map
|