Skip to content

Commit

Permalink
feat(authorization): support readonly arrays for roles (#935)
Browse files Browse the repository at this point in the history
Co-authored-by: Michał Lytek <[email protected]>
  • Loading branch information
beaucollins and MichalLytek authored Aug 20, 2021
1 parent 9d0491c commit 6ac6e1b
Show file tree
Hide file tree
Showing 4 changed files with 37 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
8 changes: 5 additions & 3 deletions src/decorators/Authorized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@ import { getArrayFromOverloadedRest } from "../helpers/decorators";
import { MethodAndPropDecorator } from "./types";

export function Authorized(): MethodAndPropDecorator;
export function Authorized<RoleType = string>(roles: RoleType[]): MethodAndPropDecorator;
export function Authorized<RoleType = string>(...roles: RoleType[]): MethodAndPropDecorator;
export function Authorized<RoleType = string>(roles: readonly RoleType[]): MethodAndPropDecorator;
export function Authorized<RoleType = string>(
...rolesOrRolesArray: Array<RoleType | RoleType[]>
...roles: readonly RoleType[]
): MethodAndPropDecorator;
export function Authorized<RoleType = string>(
...rolesOrRolesArray: Array<RoleType | readonly RoleType[]>
): MethodDecorator | PropertyDecorator {
const roles = getArrayFromOverloadedRest(rolesOrRolesArray);

Expand Down
2 changes: 1 addition & 1 deletion src/helpers/decorators.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export function getNameDecoratorParams<T extends DescriptionOptions>(
}
}

export function getArrayFromOverloadedRest<T>(overloadedArray: Array<T | T[]>): T[] {
export function getArrayFromOverloadedRest<T>(overloadedArray: Array<T | readonly T[]>): T[] {
let items: T[];
if (Array.isArray(overloadedArray[0])) {
items = overloadedArray[0] as T[];
Expand Down
32 changes: 30 additions & 2 deletions tests/functional/authorization.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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", () => {
Expand Down Expand Up @@ -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,
});
});
});
});

0 comments on commit 6ac6e1b

Please sign in to comment.