permissions: add support for adding permission rules separately from resource type
Signed-off-by: Patrik Oldsberg <poldsberg@gmail.com>
This commit is contained in:
+8
@@ -62,6 +62,14 @@ export const permissionIntegrationsServiceFactory = createServiceFactory({
|
||||
}
|
||||
router.addPermissions(permissions);
|
||||
},
|
||||
addPermissionRules(rules) {
|
||||
if (started) {
|
||||
throw new Error(
|
||||
'Cannot add permission rules after the plugin has started',
|
||||
);
|
||||
}
|
||||
router.addPermissionRules(rules);
|
||||
},
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
@@ -434,6 +434,7 @@ export interface LoggerService {
|
||||
|
||||
// @public
|
||||
export interface PermissionIntegrationsService {
|
||||
addPermissionRules(rules: PermissionRule<any, any, string>[]): void;
|
||||
addPermissions(permissions: Permission[]): void;
|
||||
addResourceType<const TResourceType extends string, TResource>(
|
||||
options: PermissionIntegrationsServiceAddResourceTypeOptions<
|
||||
|
||||
@@ -77,6 +77,21 @@ export interface PermissionIntegrationsService {
|
||||
*/
|
||||
addPermissions(permissions: Permission[]): void;
|
||||
|
||||
/**
|
||||
* Adds a set of permission rules to the permission system for a resource type
|
||||
* that is owned by this plugin.
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* Rules should be created using corresponding `create*PermissionRule`
|
||||
* functions exported by plugins, who in turn are created with
|
||||
* `makeCreatePermissionRule`.
|
||||
*
|
||||
* Rules can be added either directly by the plugin itself or through a plugin
|
||||
* module.
|
||||
*/
|
||||
addPermissionRules(rules: PermissionRule<any, any, string>[]): void;
|
||||
|
||||
/**
|
||||
* Add a new resource type that is owned by this plugin to the permission
|
||||
* system.
|
||||
|
||||
@@ -142,6 +142,7 @@ export function createPermissionIntegrationRouter<
|
||||
>,
|
||||
): express.Router & {
|
||||
addPermissions(permissions: Permission[]): void;
|
||||
addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;
|
||||
addResourceType<const TResourceType extends string, TResource>(
|
||||
resource: CreatePermissionIntegrationRouterResourceOptions<
|
||||
TResourceType,
|
||||
|
||||
@@ -1006,14 +1006,19 @@ describe('createPermissionIntegrationRouter', () => {
|
||||
resourceType: 'test-resource',
|
||||
permissions: [testPermission],
|
||||
getResources: defaultMockedGetResources1,
|
||||
rules: [testRule1, testRule2],
|
||||
rules: [testRule1],
|
||||
});
|
||||
|
||||
router.addPermissionRules([testRule2]);
|
||||
|
||||
// This one is for the resource added below, it should be possible to add rules before the resource typeof
|
||||
router.addPermissionRules([testRule3]);
|
||||
|
||||
router.addResourceType({
|
||||
resourceType: 'test-resource-2',
|
||||
permissions: [testPermission2],
|
||||
getResources: defaultMockedGetResources2,
|
||||
rules: [testRule3],
|
||||
rules: [],
|
||||
});
|
||||
|
||||
const responseAfter = await request(express().use(router)).get(
|
||||
|
||||
@@ -308,6 +308,28 @@ class PermissionIntegrationMetadataStore {
|
||||
}
|
||||
}
|
||||
|
||||
addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {
|
||||
for (const rule of rules) {
|
||||
const rulesByName =
|
||||
this.#rulesByTypeByName.get(rule.resourceType) ?? new Map();
|
||||
this.#rulesByTypeByName.set(rule.resourceType, rulesByName);
|
||||
|
||||
if (rulesByName.has(rule.name)) {
|
||||
throw new Error(
|
||||
`Refused to add permission rule for type '${rule.resourceType}' with name '${rule.name}' because it already exists`,
|
||||
);
|
||||
}
|
||||
rulesByName.set(rule.name, rule);
|
||||
|
||||
this.#serializedRules.push({
|
||||
name: rule.name,
|
||||
description: rule.description,
|
||||
resourceType: rule.resourceType,
|
||||
paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
addResourceType(
|
||||
resource: CreatePermissionIntegrationRouterResourceOptions<string, unknown>,
|
||||
) {
|
||||
@@ -320,24 +342,8 @@ class PermissionIntegrationMetadataStore {
|
||||
}
|
||||
this.#resourcesByType.set(resourceType, resource);
|
||||
|
||||
for (const rule of resource.rules) {
|
||||
const rulesByName =
|
||||
this.#rulesByTypeByName.get(resourceType) ?? new Map();
|
||||
this.#rulesByTypeByName.set(resourceType, rulesByName);
|
||||
|
||||
if (rulesByName.has(rule.name)) {
|
||||
throw new Error(
|
||||
`Refused to add permission rule for type '${resourceType}' with name '${rule.name}' because it already exists`,
|
||||
);
|
||||
}
|
||||
rulesByName.set(rule.name, rule);
|
||||
|
||||
this.#serializedRules.push({
|
||||
name: rule.name,
|
||||
description: rule.description,
|
||||
resourceType: rule.resourceType,
|
||||
paramsSchema: zodToJsonSchema(rule.paramsSchema ?? z.object({})),
|
||||
});
|
||||
if (resource.rules) {
|
||||
this.addPermissionRules(resource.rules);
|
||||
}
|
||||
|
||||
if (resource.permissions) {
|
||||
@@ -411,6 +417,7 @@ export function createPermissionIntegrationRouter<
|
||||
>,
|
||||
): express.Router & {
|
||||
addPermissions(permissions: Permission[]): void;
|
||||
addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]): void;
|
||||
addResourceType<const TResourceType extends string, TResource>(
|
||||
resource: CreatePermissionIntegrationRouterResourceOptions<
|
||||
TResourceType,
|
||||
@@ -495,6 +502,9 @@ export function createPermissionIntegrationRouter<
|
||||
addPermissions(permissions: Permission[]) {
|
||||
store.addPermissions(permissions);
|
||||
},
|
||||
addPermissionRules(rules: PermissionRule<unknown, unknown, string>[]) {
|
||||
store.addPermissionRules(rules);
|
||||
},
|
||||
addResourceType<const TResourceType extends string, TResource>(
|
||||
resource: CreatePermissionIntegrationRouterResourceOptions<
|
||||
TResourceType,
|
||||
|
||||
Reference in New Issue
Block a user