From eeb80b019a6ed2420d6ba12887da18004c0bb860 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gunnlaugur=20Gu=C3=B0mundsson?= Date: Fri, 4 Oct 2024 13:06:12 +0000 Subject: [PATCH] pr comments fixes --- .../delegation-admin.controller.ts | 21 +++++--------- .../test/delegation-admin.auth.spec.ts | 29 +++++++------------ apps/services/auth/admin-api/src/main.ts | 16 ++++------ libs/auth-api-lib/src/index.ts | 1 + .../dto/zendesk-webhook-input.dto.ts | 8 +++++ libs/infra-nest-server/src/index.ts | 1 + .../src/lib/includeRawBodyMiddleware.ts | 14 +++++++++ 7 files changed, 46 insertions(+), 44 deletions(-) create mode 100644 libs/auth-api-lib/src/lib/delegations/dto/zendesk-webhook-input.dto.ts create mode 100644 libs/infra-nest-server/src/lib/includeRawBodyMiddleware.ts diff --git a/apps/services/auth/admin-api/src/app/v2/delegations/delegation-admin.controller.ts b/apps/services/auth/admin-api/src/app/v2/delegations/delegation-admin.controller.ts index 5cdc8224393a..8d218b31cd26 100644 --- a/apps/services/auth/admin-api/src/app/v2/delegations/delegation-admin.controller.ts +++ b/apps/services/auth/admin-api/src/app/v2/delegations/delegation-admin.controller.ts @@ -9,6 +9,7 @@ import { UseGuards, } from '@nestjs/common' import { ApiTags } from '@nestjs/swagger' +import flatMap from 'lodash/flatMap' import { BypassAuth, @@ -24,11 +25,11 @@ import { DelegationAdminCustomDto, DelegationAdminCustomService, DelegationDTO, + ZendeskWebhookInputDto, } from '@island.is/auth-api-lib' import { Documentation } from '@island.is/nest/swagger' import { Audit, AuditService } from '@island.is/nest/audit' import { DelegationAdminScopes } from '@island.is/auth/scopes' -import flatMap from 'lodash/flatMap' import { isDefined } from '@island.is/shared/utils' const namespace = '@island.is/auth/delegation-admin' @@ -45,8 +46,8 @@ export class DelegationAdminController { private readonly auditService: AuditService, ) {} - @Scopes(DelegationAdminScopes.read) @Get() + @Scopes(DelegationAdminScopes.read) @Documentation({ response: { status: 200, type: DelegationAdminCustomDto }, request: { @@ -97,22 +98,14 @@ export class DelegationAdminController { @BypassAuth() @UseGuards(ZendeskAuthGuard(ZENDESK_WEBHOOK_SECRET_GENERAL_MANDATE)) - @Post(':zendeskId') + @Post('/zendesk') @Documentation({ - response: { status: 201, type: DelegationDTO }, - request: { - params: { - zendeskId: { - required: true, - description: 'The id of the zendesk ticket containing the delegation', - }, - }, - }, + response: { status: 200, type: DelegationDTO }, }) createByZendeskId( - @Param('zendeskId') zendeskId: string, + @Body() { id }: ZendeskWebhookInputDto, ): Promise { - return this.delegationAdminService.createDelegationByZendeskId(zendeskId) + return this.delegationAdminService.createDelegationByZendeskId(id) } @Delete(':delegationId') diff --git a/apps/services/auth/admin-api/src/app/v2/delegations/test/delegation-admin.auth.spec.ts b/apps/services/auth/admin-api/src/app/v2/delegations/test/delegation-admin.auth.spec.ts index db6293c0a689..f4943d43c822 100644 --- a/apps/services/auth/admin-api/src/app/v2/delegations/test/delegation-admin.auth.spec.ts +++ b/apps/services/auth/admin-api/src/app/v2/delegations/test/delegation-admin.auth.spec.ts @@ -16,6 +16,7 @@ import { DelegationDTO, SequelizeConfigService } from '@island.is/auth-api-lib' import { DelegationAdminCustomService } from '@island.is/auth-api-lib' import { AppModule } from '../../../app.module' +import { includeRawBodyMiddleware } from '@island.is/infra-nest-server' describe('withoutAuth and permissions', () => { async function formatUrl(app: TestApp, endpoint: string, user?: User) { @@ -147,17 +148,7 @@ describe('withoutAuth and permissions', () => { dbType: 'postgres', beforeServerStart: async (app) => { await new Promise((resolve) => - resolve( - app.use( - bodyParser.json({ - verify: (req: any, res, buf) => { - if (buf && buf.length) { - req.rawBody = buf - } - }, - }), - ), - ), + resolve(app.use(includeRawBodyMiddleware())), ) }, }) @@ -175,14 +166,14 @@ describe('withoutAuth and permissions', () => { app.cleanUp() }) - it('POST /delegation-admin/:zendeskId should return 403 Forbidden when user does not have correct headers for the body', async () => { + it('POST /delegation-admin/zendesk should return 403 Forbidden when request signature is invalid.', async () => { // Act const res = await getRequestMethod( server, 'POST', - )('/delegation-admin/123') + )('/delegation-admin/zendesk') .send({ - custom: 'Incorrect body', + id: 'Incorrect body', }) .set( 'x-zendesk-webhook-signature', @@ -200,23 +191,23 @@ describe('withoutAuth and permissions', () => { }) }) - it('POST /delegation-admin/:zendeskId should return 201 since the correct headers are set for that body', async () => { + it('POST /delegation-admin/zendesk should return 201 when signature is valid', async () => { // Act const res = await getRequestMethod( server, 'POST', - )('/delegation-admin/123') + )('/delegation-admin/zendesk') .send({ - custom: 'test', + id: 'test', }) .set( 'x-zendesk-webhook-signature', - '6sUtGV8C8OdoGgCdsV2xRm3XeskZ33Bc5124RiAK4Q4=', + 'ntgS06VGgd4z73lHjIpC2sk9azhRNi4u1xkXF/KPKTs=', ) .set('x-zendesk-webhook-signature-timestamp', '2024-10-02T14:21:04Z') // Assert - expect(res.status).toEqual(201) + expect(res.status).toEqual(200) }) }) }) diff --git a/apps/services/auth/admin-api/src/main.ts b/apps/services/auth/admin-api/src/main.ts index 03919e51b2e6..69bcbf501c32 100644 --- a/apps/services/auth/admin-api/src/main.ts +++ b/apps/services/auth/admin-api/src/main.ts @@ -1,9 +1,11 @@ -import { bootstrap } from '@island.is/infra-nest-server' +import { + bootstrap, + includeRawBodyMiddleware, +} from '@island.is/infra-nest-server' import { AppModule } from './app/app.module' import { environment as env } from './environments' import { openApi } from './openApi' -import bodyParser from 'body-parser' bootstrap({ appModule: AppModule, @@ -16,14 +18,6 @@ bootstrap({ database: true, }, beforeServerStart: async (app) => { - app.use( - bodyParser.json({ - verify: (req: any, res, buf) => { - if (buf && buf.length) { - req.rawBody = buf - } - }, - }), - ) + app.use(includeRawBodyMiddleware()) }, }) diff --git a/libs/auth-api-lib/src/index.ts b/libs/auth-api-lib/src/index.ts index b9305d456101..28b1b0007819 100644 --- a/libs/auth-api-lib/src/index.ts +++ b/libs/auth-api-lib/src/index.ts @@ -47,6 +47,7 @@ export * from './lib/delegations/dto/delegation-index.dto' export * from './lib/delegations/dto/paginated-delegation-provider.dto' export * from './lib/delegations/dto/delegation-provider.dto' export * from './lib/delegations/dto/merged-delegation.dto' +export * from './lib/delegations/dto/zendesk-webhook-input.dto' export * from './lib/delegations/models/delegation.model' export * from './lib/delegations/models/delegation.model' export * from './lib/delegations/models/delegation-scope.model' diff --git a/libs/auth-api-lib/src/lib/delegations/dto/zendesk-webhook-input.dto.ts b/libs/auth-api-lib/src/lib/delegations/dto/zendesk-webhook-input.dto.ts new file mode 100644 index 000000000000..31d71c17ccad --- /dev/null +++ b/libs/auth-api-lib/src/lib/delegations/dto/zendesk-webhook-input.dto.ts @@ -0,0 +1,8 @@ +import { IsString } from 'class-validator' +import { ApiProperty } from '@nestjs/swagger' + +export class ZendeskWebhookInputDto { + @IsString() + @ApiProperty() + id!: string +} diff --git a/libs/infra-nest-server/src/index.ts b/libs/infra-nest-server/src/index.ts index e6a5847c8151..6fe69a8ae2bd 100644 --- a/libs/infra-nest-server/src/index.ts +++ b/libs/infra-nest-server/src/index.ts @@ -3,5 +3,6 @@ export * from './lib/buildOpenApi' export * from './lib/infra/infra.controller' export { InfraModule } from './lib/infra/infra.module' export { HealthCheckOptions } from './lib/infra/health/types' +export * from './lib/includeRawBodyMiddleware' export * from './lib/processJob' export * from './lib/types' diff --git a/libs/infra-nest-server/src/lib/includeRawBodyMiddleware.ts b/libs/infra-nest-server/src/lib/includeRawBodyMiddleware.ts new file mode 100644 index 000000000000..d059a4462ffb --- /dev/null +++ b/libs/infra-nest-server/src/lib/includeRawBodyMiddleware.ts @@ -0,0 +1,14 @@ +import bodyParser from 'body-parser' + +/** + * Middleware that includes the raw body in the request object. + */ +export const includeRawBodyMiddleware = () => { + return bodyParser.json({ + verify: (req: any, res, buf) => { + if (buf && buf.length) { + req.rawBody = buf + } + }, + }) +}