@@ -13,16 +13,27 @@ interface EscrowEventData {
1313 [ key : string ] : unknown ;
1414}
1515
16+ interface JwtPayload {
17+ sub ?: string ;
18+ userId ?: string ;
19+ id ?: string ;
20+ }
21+
22+ interface ClientAuthPayload {
23+ token ?: string ;
24+ }
25+
1626@WebSocketGateway ( {
1727 namespace : '/events' ,
1828 cors : {
19- origin : process . env . FRONTEND_URL ?. split ( ',' ) || [ 'http://localhost:3001' ] ,
29+ origin : ( typeof process !== 'undefined' &&
30+ process . env . FRONTEND_URL ?. split ( ',' ) ) || [ 'http://localhost:3001' ] ,
2031 credentials : true ,
2132 } ,
2233} )
2334export class EventsGateway implements OnGatewayConnection , OnGatewayDisconnect {
2435 @WebSocketServer ( )
25- server : Server ;
36+ server ! : Server ;
2637
2738 private readonly logger = new Logger ( EventsGateway . name ) ;
2839 private readonly userSocketMap = new Map < string , Set < string > > ( ) ;
@@ -31,11 +42,23 @@ export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
3142
3243 constructor ( private readonly jwtService : JwtService ) { }
3344
45+ private extractToken ( client : Socket ) : string | undefined {
46+ const authPayload = client . handshake . auth as ClientAuthPayload | undefined ;
47+ const authorizationHeader = client . handshake . headers . authorization as
48+ | string
49+ | undefined ;
50+
51+ if ( authPayload ?. token ) {
52+ return authPayload . token ;
53+ }
54+
55+ const parts = authorizationHeader ?. split ( ' ' ) ?? [ ] ;
56+ return parts [ 1 ] ;
57+ }
58+
3459 async handleConnection ( client : Socket ) : Promise < void > {
3560 try {
36- const token =
37- ( client . handshake . auth ?. token as string ) ||
38- ( client . handshake . headers . authorization as string ) ?. split ( ' ' ) [ 1 ] ;
61+ const token = this . extractToken ( client ) ;
3962
4063 if ( ! token ) {
4164 this . logger . warn (
@@ -45,12 +68,27 @@ export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
4568 return ;
4669 }
4770
48- const decoded = this . jwtService . verify ( token ) as {
49- sub ?: string ;
50- userId ?: string ;
51- id ?: string ;
52- } ;
53- const userId = decoded ?. sub || decoded ?. userId || decoded ?. id ;
71+ let decoded : unknown ;
72+ try {
73+ decoded = this . jwtService . verify ( token ) ;
74+ } catch {
75+ this . logger . warn ( `Connection rejected: invalid token (${ client . id } )` ) ;
76+ client . disconnect ( ) ;
77+ return ;
78+ }
79+
80+ if (
81+ ! decoded ||
82+ typeof decoded !== 'object' ||
83+ ! ( 'sub' in decoded || 'userId' in decoded || 'id' in decoded )
84+ ) {
85+ this . logger . warn ( `Connection rejected: invalid token (${ client . id } )` ) ;
86+ client . disconnect ( ) ;
87+ return ;
88+ }
89+
90+ const payload = decoded as JwtPayload ;
91+ const userId = payload . sub || payload . userId || payload . id ;
5492
5593 if ( ! userId ) {
5694 this . logger . warn ( `Connection rejected: invalid token (${ client . id } )` ) ;
@@ -201,6 +239,10 @@ export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
201239 return ( this . userSocketMap . get ( userId ) ?. size || 0 ) > 0 ;
202240 }
203241
242+ isHealthy ( ) : boolean {
243+ return this . server !== undefined ;
244+ }
245+
204246 private emitToEscrowRoom (
205247 eventName : string ,
206248 escrowId : string ,
0 commit comments