From 9d74d2ace6cb88020d0daaccf01d9a442faf9d22 Mon Sep 17 00:00:00 2001 From: cbolles Date: Thu, 4 Jan 2024 09:58:14 -0500 Subject: [PATCH 1/5] Move roles to permissions folder --- packages/server/src/auth/auth.service.ts | 2 +- packages/server/src/auth/casbin.provider.ts | 2 +- packages/server/src/auth/permissions/dataset.ts | 2 +- packages/server/src/auth/permissions/project.ts | 2 +- packages/server/src/auth/{ => permissions}/roles.ts | 0 packages/server/src/auth/permissions/study.ts | 2 +- packages/server/src/auth/permissions/tag.ts | 2 +- 7 files changed, 6 insertions(+), 6 deletions(-) rename packages/server/src/auth/{ => permissions}/roles.ts (100%) diff --git a/packages/server/src/auth/auth.service.ts b/packages/server/src/auth/auth.service.ts index e17c8da5..f4d84227 100644 --- a/packages/server/src/auth/auth.service.ts +++ b/packages/server/src/auth/auth.service.ts @@ -4,7 +4,7 @@ import { ConfigService } from '@nestjs/config'; import { firstValueFrom } from 'rxjs'; import { CASBIN_PROVIDER } from './casbin.provider'; import * as casbin from 'casbin'; -import { Roles } from './roles'; +import { Roles } from './permissions/roles'; @Injectable() export class AuthService { diff --git a/packages/server/src/auth/casbin.provider.ts b/packages/server/src/auth/casbin.provider.ts index d559b149..8442c259 100644 --- a/packages/server/src/auth/casbin.provider.ts +++ b/packages/server/src/auth/casbin.provider.ts @@ -2,7 +2,7 @@ import { Provider } from '@nestjs/common'; import { ConfigService } from '@nestjs/config'; import * as casbin from 'casbin'; import { MongooseAdapter } from 'casbin-mongoose-adapter'; -import { roleHierarchy } from './roles'; +import { roleHierarchy } from './permissions/roles'; import { roleToStudyPermissions } from './permissions/study'; import { roleToProjectPermissions } from './permissions/project'; import { roleToTagPermissions } from './permissions/tag'; diff --git a/packages/server/src/auth/permissions/dataset.ts b/packages/server/src/auth/permissions/dataset.ts index 81c0d549..f0f7e370 100644 --- a/packages/server/src/auth/permissions/dataset.ts +++ b/packages/server/src/auth/permissions/dataset.ts @@ -1,4 +1,4 @@ -import { Roles } from '../roles'; +import { Roles } from './roles'; export enum DatasetPermissions { CREATE = 'dataset:create', diff --git a/packages/server/src/auth/permissions/project.ts b/packages/server/src/auth/permissions/project.ts index 327f4d6d..0327f6e8 100644 --- a/packages/server/src/auth/permissions/project.ts +++ b/packages/server/src/auth/permissions/project.ts @@ -1,4 +1,4 @@ -import { Roles } from '../roles'; +import { Roles } from './roles'; /** Permissions associated with projects */ export enum ProjectPermissions { diff --git a/packages/server/src/auth/roles.ts b/packages/server/src/auth/permissions/roles.ts similarity index 100% rename from packages/server/src/auth/roles.ts rename to packages/server/src/auth/permissions/roles.ts diff --git a/packages/server/src/auth/permissions/study.ts b/packages/server/src/auth/permissions/study.ts index abc0d8bf..df831450 100644 --- a/packages/server/src/auth/permissions/study.ts +++ b/packages/server/src/auth/permissions/study.ts @@ -1,4 +1,4 @@ -import { Roles } from '../roles'; +import { Roles } from './roles'; /** Permissions associated with studies */ export enum StudyPermissions { diff --git a/packages/server/src/auth/permissions/tag.ts b/packages/server/src/auth/permissions/tag.ts index c0a4e671..81715590 100644 --- a/packages/server/src/auth/permissions/tag.ts +++ b/packages/server/src/auth/permissions/tag.ts @@ -1,4 +1,4 @@ -import { Roles } from '../roles'; +import { Roles } from './roles'; export enum TagPermissions { CREATE = 'tag:create', From e25c4132ded196620a321716cace6ad01909faa4 Mon Sep 17 00:00:00 2001 From: cbolles Date: Thu, 4 Jan 2024 10:44:53 -0500 Subject: [PATCH 2/5] Move JWT logic to dedicated module --- packages/server/src/app.module.ts | 6 ++- packages/server/src/auth/auth.module.ts | 17 +------ packages/server/src/auth/auth.resolver.ts | 8 ++-- .../server/src/dataset/dataset.resolver.ts | 8 ++-- .../src/entry/resolvers/entry.resolver.ts | 8 ++-- .../resolvers/upload-session.resolver.ts | 16 +++---- .../server/src/{auth => jwt}/jwt.guard.ts | 0 packages/server/src/jwt/jwt.module.ts | 45 +++++++++++++++++++ packages/server/src/jwt/jwt.service.ts | 31 +++++++++++++ .../server/src/{auth => jwt}/jwt.strategy.ts | 2 +- .../token.context.ts} | 2 +- .../{auth/user.dto.ts => jwt/token.dto.ts} | 0 .../src/organization/organization.resolver.ts | 2 +- packages/server/src/perms/perms.module.ts | 4 ++ .../server/src/project/project.resolver.ts | 14 +++--- packages/server/src/study/study.resolver.ts | 8 ++-- packages/server/src/tag/tag.resolver.ts | 2 +- 17 files changed, 121 insertions(+), 52 deletions(-) rename packages/server/src/{auth => jwt}/jwt.guard.ts (100%) create mode 100644 packages/server/src/jwt/jwt.module.ts create mode 100644 packages/server/src/jwt/jwt.service.ts rename packages/server/src/{auth => jwt}/jwt.strategy.ts (96%) rename packages/server/src/{auth/user.decorator.ts => jwt/token.context.ts} (70%) rename packages/server/src/{auth/user.dto.ts => jwt/token.dto.ts} (100%) create mode 100644 packages/server/src/perms/perms.module.ts diff --git a/packages/server/src/app.module.ts b/packages/server/src/app.module.ts index 5e022e71..523b9a3a 100644 --- a/packages/server/src/app.module.ts +++ b/packages/server/src/app.module.ts @@ -12,6 +12,8 @@ import { EntryModule } from './entry/entry.module'; import { TagModule } from './tag/tag.module'; import { SharedModule } from './shared/shared.module'; import { AuthModule } from './auth/auth.module'; +import { JwtModule } from './jwt/jwt.module'; +import { PermsModule } from './perms/perms.module'; @Module({ imports: [ @@ -40,7 +42,9 @@ import { AuthModule } from './auth/auth.module'; EntryModule, TagModule, SharedModule, - AuthModule + AuthModule, + JwtModule, + PermsModule ] }) export class AppModule {} diff --git a/packages/server/src/auth/auth.module.ts b/packages/server/src/auth/auth.module.ts index b47c497a..ecfe1dd0 100644 --- a/packages/server/src/auth/auth.module.ts +++ b/packages/server/src/auth/auth.module.ts @@ -2,18 +2,13 @@ import { forwardRef, Module } from '@nestjs/common'; import { JwtModule, JwtModuleOptions } from '@nestjs/jwt'; import { AuthService } from './auth.service'; import { PassportModule } from '@nestjs/passport'; -import { JwtStrategy } from './jwt.strategy'; -import { JwtAuthGuard } from './jwt.guard'; -import { OrganizationModule } from '../organization/organization.module'; import { HttpModule } from '@nestjs/axios'; import { casbinProvider } from './casbin.provider'; import { AuthResolver } from './auth.resolver'; -import { OrganizationService } from '../organization/organization.service'; @Module({ imports: [ PassportModule, - OrganizationModule, HttpModule, JwtModule.registerAsync({ imports: [forwardRef(() => AuthModule)], @@ -27,22 +22,12 @@ import { OrganizationService } from '../organization/organization.service'; }; return options; } - }), - forwardRef(() => OrganizationModule) + }) ], providers: [ AuthService, - JwtAuthGuard, casbinProvider, AuthResolver, - { - provide: JwtStrategy, - inject: [AuthService, OrganizationService], - useFactory: async (authService: AuthService, organizationService: OrganizationService) => { - const key = await authService.getPublicKey(); - return new JwtStrategy(key, organizationService); - } - } ], exports: [AuthService, casbinProvider] }) diff --git a/packages/server/src/auth/auth.resolver.ts b/packages/server/src/auth/auth.resolver.ts index ee78914e..b4681649 100644 --- a/packages/server/src/auth/auth.resolver.ts +++ b/packages/server/src/auth/auth.resolver.ts @@ -1,8 +1,8 @@ import { Resolver, Mutation, Args, ID } from '@nestjs/graphql'; -import { JwtAuthGuard } from './jwt.guard'; +import { JwtAuthGuard } from '../jwt/jwt.guard'; import { UseGuards } from '@nestjs/common'; -import { UserContext } from './user.decorator'; -import { TokenPayload } from './user.dto'; +import { TokenContext } from '../jwt/token.context'; +import { TokenPayload } from '../jwt/token.dto'; import { AuthService } from './auth.service'; import { OrganizationContext } from 'src/organization/organization.context'; import { Organization } from 'src/organization/organization.model'; @@ -15,7 +15,7 @@ export class AuthResolver { @Mutation(() => Boolean) async grantOwner( @Args('targetUser', { type: () => ID }) targetUser: string, - @UserContext() requestingUser: TokenPayload, + @TokenContext() requestingUser: TokenPayload, @OrganizationContext() organization: Organization ): Promise { await this.authService.grantOwner(targetUser, requestingUser.id, organization._id); diff --git a/packages/server/src/dataset/dataset.resolver.ts b/packages/server/src/dataset/dataset.resolver.ts index 35d83acd..1d8e3eea 100644 --- a/packages/server/src/dataset/dataset.resolver.ts +++ b/packages/server/src/dataset/dataset.resolver.ts @@ -6,11 +6,11 @@ import { OrganizationContext } from '../organization/organization.context'; import { DatasetCreate } from './dtos/create.dto'; import { DatasetPipe } from './pipes/dataset.pipe'; import { BadRequestException, UseGuards, Inject, UnauthorizedException } from '@nestjs/common'; -import { JwtAuthGuard } from '../auth/jwt.guard'; +import { JwtAuthGuard } from '../jwt/jwt.guard'; import { CASBIN_PROVIDER } from '../auth/casbin.provider'; import * as casbin from 'casbin'; -import { UserContext } from '../auth/user.decorator'; -import { TokenPayload } from '../auth/user.dto'; +import { TokenContext } from '../jwt/token.context'; +import { TokenPayload } from '../jwt/token.dto'; import { DatasetPermissions } from '../auth/permissions/dataset'; // TODO: Add authentication @@ -33,7 +33,7 @@ export class DatasetResolver { async createDataset( @Args('dataset') dataset: DatasetCreate, @OrganizationContext() organization: Organization, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.CREATE, organization._id))) { throw new UnauthorizedException('User does not have permission to create a dataset in this organization'); diff --git a/packages/server/src/entry/resolvers/entry.resolver.ts b/packages/server/src/entry/resolvers/entry.resolver.ts index 55ffdee6..88116430 100644 --- a/packages/server/src/entry/resolvers/entry.resolver.ts +++ b/packages/server/src/entry/resolvers/entry.resolver.ts @@ -4,12 +4,12 @@ import { Entry } from '../models/entry.model'; import { EntryService } from '../services/entry.service'; import { DatasetPipe } from '../../dataset/pipes/dataset.pipe'; import { UseGuards, Inject, UnauthorizedException } from '@nestjs/common'; -import { JwtAuthGuard } from '../../auth/jwt.guard'; +import { JwtAuthGuard } from '../../jwt/jwt.guard'; import { DatasetPermissions } from '../../auth/permissions/dataset'; import { CASBIN_PROVIDER } from '../../auth/casbin.provider'; import * as casbin from 'casbin'; -import { TokenPayload } from '../../auth/user.dto'; -import { UserContext } from '../../auth/user.decorator'; +import { TokenPayload } from '../../jwt/token.dto'; +import { TokenContext } from '../../jwt/token.context'; @UseGuards(JwtAuthGuard) @Resolver(() => Entry) @@ -22,7 +22,7 @@ export class EntryResolver { @Query(() => [Entry]) async entryForDataset( @Args('dataset', { type: () => ID }, DatasetPipe) dataset: Dataset, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.READ, dataset._id))) { throw new UnauthorizedException('User cannot read entries on this dataset'); diff --git a/packages/server/src/entry/resolvers/upload-session.resolver.ts b/packages/server/src/entry/resolvers/upload-session.resolver.ts index 65f6b4f1..c9b17505 100644 --- a/packages/server/src/entry/resolvers/upload-session.resolver.ts +++ b/packages/server/src/entry/resolvers/upload-session.resolver.ts @@ -6,12 +6,12 @@ import { Args, ID, Mutation, Query } from '@nestjs/graphql'; import { UploadSessionPipe } from '../pipes/upload-session.pipe'; import { DatasetPipe } from '../../dataset/pipes/dataset.pipe'; import { UploadResult } from '../dtos/upload-result.dto'; -import { JwtAuthGuard } from '../../auth/jwt.guard'; +import { JwtAuthGuard } from '../../jwt/jwt.guard'; import { DatasetPermissions } from '../../auth/permissions/dataset'; import { CASBIN_PROVIDER } from '../../auth/casbin.provider'; import * as casbin from 'casbin'; -import { UserContext } from 'src/auth/user.decorator'; -import { TokenPayload } from 'src/auth/user.dto'; +import { TokenContext } from '../../jwt/token.context'; +import { TokenPayload } from '../../jwt/token.dto'; @UseGuards(JwtAuthGuard) @Injectable() @@ -25,7 +25,7 @@ export class UploadSessionResolver { @Mutation(() => UploadSession) async createUploadSession( @Args('dataset', { type: () => ID }, DatasetPipe) dataset: Dataset, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.UPDATE, dataset._id))) { throw new UnauthorizedException('User cannot write entries on this dataset'); @@ -38,7 +38,7 @@ export class UploadSessionResolver { @Mutation(() => UploadResult) async completeUploadSession( @Args('session', { type: () => ID }, UploadSessionPipe) uploadSession: UploadSession, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.UPDATE, uploadSession.dataset))) { throw new UnauthorizedException('User cannot write entries on this dataset'); @@ -50,7 +50,7 @@ export class UploadSessionResolver { @Query(() => String, { description: 'Get the presigned URL for where to upload the CSV against' }) async getCSVUploadURL( @Args('session', { type: () => ID }, UploadSessionPipe) uploadSession: UploadSession, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.UPDATE, uploadSession.dataset))) { throw new UnauthorizedException('User cannot write entries on this dataset'); @@ -62,7 +62,7 @@ export class UploadSessionResolver { @Query(() => UploadResult) async validateCSV( @Args('session', { type: () => ID }, UploadSessionPipe) uploadSession: UploadSession, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.UPDATE, uploadSession.dataset))) { throw new UnauthorizedException('User cannot write entries on this dataset'); @@ -77,7 +77,7 @@ export class UploadSessionResolver { @Args('session', { type: () => ID }, UploadSessionPipe) uploadSession: UploadSession, @Args('filename') filename: string, @Args('contentType') contentType: string, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, DatasetPermissions.UPDATE, uploadSession.dataset))) { throw new UnauthorizedException('User cannot write entries on this dataset'); diff --git a/packages/server/src/auth/jwt.guard.ts b/packages/server/src/jwt/jwt.guard.ts similarity index 100% rename from packages/server/src/auth/jwt.guard.ts rename to packages/server/src/jwt/jwt.guard.ts diff --git a/packages/server/src/jwt/jwt.module.ts b/packages/server/src/jwt/jwt.module.ts new file mode 100644 index 00000000..e4609f0d --- /dev/null +++ b/packages/server/src/jwt/jwt.module.ts @@ -0,0 +1,45 @@ +import { Module, forwardRef } from '@nestjs/common'; +import { + JwtModule as NestJwtModule, + JwtModuleOptions as NestJwtModuleOptions +} from '@nestjs/jwt'; +import { JwtService } from './jwt.service'; +import { HttpModule } from '@nestjs/axios'; +import { JwtAuthGuard } from './jwt.guard'; +import { JwtStrategy } from './jwt.strategy'; +import { OrganizationService } from '../organization/organization.service'; +import { OrganizationModule } from '../organization/organization.module'; + +@Module({ + imports: [ + NestJwtModule.registerAsync({ + imports: [forwardRef(() => JwtModule)], + inject: [JwtService], + useFactory: async (jwtService: JwtService) => { + const options: NestJwtModuleOptions = { + publicKey: await jwtService.getPublicKey(), + signOptions: { + algorithm: 'RS256', + } + }; + return options; + }, + }), + HttpModule, + forwardRef(() => OrganizationModule) + ], + providers: [ + JwtService, + JwtAuthGuard, + { + provide: JwtStrategy, + inject: [JwtService, OrganizationService], + useFactory: async (jwtService: JwtService, organizationService: OrganizationService) => { + const key = await jwtService.getPublicKey(); + return new JwtStrategy(key, organizationService); + } + } + ], + exports: [JwtService] +}) +export class JwtModule {} diff --git a/packages/server/src/jwt/jwt.service.ts b/packages/server/src/jwt/jwt.service.ts new file mode 100644 index 00000000..c978904b --- /dev/null +++ b/packages/server/src/jwt/jwt.service.ts @@ -0,0 +1,31 @@ +import { Injectable } from '@nestjs/common'; +import { HttpService } from '@nestjs/axios'; +import { ConfigService } from '@nestjs/config'; +import { firstValueFrom } from 'rxjs'; + +@Injectable() +export class JwtService { + private publicKey: string | null = null; + + constructor( + private readonly httpService: HttpService, + private readonly configService: ConfigService, + ) {} + + // TODO: In the future this will be replaced by a library which handles + // key rotation + async queryForPublicKey(): Promise { + const query = this.configService.getOrThrow('auth.publicKeyUrl'); + + const response = await firstValueFrom(this.httpService.get(query)); + return response.data[0]; + } + + async getPublicKey(): Promise { + if (this.publicKey === null) { + this.publicKey = await this.queryForPublicKey(); + } + + return this.publicKey; + } +} diff --git a/packages/server/src/auth/jwt.strategy.ts b/packages/server/src/jwt/jwt.strategy.ts similarity index 96% rename from packages/server/src/auth/jwt.strategy.ts rename to packages/server/src/jwt/jwt.strategy.ts index 360dfd05..e4396434 100644 --- a/packages/server/src/auth/jwt.strategy.ts +++ b/packages/server/src/jwt/jwt.strategy.ts @@ -1,7 +1,7 @@ import { Injectable, BadGatewayException } from '@nestjs/common'; import { PassportStrategy } from '@nestjs/passport'; import { ExtractJwt, Strategy } from 'passport-jwt'; -import { TokenPayload } from './user.dto'; +import { TokenPayload } from './token.dto'; import { OrganizationService } from '../organization/organization.service'; import { Organization } from 'src/organization/organization.model'; diff --git a/packages/server/src/auth/user.decorator.ts b/packages/server/src/jwt/token.context.ts similarity index 70% rename from packages/server/src/auth/user.decorator.ts rename to packages/server/src/jwt/token.context.ts index 27a37e42..fece3f78 100644 --- a/packages/server/src/auth/user.decorator.ts +++ b/packages/server/src/jwt/token.context.ts @@ -1,7 +1,7 @@ import { GqlExecutionContext } from '@nestjs/graphql'; import { ExecutionContext, createParamDecorator } from '@nestjs/common'; -export const UserContext = createParamDecorator((_data: unknown, ctx: ExecutionContext) => { +export const TokenContext = createParamDecorator((_data: unknown, ctx: ExecutionContext) => { const gqlCtx = GqlExecutionContext.create(ctx); return gqlCtx.getContext().req.user; }); diff --git a/packages/server/src/auth/user.dto.ts b/packages/server/src/jwt/token.dto.ts similarity index 100% rename from packages/server/src/auth/user.dto.ts rename to packages/server/src/jwt/token.dto.ts diff --git a/packages/server/src/organization/organization.resolver.ts b/packages/server/src/organization/organization.resolver.ts index f34bae36..cb53d629 100644 --- a/packages/server/src/organization/organization.resolver.ts +++ b/packages/server/src/organization/organization.resolver.ts @@ -4,7 +4,7 @@ import { Organization } from './organization.model'; import { OrganizationService } from './organization.service'; import { CreateOrganizationPipe } from './pipes/create.pipe'; import { UseGuards } from '@nestjs/common'; -import { JwtAuthGuard } from '../auth/jwt.guard'; +import { JwtAuthGuard } from '../jwt/jwt.guard'; @Resolver(() => Organization) export class OrganizationResolver { diff --git a/packages/server/src/perms/perms.module.ts b/packages/server/src/perms/perms.module.ts new file mode 100644 index 00000000..cdfcfc98 --- /dev/null +++ b/packages/server/src/perms/perms.module.ts @@ -0,0 +1,4 @@ +import { Module } from '@nestjs/common'; + +@Module({}) +export class PermsModule {} diff --git a/packages/server/src/project/project.resolver.ts b/packages/server/src/project/project.resolver.ts index 628ac15a..61f3fe22 100644 --- a/packages/server/src/project/project.resolver.ts +++ b/packages/server/src/project/project.resolver.ts @@ -6,9 +6,9 @@ import { ProjectCreate } from './dtos/create.dto'; import { Project } from './project.model'; import { ProjectService } from './project.service'; import { ProjectPipe } from './pipes/project.pipe'; -import { JwtAuthGuard } from '../auth/jwt.guard'; -import { UserContext } from '../auth/user.decorator'; -import { TokenPayload } from '../auth/user.dto'; +import { JwtAuthGuard } from '../jwt/jwt.guard'; +import { TokenContext } from '../jwt/token.context'; +import { TokenPayload } from '../jwt/token.dto'; import { CASBIN_PROVIDER } from '../auth/casbin.provider'; import * as casbin from 'casbin'; import { ProjectPermissions } from '../auth/permissions/project'; @@ -25,7 +25,7 @@ export class ProjectResolver { async signLabCreateProject( @Args('project') project: ProjectCreate, @OrganizationContext() organization: Organization, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { // Make sure the user is allowed to create projects if (!(await this.enforcer.enforce(user.id, ProjectPermissions.CREATE, organization._id))) { @@ -43,7 +43,7 @@ export class ProjectResolver { async projectExists( @Args('name') name: string, @OrganizationContext() organization: Organization, - @UserContext() _user: TokenPayload + @TokenContext() _user: TokenPayload ): Promise { return this.projectService.exists(name, organization._id); } @@ -52,7 +52,7 @@ export class ProjectResolver { @Mutation(() => Boolean) async deleteProject( @Args('project', { type: () => ID }, ProjectPipe) project: Project, - @UserContext() user: TokenPayload, + @TokenContext() user: TokenPayload, @OrganizationContext() organization: Organization ): Promise { if (!(await this.enforcer.enforce(user.id, ProjectPermissions.DELETE, organization._id))) { @@ -67,7 +67,7 @@ export class ProjectResolver { @Query(() => [Project]) async getProjects( @OrganizationContext() organization: Organization, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, ProjectPermissions.READ, organization._id))) { throw new UnauthorizedException('User does not have permission to read projects'); diff --git a/packages/server/src/study/study.resolver.ts b/packages/server/src/study/study.resolver.ts index 9543be5f..1dc08419 100644 --- a/packages/server/src/study/study.resolver.ts +++ b/packages/server/src/study/study.resolver.ts @@ -7,12 +7,12 @@ import { StudyCreate } from './dtos/create.dto'; import { StudyService } from './study.service'; import { StudyCreatePipe } from './pipes/create.pipe'; import { UseGuards, Inject, UnauthorizedException } from '@nestjs/common'; -import { JwtAuthGuard } from '../auth/jwt.guard'; +import { JwtAuthGuard } from '../jwt/jwt.guard'; import { CASBIN_PROVIDER } from '../auth/casbin.provider'; import * as casbin from 'casbin'; import { StudyPermissions } from '../auth/permissions/study'; -import { UserContext } from 'src/auth/user.decorator'; -import { TokenPayload } from 'src/auth/user.dto'; +import { TokenContext } from '../jwt/token.context'; +import { TokenPayload } from '../jwt/token.dto'; @UseGuards(JwtAuthGuard) @Resolver(() => Study) @@ -25,7 +25,7 @@ export class StudyResolver { @Mutation(() => Study) async createStudy( @Args('study', { type: () => StudyCreate }, StudyCreatePipe) study: StudyCreate, - @UserContext() user: TokenPayload + @TokenContext() user: TokenPayload ): Promise { if (!(await this.enforcer.enforce(user.id, StudyPermissions.CREATE, study.project))) { throw new UnauthorizedException('User cannot create studies on this project'); diff --git a/packages/server/src/tag/tag.resolver.ts b/packages/server/src/tag/tag.resolver.ts index 56d8a06c..44cb49fc 100644 --- a/packages/server/src/tag/tag.resolver.ts +++ b/packages/server/src/tag/tag.resolver.ts @@ -8,7 +8,7 @@ import { Entry } from '../entry/models/entry.model'; import { TagPipe } from './pipes/tag.pipe'; import JSON from 'graphql-type-json'; import { UseGuards } from '@nestjs/common'; -import { JwtAuthGuard } from '../auth/jwt.guard'; +import { JwtAuthGuard } from '../jwt/jwt.guard'; // TODO: Add permissioning @UseGuards(JwtAuthGuard) From 32ea36ffc7632fd47b6789491ee9a0fdaab6ca8f Mon Sep 17 00:00:00 2001 From: cbolles Date: Thu, 4 Jan 2024 10:59:48 -0500 Subject: [PATCH 3/5] Move permission logic into dedicated module --- packages/server/schema.gql | 1 - packages/server/src/app.module.ts | 6 ++-- packages/server/src/auth/auth.module.ts | 34 ------------------- packages/server/src/dataset/dataset.module.ts | 5 +-- .../server/src/dataset/dataset.resolver.ts | 4 +-- .../server/src/dataset/dataset.service.ts | 2 +- packages/server/src/entry/entry.module.ts | 6 ++-- .../src/entry/resolvers/entry.resolver.ts | 4 +-- .../resolvers/upload-session.resolver.ts | 4 +-- .../{auth => permission}/casbin.provider.ts | 0 .../src/permission/permission.module.ts | 10 ++++++ .../permission.resolver.ts} | 8 ++--- .../permission.service.ts} | 26 +------------- .../permissions/dataset.ts | 0 .../permissions/project.ts | 0 .../{auth => permission}/permissions/roles.ts | 0 .../{auth => permission}/permissions/study.ts | 0 .../{auth => permission}/permissions/tag.ts | 0 packages/server/src/perms/perms.module.ts | 4 --- packages/server/src/project/project.module.ts | 6 ++-- .../server/src/project/project.resolver.ts | 4 +-- .../server/src/project/project.service.ts | 2 +- packages/server/src/study/study.module.ts | 6 ++-- packages/server/src/study/study.resolver.ts | 4 +-- packages/server/src/study/study.service.ts | 2 +- 25 files changed, 45 insertions(+), 93 deletions(-) delete mode 100644 packages/server/src/auth/auth.module.ts rename packages/server/src/{auth => permission}/casbin.provider.ts (100%) create mode 100644 packages/server/src/permission/permission.module.ts rename packages/server/src/{auth/auth.resolver.ts => permission/permission.resolver.ts} (73%) rename packages/server/src/{auth/auth.service.ts => permission/permission.service.ts} (50%) rename packages/server/src/{auth => permission}/permissions/dataset.ts (100%) rename packages/server/src/{auth => permission}/permissions/project.ts (100%) rename packages/server/src/{auth => permission}/permissions/roles.ts (100%) rename packages/server/src/{auth => permission}/permissions/study.ts (100%) rename packages/server/src/{auth => permission}/permissions/tag.ts (100%) delete mode 100644 packages/server/src/perms/perms.module.ts diff --git a/packages/server/schema.gql b/packages/server/schema.gql index 0f06f13e..3796e91a 100644 --- a/packages/server/schema.gql +++ b/packages/server/schema.gql @@ -125,7 +125,6 @@ type Mutation { createDataset(dataset: DatasetCreate!): Dataset! changeDatasetName(dataset: ID!, newName: String!): Boolean! changeDatasetDescription(dataset: ID!, newDescription: String!): Boolean! - grantOwner(targetUser: ID!): Boolean! signLabCreateProject(project: ProjectCreate!): Project! deleteProject(project: ID!): Boolean! createStudy(study: StudyCreate!): Study! diff --git a/packages/server/src/app.module.ts b/packages/server/src/app.module.ts index 523b9a3a..23bf25eb 100644 --- a/packages/server/src/app.module.ts +++ b/packages/server/src/app.module.ts @@ -11,9 +11,8 @@ import { StudyModule } from './study/study.module'; import { EntryModule } from './entry/entry.module'; import { TagModule } from './tag/tag.module'; import { SharedModule } from './shared/shared.module'; -import { AuthModule } from './auth/auth.module'; import { JwtModule } from './jwt/jwt.module'; -import { PermsModule } from './perms/perms.module'; +import { PermissionModule } from './permission/permission.module'; @Module({ imports: [ @@ -42,9 +41,8 @@ import { PermsModule } from './perms/perms.module'; EntryModule, TagModule, SharedModule, - AuthModule, JwtModule, - PermsModule + PermissionModule ] }) export class AppModule {} diff --git a/packages/server/src/auth/auth.module.ts b/packages/server/src/auth/auth.module.ts deleted file mode 100644 index ecfe1dd0..00000000 --- a/packages/server/src/auth/auth.module.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { forwardRef, Module } from '@nestjs/common'; -import { JwtModule, JwtModuleOptions } from '@nestjs/jwt'; -import { AuthService } from './auth.service'; -import { PassportModule } from '@nestjs/passport'; -import { HttpModule } from '@nestjs/axios'; -import { casbinProvider } from './casbin.provider'; -import { AuthResolver } from './auth.resolver'; - -@Module({ - imports: [ - PassportModule, - HttpModule, - JwtModule.registerAsync({ - imports: [forwardRef(() => AuthModule)], - inject: [AuthService], - useFactory: async (authService: AuthService) => { - const options: JwtModuleOptions = { - publicKey: await authService.getPublicKey(), - signOptions: { - algorithm: 'RS256' - } - }; - return options; - } - }) - ], - providers: [ - AuthService, - casbinProvider, - AuthResolver, - ], - exports: [AuthService, casbinProvider] -}) -export class AuthModule {} diff --git a/packages/server/src/dataset/dataset.module.ts b/packages/server/src/dataset/dataset.module.ts index 387e4267..898e65ad 100644 --- a/packages/server/src/dataset/dataset.module.ts +++ b/packages/server/src/dataset/dataset.module.ts @@ -4,10 +4,11 @@ import { DatasetService } from './dataset.service'; import { MongooseModule } from '@nestjs/mongoose'; import { Dataset, DatasetSchema } from './dataset.model'; import { DatasetPipe } from './pipes/dataset.pipe'; -import { AuthModule } from '../auth/auth.module'; +import { PermissionModule } from '../permission/permission.module'; +import { JwtModule } from '../jwt/jwt.module'; @Module({ - imports: [MongooseModule.forFeature([{ name: Dataset.name, schema: DatasetSchema }]), AuthModule], + imports: [MongooseModule.forFeature([{ name: Dataset.name, schema: DatasetSchema }]), PermissionModule, JwtModule], providers: [DatasetResolver, DatasetService, DatasetPipe], exports: [DatasetService, DatasetPipe] }) diff --git a/packages/server/src/dataset/dataset.resolver.ts b/packages/server/src/dataset/dataset.resolver.ts index 1d8e3eea..1629174e 100644 --- a/packages/server/src/dataset/dataset.resolver.ts +++ b/packages/server/src/dataset/dataset.resolver.ts @@ -7,11 +7,11 @@ import { DatasetCreate } from './dtos/create.dto'; import { DatasetPipe } from './pipes/dataset.pipe'; import { BadRequestException, UseGuards, Inject, UnauthorizedException } from '@nestjs/common'; import { JwtAuthGuard } from '../jwt/jwt.guard'; -import { CASBIN_PROVIDER } from '../auth/casbin.provider'; +import { CASBIN_PROVIDER } from '../permission/casbin.provider'; import * as casbin from 'casbin'; import { TokenContext } from '../jwt/token.context'; import { TokenPayload } from '../jwt/token.dto'; -import { DatasetPermissions } from '../auth/permissions/dataset'; +import { DatasetPermissions } from '../permission/permissions/dataset'; // TODO: Add authentication @UseGuards(JwtAuthGuard) diff --git a/packages/server/src/dataset/dataset.service.ts b/packages/server/src/dataset/dataset.service.ts index cf616797..8e2c2097 100644 --- a/packages/server/src/dataset/dataset.service.ts +++ b/packages/server/src/dataset/dataset.service.ts @@ -4,7 +4,7 @@ import { InjectModel } from '@nestjs/mongoose'; import { Dataset } from './dataset.model'; import { DatasetCreate } from './dtos/create.dto'; import { ConfigService } from '@nestjs/config'; -import { CASBIN_PROVIDER } from '../auth/casbin.provider'; +import { CASBIN_PROVIDER } from '../permission/casbin.provider'; import * as casbin from 'casbin'; @Injectable() diff --git a/packages/server/src/entry/entry.module.ts b/packages/server/src/entry/entry.module.ts index 0c59c266..a94d7be5 100644 --- a/packages/server/src/entry/entry.module.ts +++ b/packages/server/src/entry/entry.module.ts @@ -13,7 +13,8 @@ import { EntryUploadService } from './services/entry-upload.service'; import { UploadSessionPipe } from './pipes/upload-session.pipe'; import { GcpModule } from '../gcp/gcp.module'; import { CsvValidationService } from './services/csv-validation.service'; -import { AuthModule } from '../auth/auth.module'; +import { PermissionModule } from '../permission/permission.module'; +import { JwtModule } from '../jwt/jwt.module'; @Module({ imports: [ @@ -24,7 +25,8 @@ import { AuthModule } from '../auth/auth.module'; ]), DatasetModule, GcpModule, - AuthModule + PermissionModule, + JwtModule ], providers: [ EntryResolver, diff --git a/packages/server/src/entry/resolvers/entry.resolver.ts b/packages/server/src/entry/resolvers/entry.resolver.ts index 88116430..f2a76ba8 100644 --- a/packages/server/src/entry/resolvers/entry.resolver.ts +++ b/packages/server/src/entry/resolvers/entry.resolver.ts @@ -5,8 +5,8 @@ import { EntryService } from '../services/entry.service'; import { DatasetPipe } from '../../dataset/pipes/dataset.pipe'; import { UseGuards, Inject, UnauthorizedException } from '@nestjs/common'; import { JwtAuthGuard } from '../../jwt/jwt.guard'; -import { DatasetPermissions } from '../../auth/permissions/dataset'; -import { CASBIN_PROVIDER } from '../../auth/casbin.provider'; +import { DatasetPermissions } from '../../permission/permissions/dataset'; +import { CASBIN_PROVIDER } from '../../permission/casbin.provider'; import * as casbin from 'casbin'; import { TokenPayload } from '../../jwt/token.dto'; import { TokenContext } from '../../jwt/token.context'; diff --git a/packages/server/src/entry/resolvers/upload-session.resolver.ts b/packages/server/src/entry/resolvers/upload-session.resolver.ts index c9b17505..48f5db74 100644 --- a/packages/server/src/entry/resolvers/upload-session.resolver.ts +++ b/packages/server/src/entry/resolvers/upload-session.resolver.ts @@ -7,8 +7,8 @@ import { UploadSessionPipe } from '../pipes/upload-session.pipe'; import { DatasetPipe } from '../../dataset/pipes/dataset.pipe'; import { UploadResult } from '../dtos/upload-result.dto'; import { JwtAuthGuard } from '../../jwt/jwt.guard'; -import { DatasetPermissions } from '../../auth/permissions/dataset'; -import { CASBIN_PROVIDER } from '../../auth/casbin.provider'; +import { DatasetPermissions } from '../../permission/permissions/dataset'; +import { CASBIN_PROVIDER } from '../../permission/casbin.provider'; import * as casbin from 'casbin'; import { TokenContext } from '../../jwt/token.context'; import { TokenPayload } from '../../jwt/token.dto'; diff --git a/packages/server/src/auth/casbin.provider.ts b/packages/server/src/permission/casbin.provider.ts similarity index 100% rename from packages/server/src/auth/casbin.provider.ts rename to packages/server/src/permission/casbin.provider.ts diff --git a/packages/server/src/permission/permission.module.ts b/packages/server/src/permission/permission.module.ts new file mode 100644 index 00000000..9669bcd1 --- /dev/null +++ b/packages/server/src/permission/permission.module.ts @@ -0,0 +1,10 @@ +import { Module } from '@nestjs/common'; +import { casbinProvider } from './casbin.provider'; + +@Module({ + providers: [ + casbinProvider + ], + exports: [casbinProvider] +}) +export class PermissionModule {} diff --git a/packages/server/src/auth/auth.resolver.ts b/packages/server/src/permission/permission.resolver.ts similarity index 73% rename from packages/server/src/auth/auth.resolver.ts rename to packages/server/src/permission/permission.resolver.ts index b4681649..a3b7692c 100644 --- a/packages/server/src/auth/auth.resolver.ts +++ b/packages/server/src/permission/permission.resolver.ts @@ -3,14 +3,14 @@ import { JwtAuthGuard } from '../jwt/jwt.guard'; import { UseGuards } from '@nestjs/common'; import { TokenContext } from '../jwt/token.context'; import { TokenPayload } from '../jwt/token.dto'; -import { AuthService } from './auth.service'; +import { PermissionService } from './permission.service'; import { OrganizationContext } from 'src/organization/organization.context'; import { Organization } from 'src/organization/organization.model'; @UseGuards(JwtAuthGuard) @Resolver() -export class AuthResolver { - constructor(private readonly authService: AuthService) {} +export class PermissionResolver { + constructor(private readonly permissionService: PermissionService) {} @Mutation(() => Boolean) async grantOwner( @@ -18,7 +18,7 @@ export class AuthResolver { @TokenContext() requestingUser: TokenPayload, @OrganizationContext() organization: Organization ): Promise { - await this.authService.grantOwner(targetUser, requestingUser.id, organization._id); + await this.permissionService.grantOwner(targetUser, requestingUser.id, organization._id); return true; } } diff --git a/packages/server/src/auth/auth.service.ts b/packages/server/src/permission/permission.service.ts similarity index 50% rename from packages/server/src/auth/auth.service.ts rename to packages/server/src/permission/permission.service.ts index f4d84227..7d4edf77 100644 --- a/packages/server/src/auth/auth.service.ts +++ b/packages/server/src/permission/permission.service.ts @@ -1,30 +1,14 @@ import { Injectable, Inject, UnauthorizedException } from '@nestjs/common'; -import { HttpService } from '@nestjs/axios'; -import { ConfigService } from '@nestjs/config'; -import { firstValueFrom } from 'rxjs'; import { CASBIN_PROVIDER } from './casbin.provider'; import * as casbin from 'casbin'; import { Roles } from './permissions/roles'; @Injectable() -export class AuthService { - private publicKey: string | null = null; - +export class PermissionService { constructor( - private readonly httpService: HttpService, - private readonly configService: ConfigService, @Inject(CASBIN_PROVIDER) private readonly enforcer: casbin.Enforcer ) {} - // TODO: In the future this will be replaced by a library which handles - // key rotation - async queryForPublicKey(): Promise { - const query = this.configService.getOrThrow('auth.publicKeyUrl'); - - const response = await firstValueFrom(this.httpService.get(query)); - return response.data[0]; - } - /** requestingUser must be an owner themselves */ async grantOwner(targetUser: string, requestingUser: string, organization: string): Promise { // Make sure the requesting user is an owner @@ -35,12 +19,4 @@ export class AuthService { await this.enforcer.addPolicy(targetUser, Roles.OWNER, organization); } - - async getPublicKey(): Promise { - if (this.publicKey === null) { - this.publicKey = await this.queryForPublicKey(); - } - - return this.publicKey; - } } diff --git a/packages/server/src/auth/permissions/dataset.ts b/packages/server/src/permission/permissions/dataset.ts similarity index 100% rename from packages/server/src/auth/permissions/dataset.ts rename to packages/server/src/permission/permissions/dataset.ts diff --git a/packages/server/src/auth/permissions/project.ts b/packages/server/src/permission/permissions/project.ts similarity index 100% rename from packages/server/src/auth/permissions/project.ts rename to packages/server/src/permission/permissions/project.ts diff --git a/packages/server/src/auth/permissions/roles.ts b/packages/server/src/permission/permissions/roles.ts similarity index 100% rename from packages/server/src/auth/permissions/roles.ts rename to packages/server/src/permission/permissions/roles.ts diff --git a/packages/server/src/auth/permissions/study.ts b/packages/server/src/permission/permissions/study.ts similarity index 100% rename from packages/server/src/auth/permissions/study.ts rename to packages/server/src/permission/permissions/study.ts diff --git a/packages/server/src/auth/permissions/tag.ts b/packages/server/src/permission/permissions/tag.ts similarity index 100% rename from packages/server/src/auth/permissions/tag.ts rename to packages/server/src/permission/permissions/tag.ts diff --git a/packages/server/src/perms/perms.module.ts b/packages/server/src/perms/perms.module.ts deleted file mode 100644 index cdfcfc98..00000000 --- a/packages/server/src/perms/perms.module.ts +++ /dev/null @@ -1,4 +0,0 @@ -import { Module } from '@nestjs/common'; - -@Module({}) -export class PermsModule {} diff --git a/packages/server/src/project/project.module.ts b/packages/server/src/project/project.module.ts index c793d7ec..61a6c339 100644 --- a/packages/server/src/project/project.module.ts +++ b/packages/server/src/project/project.module.ts @@ -6,7 +6,8 @@ import { Project, ProjectSchema } from './project.model'; import { ProjectPipe } from './pipes/project.pipe'; import { MongooseMiddlewareService } from 'src/shared/service/mongoose-callback.service'; import { SharedModule } from 'src/shared/shared.module'; -import { AuthModule } from '../auth/auth.module'; +import { JwtModule } from '../jwt/jwt.module'; +import { PermissionModule } from '../permission/permission.module'; @Module({ imports: [ @@ -27,7 +28,8 @@ import { AuthModule } from '../auth/auth.module'; inject: [MongooseMiddlewareService] } ]), - AuthModule + JwtModule, + PermissionModule ], providers: [ProjectResolver, ProjectService, ProjectPipe], exports: [ProjectPipe, ProjectService] diff --git a/packages/server/src/project/project.resolver.ts b/packages/server/src/project/project.resolver.ts index 61f3fe22..71ae22d4 100644 --- a/packages/server/src/project/project.resolver.ts +++ b/packages/server/src/project/project.resolver.ts @@ -9,9 +9,9 @@ import { ProjectPipe } from './pipes/project.pipe'; import { JwtAuthGuard } from '../jwt/jwt.guard'; import { TokenContext } from '../jwt/token.context'; import { TokenPayload } from '../jwt/token.dto'; -import { CASBIN_PROVIDER } from '../auth/casbin.provider'; +import { CASBIN_PROVIDER } from '../permission/casbin.provider'; import * as casbin from 'casbin'; -import { ProjectPermissions } from '../auth/permissions/project'; +import { ProjectPermissions } from '../permission/permissions/project'; @UseGuards(JwtAuthGuard) @Resolver(() => Project) diff --git a/packages/server/src/project/project.service.ts b/packages/server/src/project/project.service.ts index 226d429e..a0e60a10 100644 --- a/packages/server/src/project/project.service.ts +++ b/packages/server/src/project/project.service.ts @@ -3,7 +3,7 @@ import { InjectModel } from '@nestjs/mongoose'; import { Model } from 'mongoose'; import { Project, ProjectDocument } from './project.model'; import { ProjectCreate } from './dtos/create.dto'; -import { CASBIN_PROVIDER } from '../auth/casbin.provider'; +import { CASBIN_PROVIDER } from '../permission/casbin.provider'; import * as casbin from 'casbin'; @Injectable() diff --git a/packages/server/src/study/study.module.ts b/packages/server/src/study/study.module.ts index 6167d974..8ff10dd2 100644 --- a/packages/server/src/study/study.module.ts +++ b/packages/server/src/study/study.module.ts @@ -8,7 +8,8 @@ import { StudyPipe } from './pipes/study.pipe'; import { StudyCreatePipe } from './pipes/create.pipe'; import { MongooseMiddlewareService } from '../shared/service/mongoose-callback.service'; import { SharedModule } from '../shared/shared.module'; -import { AuthModule } from '../auth/auth.module'; +import { JwtModule } from '../jwt/jwt.module'; +import { PermissionModule } from '../permission/permission.module'; @Module({ imports: [ @@ -31,7 +32,8 @@ import { AuthModule } from '../auth/auth.module'; ]), ProjectModule, SharedModule, - AuthModule + JwtModule, + PermissionModule ], providers: [StudyService, StudyResolver, StudyPipe, StudyCreatePipe], exports: [StudyService, StudyPipe] diff --git a/packages/server/src/study/study.resolver.ts b/packages/server/src/study/study.resolver.ts index 1dc08419..a26c2d3e 100644 --- a/packages/server/src/study/study.resolver.ts +++ b/packages/server/src/study/study.resolver.ts @@ -8,9 +8,9 @@ import { StudyService } from './study.service'; import { StudyCreatePipe } from './pipes/create.pipe'; import { UseGuards, Inject, UnauthorizedException } from '@nestjs/common'; import { JwtAuthGuard } from '../jwt/jwt.guard'; -import { CASBIN_PROVIDER } from '../auth/casbin.provider'; +import { CASBIN_PROVIDER } from '../permission/casbin.provider'; import * as casbin from 'casbin'; -import { StudyPermissions } from '../auth/permissions/study'; +import { StudyPermissions } from '../permission/permissions/study'; import { TokenContext } from '../jwt/token.context'; import { TokenPayload } from '../jwt/token.dto'; diff --git a/packages/server/src/study/study.service.ts b/packages/server/src/study/study.service.ts index 8a5689de..1b8e75a6 100644 --- a/packages/server/src/study/study.service.ts +++ b/packages/server/src/study/study.service.ts @@ -6,7 +6,7 @@ import { StudyCreate } from './dtos/create.dto'; import { Validator } from 'jsonschema'; import { Project } from 'src/project/project.model'; import { MongooseMiddlewareService } from '../shared/service/mongoose-callback.service'; -import { CASBIN_PROVIDER } from '../auth/casbin.provider'; +import { CASBIN_PROVIDER } from '../permission/casbin.provider'; import * as casbin from 'casbin'; @Injectable() From 3ac325f6c7ccd6b1bc71cc692eea0b7e7b72c7f0 Mon Sep 17 00:00:00 2001 From: cbolles Date: Thu, 4 Jan 2024 11:04:46 -0500 Subject: [PATCH 4/5] Re-add permission resolver --- packages/server/schema.gql | 1 + packages/server/src/permission/permission.module.ts | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/server/schema.gql b/packages/server/schema.gql index 3796e91a..0f06f13e 100644 --- a/packages/server/schema.gql +++ b/packages/server/schema.gql @@ -125,6 +125,7 @@ type Mutation { createDataset(dataset: DatasetCreate!): Dataset! changeDatasetName(dataset: ID!, newName: String!): Boolean! changeDatasetDescription(dataset: ID!, newDescription: String!): Boolean! + grantOwner(targetUser: ID!): Boolean! signLabCreateProject(project: ProjectCreate!): Project! deleteProject(project: ID!): Boolean! createStudy(study: StudyCreate!): Study! diff --git a/packages/server/src/permission/permission.module.ts b/packages/server/src/permission/permission.module.ts index 9669bcd1..44b8f499 100644 --- a/packages/server/src/permission/permission.module.ts +++ b/packages/server/src/permission/permission.module.ts @@ -1,9 +1,13 @@ import { Module } from '@nestjs/common'; import { casbinProvider } from './casbin.provider'; +import { PermissionResolver } from './permission.resolver'; +import { PermissionService } from './permission.service'; @Module({ providers: [ - casbinProvider + casbinProvider, + PermissionResolver, + PermissionService ], exports: [casbinProvider] }) From 5376beec9b75649edf611da6696c4d36271a674c Mon Sep 17 00:00:00 2001 From: cbolles Date: Thu, 4 Jan 2024 11:05:27 -0500 Subject: [PATCH 5/5] Fix formatting --- packages/server/src/jwt/jwt.module.ts | 9 +++------ packages/server/src/jwt/jwt.service.ts | 5 +---- packages/server/src/permission/permission.module.ts | 6 +----- packages/server/src/permission/permission.service.ts | 4 +--- 4 files changed, 6 insertions(+), 18 deletions(-) diff --git a/packages/server/src/jwt/jwt.module.ts b/packages/server/src/jwt/jwt.module.ts index e4609f0d..98e65c2b 100644 --- a/packages/server/src/jwt/jwt.module.ts +++ b/packages/server/src/jwt/jwt.module.ts @@ -1,8 +1,5 @@ import { Module, forwardRef } from '@nestjs/common'; -import { - JwtModule as NestJwtModule, - JwtModuleOptions as NestJwtModuleOptions -} from '@nestjs/jwt'; +import { JwtModule as NestJwtModule, JwtModuleOptions as NestJwtModuleOptions } from '@nestjs/jwt'; import { JwtService } from './jwt.service'; import { HttpModule } from '@nestjs/axios'; import { JwtAuthGuard } from './jwt.guard'; @@ -19,11 +16,11 @@ import { OrganizationModule } from '../organization/organization.module'; const options: NestJwtModuleOptions = { publicKey: await jwtService.getPublicKey(), signOptions: { - algorithm: 'RS256', + algorithm: 'RS256' } }; return options; - }, + } }), HttpModule, forwardRef(() => OrganizationModule) diff --git a/packages/server/src/jwt/jwt.service.ts b/packages/server/src/jwt/jwt.service.ts index c978904b..a18d974f 100644 --- a/packages/server/src/jwt/jwt.service.ts +++ b/packages/server/src/jwt/jwt.service.ts @@ -7,10 +7,7 @@ import { firstValueFrom } from 'rxjs'; export class JwtService { private publicKey: string | null = null; - constructor( - private readonly httpService: HttpService, - private readonly configService: ConfigService, - ) {} + constructor(private readonly httpService: HttpService, private readonly configService: ConfigService) {} // TODO: In the future this will be replaced by a library which handles // key rotation diff --git a/packages/server/src/permission/permission.module.ts b/packages/server/src/permission/permission.module.ts index 44b8f499..534e61f0 100644 --- a/packages/server/src/permission/permission.module.ts +++ b/packages/server/src/permission/permission.module.ts @@ -4,11 +4,7 @@ import { PermissionResolver } from './permission.resolver'; import { PermissionService } from './permission.service'; @Module({ - providers: [ - casbinProvider, - PermissionResolver, - PermissionService - ], + providers: [casbinProvider, PermissionResolver, PermissionService], exports: [casbinProvider] }) export class PermissionModule {} diff --git a/packages/server/src/permission/permission.service.ts b/packages/server/src/permission/permission.service.ts index 7d4edf77..d07f8cbd 100644 --- a/packages/server/src/permission/permission.service.ts +++ b/packages/server/src/permission/permission.service.ts @@ -5,9 +5,7 @@ import { Roles } from './permissions/roles'; @Injectable() export class PermissionService { - constructor( - @Inject(CASBIN_PROVIDER) private readonly enforcer: casbin.Enforcer - ) {} + constructor(@Inject(CASBIN_PROVIDER) private readonly enforcer: casbin.Enforcer) {} /** requestingUser must be an owner themselves */ async grantOwner(targetUser: string, requestingUser: string, organization: string): Promise {