From ed74abf75cb7164bbc2677f4b966b09fbebd5aa1 Mon Sep 17 00:00:00 2001 From: Pl217 Date: Fri, 18 Jun 2021 13:24:48 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=82=20Introduce=20@Permission=20decora?= =?UTF-8?q?tor?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This decorator can accept permission conditions required to access the resource. For example: `@Permission({ type: 'plan', permission: 'editPlanData' })` Non-global permissions also take id argument of the query into account to check access permissions. --- src/common-libs/auth/permission-decorator.ts | 27 ++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 src/common-libs/auth/permission-decorator.ts diff --git a/src/common-libs/auth/permission-decorator.ts b/src/common-libs/auth/permission-decorator.ts new file mode 100644 index 00000000..6b27ecb7 --- /dev/null +++ b/src/common-libs/auth/permission-decorator.ts @@ -0,0 +1,27 @@ +import { actionIsPermitted } from '@unocha/hpc-api-core/src/auth'; +import { RequiredPermissionsCondition } from '@unocha/hpc-api-core/src/auth/permissions'; +import { Context } from '@unocha/hpc-api-core/src/lib/context'; +import { ForbiddenError } from '@unocha/hpc-api-core/src/util/error'; +import { createMethodDecorator, ResolverData } from 'type-graphql'; + +type RequiredPermissions = ( + resolverData: ResolverData +) => Promise>; + +// eslint-disable-next-line @typescript-eslint/naming-convention +export function Permission( + requiredPermissions: RequiredPermissions +): MethodDecorator { + return createMethodDecorator( + async (resolverData: ResolverData, next) => { + const permissions = await requiredPermissions(resolverData); + const { context } = resolverData; + + if (!(await actionIsPermitted(permissions, context))) { + throw new ForbiddenError('No permission to perform this action'); + } + + return next(); + } + ); +}