From 6ac6e1b9e42ff19a79d6c2c3bc40e3b05cc4d84b Mon Sep 17 00:00:00 2001 From: Beau Collins Date: Fri, 20 Aug 2021 10:50:11 -0700 Subject: [PATCH] feat(authorization): support readonly arrays for roles (#935) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: MichaƂ Lytek --- CHANGELOG.md | 1 + src/decorators/Authorized.ts | 8 +++++--- src/helpers/decorators.ts | 2 +- tests/functional/authorization.ts | 32 +++++++++++++++++++++++++++++-- 4 files changed, 37 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a2aaae2aa..214fc0c98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,7 @@ - allow defining directives for interface types and theirs fields, with inheritance for object types fields (#744) - allow deprecating input fields and args (#794) - support disabling inferring default values (#793) +- support readonly arrays for roles of `@Authorized` decorator (#935) ### Fixes - **Breaking Change**: properly emit types nullability when `defaultValue` is provided and remove `ConflictingDefaultWithNullableError` error (#751) - allow defining extension on field resolver level for fields also defined as a property of the class (#776) diff --git a/src/decorators/Authorized.ts b/src/decorators/Authorized.ts index 0f0d41ba4..80a1504cf 100644 --- a/src/decorators/Authorized.ts +++ b/src/decorators/Authorized.ts @@ -4,10 +4,12 @@ import { getArrayFromOverloadedRest } from "../helpers/decorators"; import { MethodAndPropDecorator } from "./types"; export function Authorized(): MethodAndPropDecorator; -export function Authorized(roles: RoleType[]): MethodAndPropDecorator; -export function Authorized(...roles: RoleType[]): MethodAndPropDecorator; +export function Authorized(roles: readonly RoleType[]): MethodAndPropDecorator; export function Authorized( - ...rolesOrRolesArray: Array + ...roles: readonly RoleType[] +): MethodAndPropDecorator; +export function Authorized( + ...rolesOrRolesArray: Array ): MethodDecorator | PropertyDecorator { const roles = getArrayFromOverloadedRest(rolesOrRolesArray); diff --git a/src/helpers/decorators.ts b/src/helpers/decorators.ts index e6f4d68b6..092fd6f2a 100644 --- a/src/helpers/decorators.ts +++ b/src/helpers/decorators.ts @@ -36,7 +36,7 @@ export function getNameDecoratorParams( } } -export function getArrayFromOverloadedRest(overloadedArray: Array): T[] { +export function getArrayFromOverloadedRest(overloadedArray: Array): T[] { let items: T[]; if (Array.isArray(overloadedArray[0])) { items = overloadedArray[0] as T[]; diff --git a/tests/functional/authorization.ts b/tests/functional/authorization.ts index 7abfbae40..640b3e8dc 100644 --- a/tests/functional/authorization.ts +++ b/tests/functional/authorization.ts @@ -185,8 +185,7 @@ describe("Authorization", () => { }); // TODO: check for wrong `@Authorized` usage - // it("should throw error when `@Authorized` is used on args, input or interface class", async () => { - // } + it.todo("should throw error when `@Authorized` is used on args, input or interface class"); }); describe("Functional", () => { @@ -541,4 +540,33 @@ describe("Authorization", () => { expect(authCheckerRoles).toEqual(["ADMIN", "REGULAR"]); }); }); + + describe("with constant readonly array or roles", () => { + let testResolver: Function; + + beforeAll(() => { + getMetadataStorage().clear(); + + const CONSTANT_ROLES = ["a", "b", "c"] as const; + + @Resolver() + class TestResolver { + @Query() + @Authorized(CONSTANT_ROLES) + authedQuery(@Ctx() ctx: any): boolean { + return ctx.user !== undefined; + } + } + + testResolver = TestResolver; + }); + + it("should not throw an error", async () => { + await buildSchema({ + resolvers: [testResolver], + // dummy auth checker + authChecker: () => false, + }); + }); + }); });