From 7471b09886e4de248d056076e892d207b4adb3a4 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Mon, 9 Jun 2025 21:08:07 +0200 Subject: [PATCH 1/9] Add swagger API documentation setup --- src/main.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/src/main.ts b/src/main.ts index 30717c7..9a88d3a 100644 --- a/src/main.ts +++ b/src/main.ts @@ -5,6 +5,7 @@ import * as process from 'node:process'; import Redis from 'ioredis'; import { RedisStore } from 'connect-redis'; import * as passport from 'passport'; +import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; async function bootstrap() { const app = await NestFactory.create(AppModule); @@ -26,6 +27,27 @@ async function bootstrap() { app.use(passport.initialize()); app.use(passport.session()); + // Swagger API documentation setup + if (process.env.NODE_ENV !== 'production') { + const config = new DocumentBuilder() + .setTitle('MotiMate API') + .setDescription('API documentation for the MotiMate backend') + .setVersion('1.0') + .addBearerAuth( + { + type: 'http', + scheme: 'bearer', + bearerFormat: 'JWT', + in: 'header', + description: 'Enter your JWT token here', + }, + 'access-token', + ) + .build(); + const document = SwaggerModule.createDocument(app, config); + SwaggerModule.setup('api', app, document); + } + await app.listen(process.env.PORT ?? 3000); } From b00959eca20917c3b6904db735cc9271524202f7 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Tue, 10 Jun 2025 23:04:05 +0200 Subject: [PATCH 2/9] Add global validation pipe --- src/main.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/main.ts b/src/main.ts index 9a88d3a..2149ce0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -6,9 +6,23 @@ import Redis from 'ioredis'; import { RedisStore } from 'connect-redis'; import * as passport from 'passport'; import { SwaggerModule, DocumentBuilder } from '@nestjs/swagger'; +import { ValidationPipe } from '@nestjs/common'; async function bootstrap() { const app = await NestFactory.create(AppModule); + + // Global validation pipe + app.useGlobalPipes( + new ValidationPipe({ + transform: true, + whitelist: true, + forbidNonWhitelisted: true, + transformOptions: { + enableImplicitConversion: true, + }, + }), + ); + app.use( session({ secret: process.env.SESSION_SECRET as string, From aa08ee03e42ed47e09e08694359e191f25bd2422 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 10:47:48 +0200 Subject: [PATCH 3/9] Add API documentation for CreateGroupDto --- src/group/dto/create-group.dto.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/group/dto/create-group.dto.ts b/src/group/dto/create-group.dto.ts index 491ad55..d347588 100644 --- a/src/group/dto/create-group.dto.ts +++ b/src/group/dto/create-group.dto.ts @@ -1,10 +1,22 @@ import { IsNotEmpty, IsString, IsOptional, IsArray } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; export class CreateGroupDto { + @ApiProperty({ + description: 'The name of the group', + example: 'Fitness Enthusiasts', + maxLength: 100, + type: String, + }) @IsNotEmpty() @IsString() groupName: string; + @ApiProperty({ + description: 'The ids of the members to be added to the group', + example: ['user123', 'user456'], + type: [String], + }) @IsOptional() @IsArray() @IsString({ each: true }) From 740ff91aff45c5f553b8fd788ef1c4655eaff923 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 11:20:21 +0200 Subject: [PATCH 4/9] Add API documentation for user input --- src/auth/dto/register-user.input.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/auth/dto/register-user.input.ts b/src/auth/dto/register-user.input.ts index 2f6da87..669636f 100644 --- a/src/auth/dto/register-user.input.ts +++ b/src/auth/dto/register-user.input.ts @@ -1,5 +1,33 @@ +import { ApiProperty } from '@nestjs/swagger'; +import { IsEmail, IsString, MinLength, IsNotEmpty } from 'class-validator'; + export class RegisterUserDto { + @ApiProperty({ + description: 'The username of the user', + example: 'john_doe', + }) + @IsNotEmpty() + @IsString() username: string; + + @ApiProperty({ + description: 'The email address of the user', + example: 'john.doe@email.com', + uniqueItems: true, + }) + @IsEmail() + @IsNotEmpty() + @IsString() email: string; + + @ApiProperty({ + description: 'The password for the user account', + example: 'S3cureP@ssw0rd!', + minLength: 8, + maxLength: 128, + }) + @IsNotEmpty() + @IsString() + @MinLength(8) password: string; } From a28c7c963c12b844dfa23e63db4e45ec30ab7c4e Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 11:33:24 +0200 Subject: [PATCH 5/9] Add API documentation for ChallengeDTO --- src/auth/dto/challenge.dto.ts | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/auth/dto/challenge.dto.ts b/src/auth/dto/challenge.dto.ts index a2d6e95..6182478 100644 --- a/src/auth/dto/challenge.dto.ts +++ b/src/auth/dto/challenge.dto.ts @@ -1,7 +1,21 @@ import { Challenge } from '../entities/challenge.entity'; +import { ApiProperty } from '@nestjs/swagger'; export class ChallengeDTO { + @ApiProperty({ + description: 'The challenge string for WebAuthn registration', + example: 'dGhpcyBpcyBhIHNhbXBsZSBjaGFsbGVuZ2U=', + type: String, + required: true, + }) challenge: string; + + @ApiProperty({ + description: 'The expiration date of the challenge', + example: '2024-10-01T12:00:00Z', + type: Date, + required: true, + }) expiresAt: Date; constructor(challenge: Challenge) { From 274067fdfd80e522a4372570b3155b65f8818ba0 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 13:09:54 +0200 Subject: [PATCH 6/9] Install class-transformer --- package-lock.json | 7 +++++++ package.json | 1 + 2 files changed, 8 insertions(+) diff --git a/package-lock.json b/package-lock.json index adcfcde..43a1390 100644 --- a/package-lock.json +++ b/package-lock.json @@ -19,6 +19,7 @@ "@simplewebauthn/server": "^9.0.3", "@supabase/supabase-js": "^2.49.4", "argon2": "^0.41.1", + "class-transformer": "^0.5.1", "class-validator": "^0.14.2", "connect-redis": "^8.0.1", "express-session": "^1.18.1", @@ -5145,6 +5146,12 @@ "dev": true, "license": "MIT" }, + "node_modules/class-transformer": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz", + "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==", + "license": "MIT" + }, "node_modules/class-validator": { "version": "0.14.2", "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.2.tgz", diff --git a/package.json b/package.json index a9bcdf2..4785635 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@simplewebauthn/server": "^9.0.3", "@supabase/supabase-js": "^2.49.4", "argon2": "^0.41.1", + "class-transformer": "^0.5.1", "class-validator": "^0.14.2", "connect-redis": "^8.0.1", "express-session": "^1.18.1", From 1c9c73850abbc2c83cdce23487b81adcb701f8b6 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 13:47:24 +0200 Subject: [PATCH 7/9] Add API documentation to create and update user DTOs --- src/user/dto/create-user.dto.ts | 34 +++++++++++++++++++++++++++++++-- src/user/dto/update-user.dto.ts | 32 +++++++++++++++++++++++++++++-- 2 files changed, 62 insertions(+), 4 deletions(-) diff --git a/src/user/dto/create-user.dto.ts b/src/user/dto/create-user.dto.ts index bc9d2f2..1c4d0a4 100644 --- a/src/user/dto/create-user.dto.ts +++ b/src/user/dto/create-user.dto.ts @@ -1,12 +1,42 @@ -import { IsEmail, IsNotEmpty, MinLength } from 'class-validator'; +import { IsEmail, IsNotEmpty, MinLength, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + export class CreateUserDto { + @ApiProperty({ + description: 'The name of the user', + example: 'John Doe', + required: true, + type: String, + minLength: 1, + maxLength: 255, + pattern: '^[a-zA-Z0-9 ]+$', // Allows alphanumeric characters and spaces + }) @IsNotEmpty() name: string; + @ApiProperty({ + description: 'The email of the user', + example: 'john.doe@email.com', + required: true, + type: String, + format: 'email', + pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$', // Basic email validation + }) @IsEmail() + @IsString() + @IsNotEmpty() email: string; + @ApiProperty({ + description: 'The password of the user', + example: 'S3cureP@ssw0rd!', + required: true, + type: String, + minLength: 8, + maxLength: 128, + }) + @IsString() @IsNotEmpty() - @MinLength(6) //Confirm the minlength we are using + @MinLength(8) password: string; } diff --git a/src/user/dto/update-user.dto.ts b/src/user/dto/update-user.dto.ts index 7dac3d8..38e7999 100644 --- a/src/user/dto/update-user.dto.ts +++ b/src/user/dto/update-user.dto.ts @@ -1,13 +1,41 @@ -import { IsEmail, IsOptional, MinLength } from 'class-validator'; +import { IsEmail, IsOptional, MinLength, IsString } from 'class-validator'; +import { ApiProperty } from '@nestjs/swagger'; + export class UpdateUserDto { + @ApiProperty({ + description: 'The name of the user', + example: 'John Doe', + required: false, + type: String, + minLength: 1, + maxLength: 255, + pattern: '^[a-zA-Z0-9 ]+$', // Allows alphanumeric characters and spaces + }) + @IsString() @IsOptional() name?: string; + @ApiProperty({ + description: 'The email of the user', + example: 'john.doe@email.com', + required: false, + type: String, + format: 'email', + pattern: '^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$', // Basic email validation + }) @IsOptional() @IsEmail() email?: string; + @ApiProperty({ + description: 'The password of the user', + example: 'S3cureP@ssw0rd!', + required: false, + type: String, + minLength: 8, + maxLength: 128, + }) @IsOptional() - @MinLength(6) + @MinLength(8) password?: string; } From aebd7175f9b9df5f316c953a6e54b6d3b31bab8e Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 13:50:58 +0200 Subject: [PATCH 8/9] Change max password length & exclude it from serialization --- src/user/entities/user.entity.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/user/entities/user.entity.ts b/src/user/entities/user.entity.ts index 566e3d6..3432c26 100644 --- a/src/user/entities/user.entity.ts +++ b/src/user/entities/user.entity.ts @@ -15,6 +15,7 @@ import { UserWeeklyTarget } from '../../user-weekly-target/entities/user-weekly- import { Group } from '../../group/entities/group.entity'; import { PasskeyEntity } from '../../auth/entities/passkey.entity'; import { Challenge } from '../../auth/entities/challenge.entity'; +import { Exclude } from 'class-transformer'; @Entity() @Unique(['email']) @@ -32,7 +33,9 @@ export class User { @Column() account_status: boolean; - @Column({ length: 255, nullable: false }) + @Column({ length: 128, nullable: false }) + // eslint-disable-next-line @typescript-eslint/no-unsafe-call + @Exclude({ toPlainOnly: true }) // Exclude password from serialization password: string; @Column({ length: 255 }) From a7d89b66be7c1e742f88116c35ca9efd8ca6a280 Mon Sep 17 00:00:00 2001 From: Till1983 Date: Thu, 12 Jun 2025 21:51:18 +0200 Subject: [PATCH 9/9] Remove comment from password column --- src/user/entities/user.entity.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/src/user/entities/user.entity.ts b/src/user/entities/user.entity.ts index 3432c26..eb2dc40 100644 --- a/src/user/entities/user.entity.ts +++ b/src/user/entities/user.entity.ts @@ -34,7 +34,6 @@ export class User { account_status: boolean; @Column({ length: 128, nullable: false }) - // eslint-disable-next-line @typescript-eslint/no-unsafe-call @Exclude({ toPlainOnly: true }) // Exclude password from serialization password: string;