From d1e7c654af41bb3ca84608b79169ef31b494db47 Mon Sep 17 00:00:00 2001 From: Anand Chowdhary Date: Tue, 17 Nov 2020 12:10:45 +0530 Subject: [PATCH] :bug: Remove unauthorized scopes from API keys --- src/modules/api-keys/api-keys.service.ts | 25 +++++++++++++++++++ src/modules/memberships/memberships.module.ts | 14 ++++++++--- .../memberships/memberships.service.ts | 10 +++++++- 3 files changed, 45 insertions(+), 4 deletions(-) diff --git a/src/modules/api-keys/api-keys.service.ts b/src/modules/api-keys/api-keys.service.ts index 6a6b9570f..2f31374a2 100644 --- a/src/modules/api-keys/api-keys.service.ts +++ b/src/modules/api-keys/api-keys.service.ts @@ -279,6 +279,31 @@ export class ApiKeysService { return this.getApiLogsFromKey(testApiKey.apiKey, params); } + /** + * Remove any unauthorized scopes in an API key for a user + * This should run when a user's permissions have changed, for example + * if they are removed from a group; this will remove any API scopes + * they don't have access to anymore from that API key + */ + async removeUnauthorizedScopesForUser(userId: number): Promise { + const userApiKeys = await this.prisma.apiKeys.findMany({ + where: { user: { id: userId } }, + }); + if (!userApiKeys.length) return; + const scopesAllowed = await this.getApiKeyScopesForUser(userId); + for await (const apiKey of userApiKeys) { + const currentScopes = (apiKey.scopes ?? []) as string[]; + const newScopes = currentScopes.filter((i) => + Object.keys(scopesAllowed).includes(i), + ); + if (currentScopes.length !== newScopes.length) + this.prisma.apiKeys.update({ + where: { id: apiKey.id }, + data: { scopes: newScopes }, + }); + } + } + private async getApiLogsFromKey( apiKey: string, params: { diff --git a/src/modules/memberships/memberships.module.ts b/src/modules/memberships/memberships.module.ts index bcd76172b..c7cac4d3e 100644 --- a/src/modules/memberships/memberships.module.ts +++ b/src/modules/memberships/memberships.module.ts @@ -1,15 +1,23 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; -import { AuthModule } from '../auth/auth.module'; import { MailModule } from '../../providers/mail/mail.module'; import { PrismaModule } from '../../providers/prisma/prisma.module'; +import { ApiKeysModule } from '../api-keys/api-keys.module'; +import { AuthModule } from '../auth/auth.module'; +import { GroupsModule } from '../groups/groups.module'; import { GroupMembershipController } from './memberships-group.controller'; import { UserMembershipController } from './memberships-user.controller'; import { MembershipsService } from './memberships.service'; -import { GroupsModule } from '../groups/groups.module'; @Module({ - imports: [PrismaModule, MailModule, ConfigModule, AuthModule, GroupsModule], + imports: [ + PrismaModule, + MailModule, + ConfigModule, + AuthModule, + GroupsModule, + ApiKeysModule, + ], controllers: [UserMembershipController, GroupMembershipController], providers: [MembershipsService], }) diff --git a/src/modules/memberships/memberships.service.ts b/src/modules/memberships/memberships.service.ts index 10f2f535b..181c03994 100644 --- a/src/modules/memberships/memberships.service.ts +++ b/src/modules/memberships/memberships.service.ts @@ -25,6 +25,7 @@ import { safeEmail } from '../../helpers/safe-email'; import { MailService } from '../../providers/mail/mail.service'; import { Expose } from '../../providers/prisma/prisma.interface'; import { PrismaService } from '../../providers/prisma/prisma.service'; +import { ApiKeysService } from '../api-keys/api-keys.service'; import { AuthService } from '../auth/auth.service'; import { GroupsService } from '../groups/groups.service'; import { CreateMembershipInput } from './memberships.interface'; @@ -37,6 +38,7 @@ export class MembershipsService { private email: MailService, private configService: ConfigService, private groupsService: GroupsService, + private apiKeyService: ApiKeysService, ) {} async getMemberships(params: { @@ -100,6 +102,7 @@ export class MembershipsService { const membership = await this.prisma.memberships.delete({ where: { id }, }); + await this.apiKeyService.removeUnauthorizedScopesForUser(userId); return this.prisma.expose(membership); } @@ -128,6 +131,9 @@ export class MembershipsService { data, include: { user: true }, }); + await this.apiKeyService.removeUnauthorizedScopesForUser( + testMembership.userId, + ); return this.prisma.expose(membership); } @@ -146,9 +152,11 @@ export class MembershipsService { where: { id }, include: { user: true }, }); + await this.apiKeyService.removeUnauthorizedScopesForUser( + testMembership.userId, + ); return this.prisma.expose(membership); } - async createUserMembership(userId: number, data: groupsCreateInput) { const created = await this.groupsService.createGroup(userId, data); return created.memberships[0];