diff --git a/apps/backend/package.json b/apps/backend/package.json index 9831a77..a6a4843 100644 --- a/apps/backend/package.json +++ b/apps/backend/package.json @@ -25,7 +25,9 @@ "@my-monorepo/common": "workspace:*", "@nestjs/common": "^11.0.1", "@nestjs/core": "^11.0.1", + "@nestjs/passport": "^11.0.5", "@nestjs/platform-express": "^11.0.1", + "@types/passport-local": "^1.0.38", "dayjs": "^1.11.13", "dotenv": "^17.2.1", "ejs": "^3.1.10", @@ -33,6 +35,8 @@ "i18next-fs-backend": "^2.6.0", "kysely": "^0.28.3", "nodemailer": "^7.0.5", + "passport": "^0.7.0", + "passport-local": "^1.0.0", "pg": "^8.16.3", "reflect-metadata": "^0.2.2", "rxjs": "^7.8.1", diff --git a/apps/backend/src/app.module.ts b/apps/backend/src/app.module.ts index 263465c..bf6f3d6 100644 --- a/apps/backend/src/app.module.ts +++ b/apps/backend/src/app.module.ts @@ -1,27 +1,9 @@ import { Module } from '@nestjs/common'; -import { AuthController } from './app/auth/auth.controller'; -import { DatabaseService } from './services/database/database.service'; -import { AuthService } from './app/auth/auth.service'; -import { UsersService } from './app/users/users.service'; -import { EnvService } from './services/env/env.service'; -import { UsersRegistry } from './app/users/users-registry'; -import { UsersController } from './app/users/users.controller'; -import { MailerService } from './services/mailer/mailer.service'; -import { LOCALIZATION_SERVICE_PROVIDER } from './services/localization/localization.service'; -import { TemplateRendererService } from './services/template-renderer/template-renderer.service'; +import { AuthModule } from './app/auth/auth.module'; +import { UsersModule } from './app/users/users.module'; +import { CoreModule } from './services/core/core.module'; @Module({ - imports: [], - controllers: [AuthController, UsersController], - providers: [ - DatabaseService, - AuthService, - UsersService, - EnvService, - UsersRegistry, - MailerService, - LOCALIZATION_SERVICE_PROVIDER, - TemplateRendererService, - ], + imports: [CoreModule, AuthModule, UsersModule], }) export class AppModule {} diff --git a/apps/backend/src/app/auth/auth-controller.service.spec.ts b/apps/backend/src/app/auth/auth-controller.service.spec.ts new file mode 100644 index 0000000..ab3ab3e --- /dev/null +++ b/apps/backend/src/app/auth/auth-controller.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { AuthControllerService } from './auth-controller.service'; + +describe('AuthControllerService', () => { + let service: AuthControllerService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [AuthControllerService], + }).compile(); + + service = module.get(AuthControllerService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/apps/backend/src/app/auth/auth-controller.service.ts b/apps/backend/src/app/auth/auth-controller.service.ts new file mode 100644 index 0000000..e002a0a --- /dev/null +++ b/apps/backend/src/app/auth/auth-controller.service.ts @@ -0,0 +1,14 @@ +import { Injectable, UnauthorizedException } from '@nestjs/common'; +import { UsersCoreService } from '../users/users-core.service'; + +@Injectable() +export class AuthControllerService { + constructor(private userCoreService: UsersCoreService) {} + + async verifyCredentials() { + const isValidCredential = await this.userCoreService.existsEmailPassword(); + if (!isValidCredential) { + throw new UnauthorizedException('invalid credentials'); + } + } +} diff --git a/apps/backend/src/app/users/users.service.spec.ts b/apps/backend/src/app/auth/auth-core.service.spec.ts similarity index 53% rename from apps/backend/src/app/users/users.service.spec.ts rename to apps/backend/src/app/auth/auth-core.service.spec.ts index 62815ba..2afddfd 100644 --- a/apps/backend/src/app/users/users.service.spec.ts +++ b/apps/backend/src/app/auth/auth-core.service.spec.ts @@ -1,15 +1,15 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { UsersService } from './users.service'; +import { AuthCoreService } from './auth-core.service'; -describe('UsersService', () => { - let service: UsersService; +describe('AuthCoreService', () => { + let service: AuthCoreService; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [UsersService], + providers: [AuthCoreService], }).compile(); - service = module.get(UsersService); + service = module.get(AuthCoreService); }); it('should be defined', () => { diff --git a/apps/backend/src/app/auth/auth-core.service.ts b/apps/backend/src/app/auth/auth-core.service.ts new file mode 100644 index 0000000..3ec9207 --- /dev/null +++ b/apps/backend/src/app/auth/auth-core.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@nestjs/common'; +import { AuthRegistry } from './auth-registry'; +import { generateSecureToken } from '../../lib/crypto'; +import * as dayjs from 'dayjs'; + +const RESET_TOKEN_VALIDITY_MINUTES = 15; + +@Injectable() +export class AuthCoreService { + constructor(private authRegistry: AuthRegistry) {} + + async addNewResetToken(userId: string): Promise { + return this.authRegistry.addResetToken({ + token: generateSecureToken(), + userId, + validUntil: dayjs().add(RESET_TOKEN_VALIDITY_MINUTES, 'minutes'), + }); + } +} diff --git a/apps/backend/src/app/auth/auth.service.spec.ts b/apps/backend/src/app/auth/auth-registry.spec.ts similarity index 56% rename from apps/backend/src/app/auth/auth.service.spec.ts rename to apps/backend/src/app/auth/auth-registry.spec.ts index 800ab66..19498c3 100644 --- a/apps/backend/src/app/auth/auth.service.spec.ts +++ b/apps/backend/src/app/auth/auth-registry.spec.ts @@ -1,15 +1,15 @@ import { Test, TestingModule } from '@nestjs/testing'; -import { AuthService } from './auth.service'; +import { AuthRegistry } from './auth-registry'; -describe('AuthService', () => { - let service: AuthService; +describe('AuthRegistry', () => { + let service: AuthRegistry; beforeEach(async () => { const module: TestingModule = await Test.createTestingModule({ - providers: [AuthService], + providers: [AuthRegistry], }).compile(); - service = module.get(AuthService); + service = module.get(AuthRegistry); }); it('should be defined', () => { diff --git a/apps/backend/src/app/auth/auth-registry.ts b/apps/backend/src/app/auth/auth-registry.ts new file mode 100644 index 0000000..60375b0 --- /dev/null +++ b/apps/backend/src/app/auth/auth-registry.ts @@ -0,0 +1,29 @@ +import { Injectable } from '@nestjs/common'; +import { DatabaseService } from '../../services/core/database/database.service'; +import * as dayjs from 'dayjs'; + +export interface CreateResetToken { + userId: string; + token: string; + validUntil: dayjs.Dayjs; +} + +@Injectable() +export class AuthRegistry { + get database() { + return this.databaseService.database; + } + constructor(private databaseService: DatabaseService) {} + + async addResetToken(resetAuth: CreateResetToken): Promise { + return this.database + .insertInto('reset_tokens') + .values({ + user_id: resetAuth.userId, + token: resetAuth.token, + valid_until: resetAuth.validUntil.toDate(), + }) + .execute() + .then(() => {}); + } +} diff --git a/apps/backend/src/app/auth/auth.controller.ts b/apps/backend/src/app/auth/auth.controller.ts index 8db7df3..e65aec8 100644 --- a/apps/backend/src/app/auth/auth.controller.ts +++ b/apps/backend/src/app/auth/auth.controller.ts @@ -1,12 +1,26 @@ -import { Controller, Post } from '@nestjs/common'; -import { AuthService } from './auth.service'; +import { + Body, + Controller, + NotImplementedException, + Post, +} from '@nestjs/common'; +import { AuthControllerService } from './auth-controller.service'; +import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe'; +import { ResetAuth, resetAuthParser } from '@my-monorepo/common'; @Controller('auth') export class AuthController { - constructor(private authService: AuthService) {} + constructor(private authService: AuthControllerService) {} @Post('credentials') async postCredentials() { return this.authService.verifyCredentials(); } + + @Post('reset') + async postReset( + @Body(new ZodValidationPipe(resetAuthParser)) resetData: ResetAuth, + ): Promise { + throw new NotImplementedException(); + } } diff --git a/apps/backend/src/app/auth/auth.module.ts b/apps/backend/src/app/auth/auth.module.ts new file mode 100644 index 0000000..e5668b0 --- /dev/null +++ b/apps/backend/src/app/auth/auth.module.ts @@ -0,0 +1,14 @@ +import { Module } from '@nestjs/common'; +import { AuthController } from './auth.controller'; +import { AuthRegistry } from './auth-registry'; +import { AuthControllerService } from './auth-controller.service'; +import { AuthCoreService } from './auth-core.service'; +import { UsersModule } from '../users/users.module'; + +@Module({ + controllers: [AuthController], + providers: [AuthRegistry, AuthControllerService, AuthCoreService], + imports: [UsersModule], + exports: [AuthCoreService, AuthRegistry], +}) +export class AuthModule {} diff --git a/apps/backend/src/app/auth/auth.service.ts b/apps/backend/src/app/auth/auth.service.ts deleted file mode 100644 index 0702160..0000000 --- a/apps/backend/src/app/auth/auth.service.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { UsersRegistry } from '../users/users-registry'; - -@Injectable() -export class AuthService { - constructor(private userRegistry: UsersRegistry) {} - - async verifyCredentials() { - const isValidCredential = await this.userRegistry.existsEmailPassword( - '', - '', - ); - if (!isValidCredential) { - throw new UnauthorizedException('invalid credentials'); - } - } -} diff --git a/apps/backend/src/app/users/users-controller.service.spec.ts b/apps/backend/src/app/users/users-controller.service.spec.ts new file mode 100644 index 0000000..00d3e59 --- /dev/null +++ b/apps/backend/src/app/users/users-controller.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsersControllerService } from './users-controller.service'; + +describe('UsersControllerService', () => { + let service: UsersControllerService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [UsersControllerService], + }).compile(); + + service = module.get(UsersControllerService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/apps/backend/src/app/users/users.service.ts b/apps/backend/src/app/users/users-controller.service.ts similarity index 56% rename from apps/backend/src/app/users/users.service.ts rename to apps/backend/src/app/users/users-controller.service.ts index 9e75fa5..927c471 100644 --- a/apps/backend/src/app/users/users.service.ts +++ b/apps/backend/src/app/users/users-controller.service.ts @@ -1,27 +1,33 @@ import { CreateUser } from '@my-monorepo/common'; import { Inject, Injectable } from '@nestjs/common'; -import { MailerService } from '../../services/mailer/mailer.service'; -import { UsersRegistry } from './users-registry'; import { LOCALIZATION_SERVICE, LocalizationService, -} from '../../services/localization/localization.service'; -import { TemplateRendererService } from '../../services/template-renderer/template-renderer.service'; -import { MailTemplateEnum } from '../../services/template-renderer/mail-template-data'; +} from '../../services/core/localization/localization.service'; +import { MailerService } from '../../services/core/mailer/mailer.service'; +import { MailTemplateEnum } from '../../services/core/template-renderer/mail-template-data'; +import { TemplateRendererService } from '../../services/core/template-renderer/template-renderer.service'; +import { AuthCoreService } from '../auth/auth-core.service'; +import { UsersCoreService } from './users-core.service'; @Injectable() -export class UsersService { +export class UsersControllerService { constructor( - private userRegistry: UsersRegistry, + private userCoreService: UsersCoreService, private mailerService: MailerService, @Inject(LOCALIZATION_SERVICE) private localizationService: LocalizationService, private templateRendererService: TemplateRendererService, + private authCoreService: AuthCoreService, ) {} async createUser(newUser: CreateUser): Promise { // FIXME : return result once auth is done - await this.userRegistry.addUser(newUser); + const createUserResult = await this.userCoreService.addUser(newUser); + if (createUserResult.ok) { + const createdUser = createUserResult.data; + await this.authCoreService.addNewResetToken(createdUser.id); + } const mailTitle = this.localizationService.translate( 'mail.create-user.title', diff --git a/apps/backend/src/app/users/users-core.service.spec.ts b/apps/backend/src/app/users/users-core.service.spec.ts new file mode 100644 index 0000000..3d246ef --- /dev/null +++ b/apps/backend/src/app/users/users-core.service.spec.ts @@ -0,0 +1,18 @@ +import { Test, TestingModule } from '@nestjs/testing'; +import { UsersCoreService } from './users-core.service'; + +describe('UsersCoreService', () => { + let service: UsersCoreService; + + beforeEach(async () => { + const module: TestingModule = await Test.createTestingModule({ + providers: [UsersCoreService], + }).compile(); + + service = module.get(UsersCoreService); + }); + + it('should be defined', () => { + expect(service).toBeDefined(); + }); +}); diff --git a/apps/backend/src/app/users/users-core.service.ts b/apps/backend/src/app/users/users-core.service.ts new file mode 100644 index 0000000..27e4d75 --- /dev/null +++ b/apps/backend/src/app/users/users-core.service.ts @@ -0,0 +1,19 @@ +import { Injectable } from '@nestjs/common'; +import { UsersRegistry } from './users-registry'; +import { CreateUser, Result, User } from '@my-monorepo/common'; +import { UserEmailAlreadyExistError } from './users-error'; + +@Injectable() +export class UsersCoreService { + constructor(private userRegistry: UsersRegistry) {} + + async existsEmailPassword() { + return await this.userRegistry.existsEmailPassword('', ''); + } + + async addUser( + newUser: CreateUser, + ): Promise> { + return await this.userRegistry.addUser(newUser); + } +} diff --git a/apps/backend/src/app/users/users-registry.ts b/apps/backend/src/app/users/users-registry.ts index 6d4dd12..935fb40 100644 --- a/apps/backend/src/app/users/users-registry.ts +++ b/apps/backend/src/app/users/users-registry.ts @@ -1,5 +1,5 @@ import { Injectable } from '@nestjs/common'; -import { DatabaseService } from '../../services/database/database.service'; +import { DatabaseService } from '../../services/core/database/database.service'; import { CreateUser, isDefined, Result, User } from '@my-monorepo/common'; import { UserEmailAlreadyExistError } from './users-error'; diff --git a/apps/backend/src/app/users/users.controller.ts b/apps/backend/src/app/users/users.controller.ts index 6035100..a975b83 100644 --- a/apps/backend/src/app/users/users.controller.ts +++ b/apps/backend/src/app/users/users.controller.ts @@ -1,15 +1,16 @@ import { CreateUser, createUserParser } from '@my-monorepo/common'; -import { Body, Controller, Post, UsePipes } from '@nestjs/common'; +import { Body, Controller, Post } from '@nestjs/common'; import { ZodValidationPipe } from '../../lib/nestjs/zod-validation/zod-validation.pipe'; -import { UsersService } from './users.service'; +import { UsersControllerService } from './users-controller.service'; @Controller('users') export class UsersController { - constructor(private userService: UsersService) {} + constructor(private userService: UsersControllerService) {} @Post() - @UsePipes(new ZodValidationPipe(createUserParser)) - async createUser(@Body() newUser: CreateUser) { + async createUser( + @Body(new ZodValidationPipe(createUserParser)) newUser: CreateUser, + ) { return this.userService.createUser(newUser); } } diff --git a/apps/backend/src/app/users/users.module.ts b/apps/backend/src/app/users/users.module.ts new file mode 100644 index 0000000..b57cd41 --- /dev/null +++ b/apps/backend/src/app/users/users.module.ts @@ -0,0 +1,14 @@ +import { forwardRef, Module } from '@nestjs/common'; +import { UsersRegistry } from './users-registry'; +import { UsersController } from './users.controller'; +import { UsersControllerService } from './users-controller.service'; +import { UsersCoreService } from './users-core.service'; +import { AuthModule } from '../auth/auth.module'; + +@Module({ + providers: [UsersRegistry, UsersControllerService, UsersCoreService], + controllers: [UsersController], + imports: [forwardRef(() => AuthModule)], + exports: [UsersCoreService, UsersRegistry], +}) +export class UsersModule {} diff --git a/apps/backend/src/database/db.d.ts b/apps/backend/src/database/db.d.ts index 8693c2e..8cbaa37 100644 --- a/apps/backend/src/database/db.d.ts +++ b/apps/backend/src/database/db.d.ts @@ -13,6 +13,16 @@ export type Int8 = ColumnType; +export interface ResetTokens { + created_at: Generated; + deleted_at: Timestamp | null; + id: Generated; + token: string; + updated_at: Generated; + user_id: Generated; + valid_until: Timestamp; +} + export interface Users { created_at: Generated; deleted_at: Timestamp | null; @@ -25,5 +35,6 @@ export interface Users { } export interface DB { + reset_tokens: ResetTokens; users: Users; } diff --git a/apps/backend/src/lib/crypto.ts b/apps/backend/src/lib/crypto.ts new file mode 100644 index 0000000..03370d6 --- /dev/null +++ b/apps/backend/src/lib/crypto.ts @@ -0,0 +1,5 @@ +import * as crypto from 'crypto'; + +export function generateSecureToken(length = 32) { + return crypto.randomBytes(length).toString('hex'); +} diff --git a/apps/backend/src/migrations/2025-08-07_22-07-35_add_reset_table.ts b/apps/backend/src/migrations/2025-08-07_22-07-35_add_reset_table.ts new file mode 100644 index 0000000..d78d29c --- /dev/null +++ b/apps/backend/src/migrations/2025-08-07_22-07-35_add_reset_table.ts @@ -0,0 +1,33 @@ +import { Kysely, sql } from 'kysely'; + +export async function up(db: Kysely): Promise { + await db.schema + .createTable('reset_tokens') + .addColumn('id', 'bigserial', (col) => col.primaryKey()) + .addColumn('user_id', 'bigserial', (col) => col.notNull()) + .addForeignKeyConstraint( + 'fk_user_id_reset_tokens_users', + ['user_id'], + 'users', + ['id'], + (col) => col.onDelete('cascade'), + ) + .addColumn('token', 'text', (col) => col.notNull()) + .addUniqueConstraint('uniq_user_id_tokens_reset_tokens', [ + 'user_id', + 'token', + ]) + .addColumn('valid_until', 'timestamptz', (col) => col.notNull()) + .addColumn('created_at', 'timestamptz', (col) => + col.notNull().defaultTo(sql`now()`), + ) + .addColumn('updated_at', 'timestamptz', (col) => + col.notNull().defaultTo(sql`now()`), + ) + .addColumn('deleted_at', 'timestamptz') + .execute(); +} + +export async function down(db: Kysely): Promise { + await db.schema.dropTable('reset_tokens').execute(); +} diff --git a/apps/backend/src/services/core/core.module.ts b/apps/backend/src/services/core/core.module.ts new file mode 100644 index 0000000..9a69d31 --- /dev/null +++ b/apps/backend/src/services/core/core.module.ts @@ -0,0 +1,23 @@ +import { Global, Module } from '@nestjs/common'; +import { DatabaseService } from './database/database.service'; +import { EnvService } from './env/env.service'; +import { LOCALIZATION_SERVICE_PROVIDER } from './localization/localization.service'; +import { LoggerService } from './logger/logger.service'; +import { MailerService } from './mailer/mailer.service'; +import { TemplateRendererService } from './template-renderer/template-renderer.service'; + +const DECLARATIONS = [ + DatabaseService, + EnvService, + LOCALIZATION_SERVICE_PROVIDER, + LoggerService, + MailerService, + TemplateRendererService, +]; + +@Global() +@Module({ + providers: DECLARATIONS, + exports: DECLARATIONS, +}) +export class CoreModule {} diff --git a/apps/backend/src/services/database/database.service.spec.ts b/apps/backend/src/services/core/database/database.service.spec.ts similarity index 100% rename from apps/backend/src/services/database/database.service.spec.ts rename to apps/backend/src/services/core/database/database.service.spec.ts diff --git a/apps/backend/src/services/database/database.service.ts b/apps/backend/src/services/core/database/database.service.ts similarity index 95% rename from apps/backend/src/services/database/database.service.ts rename to apps/backend/src/services/core/database/database.service.ts index 67dbb8f..0f5a610 100644 --- a/apps/backend/src/services/database/database.service.ts +++ b/apps/backend/src/services/core/database/database.service.ts @@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common'; import { Pool } from 'pg'; import { Kysely, PostgresDialect } from 'kysely'; -import { DB } from '../../database/db'; +import { DB } from '../../../database/db'; import { EnvService } from '../env/env.service'; @Injectable() diff --git a/apps/backend/src/services/env/env.service.spec.ts b/apps/backend/src/services/core/env/env.service.spec.ts similarity index 100% rename from apps/backend/src/services/env/env.service.spec.ts rename to apps/backend/src/services/core/env/env.service.spec.ts diff --git a/apps/backend/src/services/env/env.service.ts b/apps/backend/src/services/core/env/env.service.ts similarity index 100% rename from apps/backend/src/services/env/env.service.ts rename to apps/backend/src/services/core/env/env.service.ts diff --git a/apps/backend/src/services/localization/localization.service.spec.ts b/apps/backend/src/services/core/localization/localization.service.spec.ts similarity index 100% rename from apps/backend/src/services/localization/localization.service.spec.ts rename to apps/backend/src/services/core/localization/localization.service.spec.ts diff --git a/apps/backend/src/services/localization/localization.service.ts b/apps/backend/src/services/core/localization/localization.service.ts similarity index 100% rename from apps/backend/src/services/localization/localization.service.ts rename to apps/backend/src/services/core/localization/localization.service.ts diff --git a/apps/backend/src/services/logger/logger.service.spec.ts b/apps/backend/src/services/core/logger/logger.service.spec.ts similarity index 100% rename from apps/backend/src/services/logger/logger.service.spec.ts rename to apps/backend/src/services/core/logger/logger.service.spec.ts diff --git a/apps/backend/src/services/logger/logger.service.ts b/apps/backend/src/services/core/logger/logger.service.ts similarity index 100% rename from apps/backend/src/services/logger/logger.service.ts rename to apps/backend/src/services/core/logger/logger.service.ts diff --git a/apps/backend/src/services/mailer/mailer.service.spec.ts b/apps/backend/src/services/core/mailer/mailer.service.spec.ts similarity index 100% rename from apps/backend/src/services/mailer/mailer.service.spec.ts rename to apps/backend/src/services/core/mailer/mailer.service.spec.ts diff --git a/apps/backend/src/services/mailer/mailer.service.ts b/apps/backend/src/services/core/mailer/mailer.service.ts similarity index 100% rename from apps/backend/src/services/mailer/mailer.service.ts rename to apps/backend/src/services/core/mailer/mailer.service.ts diff --git a/apps/backend/src/services/template-renderer/mail-template-data.ts b/apps/backend/src/services/core/template-renderer/mail-template-data.ts similarity index 100% rename from apps/backend/src/services/template-renderer/mail-template-data.ts rename to apps/backend/src/services/core/template-renderer/mail-template-data.ts diff --git a/apps/backend/src/services/template-renderer/template-renderer.service.spec.ts b/apps/backend/src/services/core/template-renderer/template-renderer.service.spec.ts similarity index 100% rename from apps/backend/src/services/template-renderer/template-renderer.service.spec.ts rename to apps/backend/src/services/core/template-renderer/template-renderer.service.spec.ts diff --git a/apps/backend/src/services/template-renderer/template-renderer.service.ts b/apps/backend/src/services/core/template-renderer/template-renderer.service.ts similarity index 100% rename from apps/backend/src/services/template-renderer/template-renderer.service.ts rename to apps/backend/src/services/core/template-renderer/template-renderer.service.ts diff --git a/packages/common/src/models/auth/index.ts b/packages/common/src/models/auth/index.ts new file mode 100644 index 0000000..763ca48 --- /dev/null +++ b/packages/common/src/models/auth/index.ts @@ -0,0 +1,2 @@ +export * from "./credential-auth"; +export * from "./reset-auth"; diff --git a/packages/common/src/models/auth/reset-auth.ts b/packages/common/src/models/auth/reset-auth.ts new file mode 100644 index 0000000..655cb2b --- /dev/null +++ b/packages/common/src/models/auth/reset-auth.ts @@ -0,0 +1,9 @@ +import z from "zod"; + +export const resetAuthParser = z.object({ + userId: z.string(), + resetToken: z.string(), + newPassword: z.string(), +}); + +export type ResetAuth = z.infer; diff --git a/packages/common/src/models/index.ts b/packages/common/src/models/index.ts index a54a3b3..9b9a8fa 100644 --- a/packages/common/src/models/index.ts +++ b/packages/common/src/models/index.ts @@ -1,2 +1,3 @@ export * from "./users"; export * from "./lang"; +export * from "./auth"; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index bb96df2..53c564a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,9 +19,15 @@ importers: '@nestjs/core': specifier: ^11.0.1 version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/platform-express@11.1.3)(reflect-metadata@0.2.2)(rxjs@7.8.2) + '@nestjs/passport': + specifier: ^11.0.5 + version: 11.0.5(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0) '@nestjs/platform-express': specifier: ^11.0.1 version: 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3) + '@types/passport-local': + specifier: ^1.0.38 + version: 1.0.38 dayjs: specifier: ^1.11.13 version: 1.11.13 @@ -43,6 +49,12 @@ importers: nodemailer: specifier: ^7.0.5 version: 7.0.5 + passport: + specifier: ^0.7.0 + version: 0.7.0 + passport-local: + specifier: ^1.0.0 + version: 1.0.0 pg: specifier: ^8.16.3 version: 8.16.3 @@ -813,6 +825,12 @@ packages: '@nestjs/websockets': optional: true + '@nestjs/passport@11.0.5': + resolution: {integrity: sha512-ulQX6mbjlws92PIM15Naes4F4p2JoxGnIJuUsdXQPT+Oo2sqQmENEZXM7eYuimocfHnKlcfZOuyzbA33LwUlOQ==} + peerDependencies: + '@nestjs/common': ^10.0.0 || ^11.0.0 + passport: ^0.5.0 || ^0.6.0 || ^0.7.0 + '@nestjs/platform-express@11.1.3': resolution: {integrity: sha512-hEDNMlaPiBO72fxxX/CuRQL3MEhKRc/sIYGVoXjrnw6hTxZdezvvM6A95UaLsYknfmcZZa/CdG1SMBZOu9agHQ==} peerDependencies: @@ -1065,6 +1083,15 @@ packages: '@types/nodemailer@6.4.17': resolution: {integrity: sha512-I9CCaIp6DTldEg7vyUTZi8+9Vo0hi1/T8gv3C89yk1rSAAzoKQ8H8ki/jBYJSFoH/BisgLP8tkZMlQ91CIquww==} + '@types/passport-local@1.0.38': + resolution: {integrity: sha512-nsrW4A963lYE7lNTv9cr5WmiUD1ibYJvWrpE13oxApFsRt77b0RdtZvKbCdNIY4v/QZ6TRQWaDDEwV1kCTmcXg==} + + '@types/passport-strategy@0.2.38': + resolution: {integrity: sha512-GC6eMqqojOooq993Tmnmp7AUTbbQSgilyvpCYQjT+H6JfG/g6RGc7nXEniZlp0zyKJ0WUdOiZWLBZft9Yug1uA==} + + '@types/passport@1.0.17': + resolution: {integrity: sha512-aciLyx+wDwT2t2/kJGJR2AEeBz0nJU4WuRX04Wu9Dqc5lSUtwu0WERPHYsLhF9PtseiAMPBGNUOtFjxZ56prsg==} + '@types/pg@8.15.4': resolution: {integrity: sha512-I6UNVBAoYbvuWkkU3oosC8yxqH21f4/Jc4DK71JLG3dT2mdlGe1z+ep/LQGXaKaOgcvUrsQoPRqfgtMcvZiJhg==} @@ -2841,6 +2868,18 @@ packages: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} + passport-local@1.0.0: + resolution: {integrity: sha512-9wCE6qKznvf9mQYYbgJ3sVOHmCWoUNMVFoZzNoznmISbhnNNPhN9xfY3sLmScHMetEJeoY7CXwfhCe7argfQow==} + engines: {node: '>= 0.4.0'} + + passport-strategy@1.0.0: + resolution: {integrity: sha512-CB97UUvDKJde2V0KDWWB3lyf6PC3FaZP7YxZ2G8OAtn9p4HI9j9JLP9qjOGZFvyl8uwNT8qM+hGnz/n16NI7oA==} + engines: {node: '>= 0.4.0'} + + passport@0.7.0: + resolution: {integrity: sha512-cPLl+qZpSc+ireUvt+IzqbED1cHHkDoVYMo30jbJIdOOjQ1MQYZBPiNvmi8UM6lJuOpTPXJGZQk0DtC4y61MYQ==} + engines: {node: '>= 0.4.0'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} @@ -2868,6 +2907,9 @@ packages: resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} engines: {node: '>=8'} + pause@0.0.1: + resolution: {integrity: sha512-KG8UEiEVkR3wGEb4m5yZkVCzigAD+cVEJck2CzYZO37ZGJfctvVptVO192MwrtPhzONn6go8ylnOdMhKqi4nfg==} + peek-readable@5.4.2: resolution: {integrity: sha512-peBp3qZyuS6cNIJ2akRNG1uo1WJ1d0wTxg/fxMdZ0BqCVhx242bSFHM9eNqflfJVS9SsgkzgT/1UgnsurBOTMg==} engines: {node: '>=14.16'} @@ -3519,6 +3561,10 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + v8-compile-cache-lib@3.0.1: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} @@ -4535,6 +4581,11 @@ snapshots: optionalDependencies: '@nestjs/platform-express': 11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3) + '@nestjs/passport@11.0.5(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(passport@0.7.0)': + dependencies: + '@nestjs/common': 11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2) + passport: 0.7.0 + '@nestjs/platform-express@11.1.3(@nestjs/common@11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2))(@nestjs/core@11.1.3)': dependencies: '@nestjs/common': 11.1.3(reflect-metadata@0.2.2)(rxjs@7.8.2) @@ -4800,6 +4851,21 @@ snapshots: dependencies: '@types/node': 22.16.3 + '@types/passport-local@1.0.38': + dependencies: + '@types/express': 5.0.3 + '@types/passport': 1.0.17 + '@types/passport-strategy': 0.2.38 + + '@types/passport-strategy@0.2.38': + dependencies: + '@types/express': 5.0.3 + '@types/passport': 1.0.17 + + '@types/passport@1.0.17': + dependencies: + '@types/express': 5.0.3 + '@types/pg@8.15.4': dependencies: '@types/node': 22.16.3 @@ -6854,6 +6920,18 @@ snapshots: parseurl@1.3.3: {} + passport-local@1.0.0: + dependencies: + passport-strategy: 1.0.0 + + passport-strategy@1.0.0: {} + + passport@0.7.0: + dependencies: + passport-strategy: 1.0.0 + pause: 0.0.1 + utils-merge: 1.0.1 + path-exists@4.0.0: {} path-is-absolute@1.0.1: {} @@ -6871,6 +6949,8 @@ snapshots: path-type@4.0.0: {} + pause@0.0.1: {} + peek-readable@5.4.2: {} pend@1.2.0: {} @@ -7501,6 +7581,8 @@ snapshots: util-deprecate@1.0.2: {} + utils-merge@1.0.1: {} + v8-compile-cache-lib@3.0.1: {} v8-to-istanbul@9.3.0: