mirror of
https://github.com/suitenumerique/docs.git
synced 2026-09-26 19:45:01 +02:00
🐛(y-provider) prevent process crash on malformed websocket frames
The ws library emits an unhandled 'error' event when a client sends a frame with unexpected RSV bits (e.g. permessage-deflate mismatch), which was crashing the whole y-provider process since no listener was attached to the socket. Add an error listener to log and drop the offending connection instead.
This commit is contained in:
@@ -19,6 +19,7 @@ and this project adheres to
|
||||
- 🐛(backend) skip session creation for the liveness probe
|
||||
- 🐛(frontend) preserve page titles when adding an emoji #2586
|
||||
- 🐛(frontend) hide the selection highlight on presenter images #2665
|
||||
- 🐛(y-provider) prevent process crash on malformed websocket frames #2673
|
||||
- ♿️(frontend) restore presenter focus trapping after share links #2533
|
||||
|
||||
## [v5.6.1] - 2026-09-04
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
import { EventEmitter } from 'node:events';
|
||||
|
||||
import { Request } from 'express';
|
||||
import { describe, expect, test, vi } from 'vitest';
|
||||
import { WebSocket } from 'ws';
|
||||
|
||||
vi.mock('@/servers/hocuspocusServer', () => ({
|
||||
hocuspocusServer: {
|
||||
hocuspocus: {
|
||||
handleConnection: vi.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
import { collaborationWSHandler } from '@/handlers/collaborationWSHandler';
|
||||
import { hocuspocusServer } from '@/servers/hocuspocusServer';
|
||||
|
||||
const handleConnectionMock = vi.spyOn(
|
||||
hocuspocusServer.hocuspocus,
|
||||
'handleConnection',
|
||||
);
|
||||
|
||||
const createFakeWs = () => {
|
||||
const ws = new EventEmitter() as unknown as WebSocket;
|
||||
const closeMock = vi.fn();
|
||||
ws.close = closeMock;
|
||||
return { ws, closeMock };
|
||||
};
|
||||
|
||||
describe('collaborationWSHandler', () => {
|
||||
test('forwards the connection to hocuspocus', () => {
|
||||
const { ws } = createFakeWs();
|
||||
const req = {} as Request;
|
||||
|
||||
collaborationWSHandler(ws, req);
|
||||
|
||||
expect(handleConnectionMock).toHaveBeenCalledWith(ws, req);
|
||||
});
|
||||
|
||||
test('does not crash the process when the socket emits an unexpected "error" event', () => {
|
||||
const consoleErrorMock = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => undefined);
|
||||
const { ws } = createFakeWs();
|
||||
|
||||
collaborationWSHandler(ws, {} as Request);
|
||||
|
||||
const wsError = Object.assign(new Error('Invalid WebSocket frame'), {
|
||||
code: 'WS_ERR_UNEXPECTED_RSV_2_3',
|
||||
});
|
||||
|
||||
// Without an 'error' listener, EventEmitter would throw here and crash
|
||||
// the process - this call must not throw.
|
||||
expect(() => ws.emit('error', wsError)).not.toThrow();
|
||||
|
||||
expect(consoleErrorMock).toHaveBeenCalledWith(
|
||||
'WebSocket connection error:',
|
||||
wsError,
|
||||
);
|
||||
|
||||
consoleErrorMock.mockRestore();
|
||||
});
|
||||
|
||||
test('closes the socket and logs if handleConnection throws synchronously', () => {
|
||||
const consoleErrorMock = vi
|
||||
.spyOn(console, 'error')
|
||||
.mockImplementation(() => undefined);
|
||||
const error = new Error('boom');
|
||||
handleConnectionMock.mockImplementationOnce(() => {
|
||||
throw error;
|
||||
});
|
||||
|
||||
const { ws, closeMock } = createFakeWs();
|
||||
collaborationWSHandler(ws, {} as Request);
|
||||
|
||||
expect(closeMock).toHaveBeenCalled();
|
||||
expect(consoleErrorMock).toHaveBeenCalledWith(
|
||||
'Failed to handle WebSocket connection:',
|
||||
error,
|
||||
);
|
||||
|
||||
consoleErrorMock.mockRestore();
|
||||
});
|
||||
});
|
||||
@@ -4,6 +4,10 @@ import * as ws from 'ws';
|
||||
import { hocuspocusServer } from '@/servers/hocuspocusServer';
|
||||
|
||||
export const collaborationWSHandler = (ws: ws.WebSocket, req: Request) => {
|
||||
ws.on('error', (error) => {
|
||||
console.error('WebSocket connection error:', error);
|
||||
});
|
||||
|
||||
try {
|
||||
hocuspocusServer.hocuspocus.handleConnection(ws, req);
|
||||
} catch (error) {
|
||||
|
||||
Reference in New Issue
Block a user