security: address assessment findings and bump to v2026.3.11
- C1: Disable Swagger UI in production (env gate) - M1+M2: Add Helmet.js for security headers (CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy) and remove X-Powered-By - H2: Add @nestjs/throttler rate limiting (5 req/min on login/register) - M4: Remove orgSchema from JWT payload and client-side storage; tenant middleware now resolves schema from orgId via cached DB lookup - L1: Fix Chatwoot user identification (read from auth store on ready) - Remove schemaName from frontend Organization type and UI displays Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -9,6 +9,7 @@ import {
|
||||
} from '@nestjs/common';
|
||||
import { ApiTags, ApiOperation, ApiBearerAuth } from '@nestjs/swagger';
|
||||
import { AuthGuard } from '@nestjs/passport';
|
||||
import { Throttle } from '@nestjs/throttler';
|
||||
import { AuthService } from './auth.service';
|
||||
import { RegisterDto } from './dto/register.dto';
|
||||
import { LoginDto } from './dto/login.dto';
|
||||
@@ -23,12 +24,14 @@ export class AuthController {
|
||||
|
||||
@Post('register')
|
||||
@ApiOperation({ summary: 'Register a new user' })
|
||||
@Throttle({ default: { limit: 5, ttl: 60000 } })
|
||||
async register(@Body() dto: RegisterDto) {
|
||||
return this.authService.register(dto);
|
||||
}
|
||||
|
||||
@Post('login')
|
||||
@ApiOperation({ summary: 'Login with email and password' })
|
||||
@Throttle({ default: { limit: 5, ttl: 60000 } })
|
||||
@UseGuards(AuthGuard('local'))
|
||||
async login(@Request() req: any, @Body() _dto: LoginDto) {
|
||||
const ip = req.headers['x-forwarded-for'] || req.ip;
|
||||
|
||||
@@ -118,7 +118,6 @@ export class AuthService {
|
||||
sub: user.id,
|
||||
email: user.email,
|
||||
orgId: membership.organizationId,
|
||||
orgSchema: membership.organization.schemaName,
|
||||
role: membership.role,
|
||||
};
|
||||
|
||||
@@ -177,7 +176,6 @@ export class AuthService {
|
||||
|
||||
if (defaultOrg) {
|
||||
payload.orgId = defaultOrg.organizationId;
|
||||
payload.orgSchema = defaultOrg.organization?.schemaName;
|
||||
payload.role = defaultOrg.role;
|
||||
}
|
||||
|
||||
@@ -195,7 +193,6 @@ export class AuthService {
|
||||
organizations: orgs.map((uo) => ({
|
||||
id: uo.organizationId,
|
||||
name: uo.organization?.name,
|
||||
schemaName: uo.organization?.schemaName,
|
||||
status: uo.organization?.status,
|
||||
role: uo.role,
|
||||
})),
|
||||
|
||||
@@ -18,7 +18,6 @@ export class JwtStrategy extends PassportStrategy(Strategy) {
|
||||
sub: payload.sub,
|
||||
email: payload.email,
|
||||
orgId: payload.orgId,
|
||||
orgSchema: payload.orgSchema,
|
||||
role: payload.role,
|
||||
isSuperadmin: payload.isSuperadmin || false,
|
||||
impersonatedBy: payload.impersonatedBy || null,
|
||||
|
||||
Reference in New Issue
Block a user