refactor: restructure permission handling and enhance Guard functionality

- Introduced a new `createGuard` function to streamline the creation of Guard instances with permissions and roles.
- Updated tests in `authorize.spec.ts` to reflect changes in permission checks, ensuring they now return undefined for denied permissions.
- Added new `Permission` and `Policy` classes to improve type safety and flexibility in permission management.
- Refactored middleware and controller files to utilize the updated permission structure, including context handling for permissions.
- Created a new `SystemController.spec.ts` file to test the integration of the new permission system within the SystemController.
- Removed legacy permission handling from core security files, consolidating permission logic within the new structure.
This commit is contained in:
dswbx
2025-10-13 18:20:46 +02:00
parent b784e1c1c4
commit 2f88c2216c
26 changed files with 954 additions and 367 deletions

View File

@@ -5,7 +5,7 @@ import { entityTypes } from "data/entities/Entity";
import { isEqual } from "lodash-es";
import type { ModuleBuildContext, ModuleBuildContextMcpContext } from "./Module";
import type { EntityRelation } from "data/relations";
import type { Permission } from "core/security/Permission";
import type { Permission, PermissionContext } from "auth/authorize/Permission";
import { Exception } from "core/errors";
import { invariant, isPlainObject } from "bknd/utils";
@@ -114,10 +114,20 @@ export class ModuleHelper {
entity.__replaceField(name, newField);
}
async throwUnlessGranted(
permission: Permission,
async granted<P extends Permission<any, any, any, any>>(
c: { context: ModuleBuildContextMcpContext; raw?: unknown },
) {
permission: P,
context: PermissionContext<P>,
): Promise<void>;
async granted<P extends Permission<any, any, undefined, any>>(
c: { context: ModuleBuildContextMcpContext; raw?: unknown },
permission: P,
): Promise<void>;
async granted<P extends Permission<any, any, any, any>>(
c: { context: ModuleBuildContextMcpContext; raw?: unknown },
permission: P,
context?: PermissionContext<P>,
): Promise<void> {
invariant(c.context.app, "app is not available in mcp context");
const auth = c.context.app.module.auth;
if (!auth.enabled) return;
@@ -127,12 +137,6 @@ export class ModuleHelper {
}
const user = await auth.authenticator?.resolveAuthFromRequest(c.raw as any);
if (!this.ctx.guard.granted(permission, user)) {
throw new Exception(
`Permission "${typeof permission === "string" ? permission : permission.name}" not granted`,
403,
);
}
this.ctx.guard.granted(permission, { user }, context as any);
}
}