ws auth
This commit is contained in:
@@ -6,11 +6,25 @@ import {
|
||||
SubscribeMessage,
|
||||
WebSocketGateway,
|
||||
WebSocketServer,
|
||||
WsException,
|
||||
} from '@nestjs/websockets';
|
||||
|
||||
import { Server, Socket } from 'socket.io';
|
||||
import type { Server } from 'socket.io';
|
||||
import type { AuthenticatedSocket } from '../../types/socket';
|
||||
import { AuthService } from '../../auth/auth.service';
|
||||
import { JwtVerificationService } from '../../auth/services/jwt-verification.service';
|
||||
import { CursorPositionDto } from '../dto/cursor-position.dto';
|
||||
|
||||
@WebSocketGateway()
|
||||
const WS_EVENT = {
|
||||
CURSOR_REPORT_POSITION: 'cursor-report-position',
|
||||
} as const;
|
||||
|
||||
@WebSocketGateway({
|
||||
cors: {
|
||||
origin: true,
|
||||
credentials: true,
|
||||
},
|
||||
})
|
||||
export class StateGateway
|
||||
implements OnGatewayInit, OnGatewayConnection, OnGatewayDisconnect
|
||||
{
|
||||
@@ -18,24 +32,84 @@ export class StateGateway
|
||||
|
||||
@WebSocketServer() io: Server;
|
||||
|
||||
constructor(
|
||||
private readonly authService: AuthService,
|
||||
private readonly jwtVerificationService: JwtVerificationService,
|
||||
) {}
|
||||
|
||||
afterInit() {
|
||||
this.logger.log('Initialized');
|
||||
}
|
||||
|
||||
handleConnection(client: Socket) {
|
||||
const { sockets } = this.io.sockets;
|
||||
async handleConnection(client: AuthenticatedSocket) {
|
||||
try {
|
||||
this.logger.debug(
|
||||
`Connection attempt - handshake auth: ${JSON.stringify(client.handshake.auth)}`,
|
||||
);
|
||||
this.logger.debug(
|
||||
`Connection attempt - handshake headers: ${JSON.stringify(client.handshake.headers)}`,
|
||||
);
|
||||
|
||||
this.logger.log(`Client id: ${client.id} connected`);
|
||||
this.logger.debug(`Number of connected clients: ${sockets.size}`);
|
||||
const token = this.jwtVerificationService.extractToken(client.handshake);
|
||||
|
||||
if (!token) {
|
||||
this.logger.warn('WebSocket connection attempt without token');
|
||||
client.disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
const payload = await this.jwtVerificationService.verifyToken(token);
|
||||
|
||||
if (!payload.sub) {
|
||||
throw new WsException('Invalid token: missing subject');
|
||||
}
|
||||
|
||||
client.data.user = {
|
||||
keycloakSub: payload.sub,
|
||||
email: payload.email,
|
||||
name: payload.name,
|
||||
username: payload.preferred_username,
|
||||
picture: payload.picture,
|
||||
};
|
||||
|
||||
this.logger.log(`WebSocket authenticated: ${payload.sub}`);
|
||||
|
||||
await this.authService.syncUserFromToken(client.data.user);
|
||||
|
||||
const { sockets } = this.io.sockets;
|
||||
this.logger.log(
|
||||
`Client id: ${client.id} connected (user: ${payload.sub})`,
|
||||
);
|
||||
this.logger.debug(`Number of connected clients: ${sockets.size}`);
|
||||
} catch (error: unknown) {
|
||||
const errorMessage =
|
||||
error instanceof Error ? error.message : 'Unknown error';
|
||||
this.logger.error(`Connection error: ${errorMessage}`);
|
||||
client.disconnect();
|
||||
}
|
||||
}
|
||||
|
||||
handleDisconnect(client: Socket) {
|
||||
this.logger.log(`Cliend id:${client.id} disconnected`);
|
||||
handleDisconnect(client: AuthenticatedSocket) {
|
||||
const user = client.data.user;
|
||||
this.logger.log(
|
||||
`Client id: ${client.id} disconnected (user: ${user?.keycloakSub || 'unknown'})`,
|
||||
);
|
||||
}
|
||||
|
||||
@SubscribeMessage('cursor-report-position')
|
||||
handleCursorReportPosition(client: Socket, data: any) {
|
||||
this.logger.log(`Message received from client id: ${client.id}`);
|
||||
@SubscribeMessage(WS_EVENT.CURSOR_REPORT_POSITION)
|
||||
handleCursorReportPosition(
|
||||
client: AuthenticatedSocket,
|
||||
data: CursorPositionDto,
|
||||
) {
|
||||
const user = client.data.user;
|
||||
|
||||
if (!user) {
|
||||
throw new WsException('Unauthorized');
|
||||
}
|
||||
|
||||
this.logger.log(
|
||||
`Message received from client id: ${client.id} (user: ${user.keycloakSub})`,
|
||||
);
|
||||
this.logger.debug(`Payload: ${JSON.stringify(data, null, 0)}`);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user