fix(gateway): security hardening — auth guards, ownership checks, validation, rate limiting

This commit is contained in:
2026-03-13 08:25:57 -05:00
parent 01e9891243
commit 55b5a31c3c
22 changed files with 696 additions and 74 deletions

View File

@@ -11,18 +11,17 @@ import {
} from '@nestjs/websockets';
import { Server, Socket } from 'socket.io';
import type { AgentSessionEvent } from '@mariozechner/pi-coding-agent';
import type { Auth } from '@mosaic/auth';
import { AgentService } from '../agent/agent.service.js';
import { AUTH } from '../auth/auth.tokens.js';
import { v4 as uuid } from 'uuid';
interface ChatMessage {
conversationId?: string;
content: string;
provider?: string;
modelId?: string;
}
import { ChatSocketMessageDto } from './chat.dto.js';
import { validateSocketSession } from './chat.gateway-auth.js';
@WebSocketGateway({
cors: { origin: '*' },
cors: {
origin: process.env['GATEWAY_CORS_ORIGIN'] ?? 'http://localhost:3000',
},
namespace: '/chat',
})
export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect {
@@ -35,13 +34,25 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
{ conversationId: string; cleanup: () => void }
>();
constructor(@Inject(AgentService) private readonly agentService: AgentService) {}
constructor(
@Inject(AgentService) private readonly agentService: AgentService,
@Inject(AUTH) private readonly auth: Auth,
) {}
afterInit(): void {
this.logger.log('Chat WebSocket gateway initialized');
}
handleConnection(client: Socket): void {
async handleConnection(client: Socket): Promise<void> {
const session = await validateSocketSession(client.handshake.headers, this.auth);
if (!session) {
this.logger.warn(`Rejected unauthenticated WebSocket client: ${client.id}`);
client.disconnect();
return;
}
client.data.user = session.user;
client.data.session = session.session;
this.logger.log(`Client connected: ${client.id}`);
}
@@ -58,7 +69,7 @@ export class ChatGateway implements OnGatewayInit, OnGatewayConnection, OnGatewa
@SubscribeMessage('message')
async handleMessage(
@ConnectedSocket() client: Socket,
@MessageBody() data: ChatMessage,
@MessageBody() data: ChatSocketMessageDto,
): Promise<void> {
const conversationId = data.conversationId ?? uuid();