fix(security): harden auth, upload, and API configuration
- Lock public registration to first-user bootstrap (403 afterwards) - Require JwtAuthGuard on upload + whitelist png/jpg/webp/gif (SVG/XSS blocked) - Add global throttling (login/register 5/min, upload 10/min) - Add helmet security headers; serve uploads with nosniff - Replace permissive CORS (origin:true+credentials) with CORS_ORIGINS whitelist - Disable Swagger outside development; sanitize 500 error responses - Enforce 32+ char JWT_SECRET; make token expiry configurable (TOKEN_EXPIRES_IN) - Re-check user in DB on every JWT validation (revocation on user delete) - Dummy bcrypt compare to prevent login user-enumeration via timing - Map malformed BigInt inputs to 400 instead of 500 - Widen .gitignore to .env* and add apps/api/.env.example - Disable Nuxt devtools and sourcemaps
This commit is contained in:
@@ -1,16 +1,10 @@
|
||||
import { Body, Controller, HttpCode, HttpStatus, Post } from '@nestjs/common';
|
||||
import {
|
||||
ApiOperation,
|
||||
ApiResponse,
|
||||
ApiTags,
|
||||
} from '@nestjs/swagger';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||
import { AuthService } from './auth.service';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
import {
|
||||
LoginResponseDto,
|
||||
UserPublicDto,
|
||||
} from './dto/auth-response.dto';
|
||||
import { LoginResponseDto, UserPublicDto } from './dto/auth-response.dto';
|
||||
|
||||
@ApiTags('auth')
|
||||
@Controller('auth')
|
||||
@@ -19,15 +13,18 @@ export class AuthController {
|
||||
|
||||
@Post('register')
|
||||
@HttpCode(HttpStatus.CREATED)
|
||||
@ApiOperation({ summary: 'Register a new admin user' })
|
||||
@Throttle({ default: { limit: 5, ttl: 60_000 } })
|
||||
@ApiOperation({ summary: 'Register the first admin user (bootstrap only)' })
|
||||
@ApiResponse({ status: 201, type: UserPublicDto })
|
||||
@ApiResponse({ status: 409, description: 'Username already exists' })
|
||||
@ApiResponse({ status: 403, description: 'Registration is disabled once a user exists' })
|
||||
register(@Body() dto: RegisterDto): Promise<UserPublicDto> {
|
||||
return this.authService.register(dto) as unknown as Promise<UserPublicDto>;
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
@HttpCode(HttpStatus.OK)
|
||||
@Throttle({ default: { limit: 5, ttl: 60_000 } })
|
||||
@ApiOperation({ summary: 'Login and obtain a JWT' })
|
||||
@ApiResponse({ status: 200, type: LoginResponseDto })
|
||||
@ApiResponse({ status: 401, description: 'Invalid credentials' })
|
||||
|
||||
Reference in New Issue
Block a user