From 6ac9a2f1ec642f4424f6d90c47b2d8e7f00c728c Mon Sep 17 00:00:00 2001 From: Tom Date: Wed, 18 Jun 2025 13:50:38 +0000 Subject: [PATCH] Denied access to login & register while logged in. Fixed regular user auth for requiring admin. --- backend/nestjs-seshat-api/src/app.module.ts | 3 +- .../src/auth/auth.controller.ts | 37 +++++++++++++------ .../nestjs-seshat-api/src/auth/auth.module.ts | 2 - .../src/auth/auth.service.ts | 18 ++++++--- .../src/auth/dto/login.dto.ts | 14 ++++++- .../src/auth/guards/jwt-access.guard.ts | 2 +- .../src/auth/guards/login-auth.guard.ts | 6 --- .../src/auth/guards/offline.guard.ts | 16 ++++---- .../src/auth/strategies/login.strategy.ts | 20 ---------- .../src/users/dto/login-user.dto.ts | 9 ----- .../src/users/users.service.ts | 8 ++-- 11 files changed, 65 insertions(+), 70 deletions(-) delete mode 100644 backend/nestjs-seshat-api/src/auth/guards/login-auth.guard.ts delete mode 100644 backend/nestjs-seshat-api/src/auth/strategies/login.strategy.ts delete mode 100644 backend/nestjs-seshat-api/src/users/dto/login-user.dto.ts diff --git a/backend/nestjs-seshat-api/src/app.module.ts b/backend/nestjs-seshat-api/src/app.module.ts index 701a199..d2f044f 100644 --- a/backend/nestjs-seshat-api/src/app.module.ts +++ b/backend/nestjs-seshat-api/src/app.module.ts @@ -74,7 +74,8 @@ import { BullModule } from '@nestjs/bullmq'; BooksModule, ProvidersModule, SeriesModule, - LibraryModule + LibraryModule, + ConfigModule, ], controllers: [AppController], providers: [AppService, UsersService], diff --git a/backend/nestjs-seshat-api/src/auth/auth.controller.ts b/backend/nestjs-seshat-api/src/auth/auth.controller.ts index 12fa87a..7c3ac7d 100644 --- a/backend/nestjs-seshat-api/src/auth/auth.controller.ts +++ b/backend/nestjs-seshat-api/src/auth/auth.controller.ts @@ -1,5 +1,4 @@ -import { Controller, Request, Post, UseGuards, Body, Res, Delete, Patch } from '@nestjs/common'; -import { LoginAuthGuard } from './guards/login-auth.guard'; +import { Controller, Request, Post, UseGuards, Body, Res, Delete, Patch, UnauthorizedException } from '@nestjs/common'; import { AuthService } from './auth.service'; import { UsersService } from 'src/users/users.service'; import { RegisterUserDto } from './dto/register-user.dto'; @@ -21,7 +20,7 @@ export class AuthController { private logger: PinoLogger, ) { } - @UseGuards(LoginAuthGuard) + @UseGuards(OfflineGuard) @Post('login') async login( @Request() req, @@ -30,7 +29,7 @@ export class AuthController { ) { let data: AuthenticationDto | null; try { - data = await this.auth.login(req.user, body.remember_me); + data = await this.auth.login(body); if (!data.access_token || body.remember_me && (!data.refresh_token || !data.refresh_exp)) { response.statusCode = 500; return { @@ -47,6 +46,14 @@ export class AuthController { error: err, }); + if (err instanceof UnauthorizedException) { + response.statusCode = 401; + return { + success: false, + error_message: 'Invalid credentials.', + }; + } + response.statusCode = 500; return { success: false, @@ -224,7 +231,11 @@ export class AuthController { } try { - data = await this.auth.login(user, false); + data = await this.auth.login({ + user_login: body.user_login, + password: body.password, + remember_me: false, + }); if (!data.access_token) { this.logger.error({ class: AuthController.name, @@ -250,6 +261,15 @@ export class AuthController { error: err, }); + // This should never happen... + if (err instanceof UnauthorizedException) { + response.statusCode = 401; + return { + success: false, + error_message: 'Invalid credentials.', + }; + } + response.statusCode = 500; return { success: false, @@ -264,13 +284,6 @@ export class AuthController { sameSite: 'strict', }); - response.cookie('Refresh', data.refresh_token, { - httpOnly: true, - secure: true, - expires: new Date(data.refresh_exp), - sameSite: 'strict', - }); - return { success: true, }; diff --git a/backend/nestjs-seshat-api/src/auth/auth.module.ts b/backend/nestjs-seshat-api/src/auth/auth.module.ts index 385a4fc..3bbaf5f 100644 --- a/backend/nestjs-seshat-api/src/auth/auth.module.ts +++ b/backend/nestjs-seshat-api/src/auth/auth.module.ts @@ -2,7 +2,6 @@ import { Module } from '@nestjs/common'; import { AuthService } from './auth.service'; import { UsersModule } from 'src/users/users.module'; import { PassportModule } from '@nestjs/passport'; -import { LoginStrategy } from './strategies/login.strategy'; import { AuthController } from './auth.controller'; import { ConfigModule, ConfigService } from '@nestjs/config'; import { JwtModule } from '@nestjs/jwt'; @@ -37,7 +36,6 @@ import { JwtRefreshStrategy } from './strategies/jwt-refresh.strategy'; AuthService, JwtStrategy, JwtRefreshStrategy, - LoginStrategy, ], controllers: [AuthController] }) diff --git a/backend/nestjs-seshat-api/src/auth/auth.service.ts b/backend/nestjs-seshat-api/src/auth/auth.service.ts index c0e076d..fc0a47c 100644 --- a/backend/nestjs-seshat-api/src/auth/auth.service.ts +++ b/backend/nestjs-seshat-api/src/auth/auth.service.ts @@ -1,9 +1,11 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, UnauthorizedException } from '@nestjs/common'; import { UserEntity } from 'src/users/entities/users.entity'; import { UsersService } from 'src/users/users.service'; import { AuthRefreshService } from './auth.refresh.service'; import { AuthAccessService } from './auth.access.service'; import { UUID } from 'crypto'; +import { AuthenticationDto } from './dto/authentication.dto'; +import { LoginDto } from './dto/login.dto'; @Injectable() export class AuthService { @@ -15,10 +17,14 @@ export class AuthService { async login( - user: UserEntity, - withRefresh: boolean - ): Promise { - if (withRefresh) { + loginDetails: LoginDto + ): Promise { + const user = await this.users.findOne(loginDetails); + if (!user) { + throw new UnauthorizedException(); + } + + if (loginDetails.remember_me) { return this.renew(user); } @@ -47,7 +53,7 @@ export class AuthService { username: string, password: string, ): Promise { - return await this.users.findOne({ username, password }); + return await this.users.findOne({ user_login: username, password, remember_me: false }); } async verify( diff --git a/backend/nestjs-seshat-api/src/auth/dto/login.dto.ts b/backend/nestjs-seshat-api/src/auth/dto/login.dto.ts index 4924078..4498987 100644 --- a/backend/nestjs-seshat-api/src/auth/dto/login.dto.ts +++ b/backend/nestjs-seshat-api/src/auth/dto/login.dto.ts @@ -1,6 +1,18 @@ -import { IsBoolean, IsOptional } from 'class-validator'; +import { IsBoolean, IsNotEmpty, IsOptional, IsString, MaxLength, MinLength } from 'class-validator'; export class LoginDto { + @IsString() + @IsNotEmpty() + @MinLength(3) + @MaxLength(24) + readonly user_login: string; + + @IsString() + @IsNotEmpty() + @MinLength(8) + @MaxLength(128) + readonly password: string; + @IsBoolean() @IsOptional() readonly remember_me: boolean; diff --git a/backend/nestjs-seshat-api/src/auth/guards/jwt-access.guard.ts b/backend/nestjs-seshat-api/src/auth/guards/jwt-access.guard.ts index 80bcffe..f7a647c 100644 --- a/backend/nestjs-seshat-api/src/auth/guards/jwt-access.guard.ts +++ b/backend/nestjs-seshat-api/src/auth/guards/jwt-access.guard.ts @@ -5,7 +5,7 @@ import { AuthGuard } from '@nestjs/passport'; @Injectable() export class JwtAccessGuard extends AuthGuard('jwt-access') { handleRequest(err, user, info) { - if (err || !user || !user.isAdmin) { + if (err || !user) { throw err || new UnauthorizedException(); } return user; diff --git a/backend/nestjs-seshat-api/src/auth/guards/login-auth.guard.ts b/backend/nestjs-seshat-api/src/auth/guards/login-auth.guard.ts deleted file mode 100644 index 7d530ad..0000000 --- a/backend/nestjs-seshat-api/src/auth/guards/login-auth.guard.ts +++ /dev/null @@ -1,6 +0,0 @@ - -import { Injectable } from '@nestjs/common'; -import { AuthGuard } from '@nestjs/passport'; - -@Injectable() -export class LoginAuthGuard extends AuthGuard('login') { } diff --git a/backend/nestjs-seshat-api/src/auth/guards/offline.guard.ts b/backend/nestjs-seshat-api/src/auth/guards/offline.guard.ts index 2688f03..72b71de 100644 --- a/backend/nestjs-seshat-api/src/auth/guards/offline.guard.ts +++ b/backend/nestjs-seshat-api/src/auth/guards/offline.guard.ts @@ -1,13 +1,13 @@ -import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common'; -import { Observable } from 'rxjs'; +import { ForbiddenException, Injectable } from '@nestjs/common'; +import { AuthGuard } from '@nestjs/passport'; @Injectable() -export class OfflineGuard implements CanActivate { - canActivate( - context: ExecutionContext, - ): boolean | Promise | Observable { - const request = context.switchToHttp().getRequest(); - return !request.user; +export class OfflineGuard extends AuthGuard('jwt-access') { + handleRequest(err, user, info) { + if (err || user) { + throw err || new ForbiddenException(); + } + return null; } } diff --git a/backend/nestjs-seshat-api/src/auth/strategies/login.strategy.ts b/backend/nestjs-seshat-api/src/auth/strategies/login.strategy.ts deleted file mode 100644 index 922fc25..0000000 --- a/backend/nestjs-seshat-api/src/auth/strategies/login.strategy.ts +++ /dev/null @@ -1,20 +0,0 @@ - -import { Strategy } from 'passport-local'; -import { PassportStrategy } from '@nestjs/passport'; -import { Injectable, UnauthorizedException } from '@nestjs/common'; -import { AuthService } from '../auth.service'; - -@Injectable() -export class LoginStrategy extends PassportStrategy(Strategy, 'login') { - constructor(private authService: AuthService) { - super(); - } - - async validate(username: string, password: string): Promise { - const user = await this.authService.validate(username, password); - if (!user) { - throw new UnauthorizedException(); - } - return user; - } -} diff --git a/backend/nestjs-seshat-api/src/users/dto/login-user.dto.ts b/backend/nestjs-seshat-api/src/users/dto/login-user.dto.ts deleted file mode 100644 index 6c37225..0000000 --- a/backend/nestjs-seshat-api/src/users/dto/login-user.dto.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { IsNotEmpty } from 'class-validator'; - -export class LoginUserDto { - @IsNotEmpty() - readonly username: string; - - @IsNotEmpty() - readonly password: string; -} \ No newline at end of file diff --git a/backend/nestjs-seshat-api/src/users/users.service.ts b/backend/nestjs-seshat-api/src/users/users.service.ts index b2ec8aa..78f998f 100644 --- a/backend/nestjs-seshat-api/src/users/users.service.ts +++ b/backend/nestjs-seshat-api/src/users/users.service.ts @@ -3,8 +3,8 @@ import { Injectable } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import { UserEntity } from './entities/users.entity'; -import { LoginUserDto } from './dto/login-user.dto'; import { UUID } from 'crypto'; +import { LoginDto } from 'src/auth/dto/login.dto'; class UserDto { userId: UUID; @@ -32,15 +32,15 @@ export class UsersService { })); } - async findOne({ username, password }: LoginUserDto): Promise { - const user = await this.userRepository.findOneBy({ userLogin: username }); + async findOne(loginDetails: LoginDto): Promise { + const user = await this.userRepository.findOneBy({ userLogin: loginDetails.user_login }); if (!user) { // TODO: force an argon2.verify() to occur here. return null; } const buffer = Buffer.concat([ - Buffer.from(password, 'utf8'), + Buffer.from(loginDetails.password, 'utf8'), Buffer.from(user.salt.toString(16), 'hex'), ]);