Merge pull request #293 from peers/290-rangeerror-invalid-websocket-frame-rsv2-and-rsv3-must-be-clear

fix: the server could crash if a client sends invalid frames
This commit is contained in:
Jonas Gloning 2022-12-08 14:57:09 +01:00 committed by GitHub
commit ae4f6fd8c6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 18 additions and 19 deletions

View File

@ -1,13 +1,13 @@
import { MyWebSocket } from "../services/webSocketServer/webSocket"; import type WebSocket from "ws";
export interface IClient { export interface IClient {
getId(): string; getId(): string;
getToken(): string; getToken(): string;
getSocket(): MyWebSocket | null; getSocket(): WebSocket | null;
setSocket(socket: MyWebSocket | null): void; setSocket(socket: WebSocket | null): void;
getLastPing(): number; getLastPing(): number;
@ -19,7 +19,7 @@ export interface IClient {
export class Client implements IClient { export class Client implements IClient {
private readonly id: string; private readonly id: string;
private readonly token: string; private readonly token: string;
private socket: MyWebSocket | null = null; private socket: WebSocket | null = null;
private lastPing: number = new Date().getTime(); private lastPing: number = new Date().getTime();
constructor({ id, token }: { id: string; token: string; }) { constructor({ id, token }: { id: string; token: string; }) {
@ -35,11 +35,11 @@ export class Client implements IClient {
return this.token; return this.token;
} }
public getSocket(): MyWebSocket | null { public getSocket(): WebSocket | null {
return this.socket; return this.socket;
} }
public setSocket(socket: MyWebSocket | null): void { public setSocket(socket: WebSocket | null): void {
this.socket = socket; this.socket = socket;
} }

View File

@ -6,7 +6,7 @@ import { IConfig } from "../../config";
import { Errors, MessageType } from "../../enums"; import { Errors, MessageType } from "../../enums";
import { Client, IClient } from "../../models/client"; import { Client, IClient } from "../../models/client";
import { IRealm } from "../../models/realm"; import { IRealm } from "../../models/realm";
import { MyWebSocket } from "./webSocket"; import type WebSocket from "ws";
export interface IWebSocketServer extends EventEmitter { export interface IWebSocketServer extends EventEmitter {
readonly path: string; readonly path: string;
@ -42,11 +42,14 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer {
this.socketServer = new WebSocketLib.Server({ path: this.path, server }); this.socketServer = new WebSocketLib.Server({ path: this.path, server });
this.socketServer.on("connection", (socket: MyWebSocket, req) => this._onSocketConnection(socket, req)); this.socketServer.on("connection", (socket, req) => this._onSocketConnection(socket, req));
this.socketServer.on("error", (error: Error) => this._onSocketError(error)); this.socketServer.on("error", (error: Error) => this._onSocketError(error));
} }
private _onSocketConnection(socket: MyWebSocket, req: IncomingMessage): void { private _onSocketConnection(socket: WebSocket, req: IncomingMessage): void {
// An unhandled socket error might crash the server. Handle it first.
socket.on("error", error => this._onSocketError(error))
const { query = {} } = url.parse(req.url ?? '', true); const { query = {} } = url.parse(req.url ?? '', true);
const { id, token, key }: IAuthParams = query; const { id, token, key }: IAuthParams = query;
@ -85,7 +88,7 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer {
private _registerClient({ socket, id, token }: private _registerClient({ socket, id, token }:
{ {
socket: MyWebSocket; socket: WebSocket;
id: string; id: string;
token: string; token: string;
}): void { }): void {
@ -103,7 +106,7 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer {
this._configureWS(socket, newClient); this._configureWS(socket, newClient);
} }
private _configureWS(socket: MyWebSocket, client: IClient): void { private _configureWS(socket: WebSocket, client: IClient): void {
client.setSocket(socket); client.setSocket(socket);
// Cleanup after a socket closes. // Cleanup after a socket closes.
@ -130,7 +133,7 @@ export class WebSocketServer extends EventEmitter implements IWebSocketServer {
this.emit("connection", client); this.emit("connection", client);
} }
private _sendErrorAndClose(socket: MyWebSocket, msg: Errors): void { private _sendErrorAndClose(socket: WebSocket, msg: Errors): void {
socket.send( socket.send(
JSON.stringify({ JSON.stringify({
type: MessageType.ERROR, type: MessageType.ERROR,

View File

@ -1,4 +0,0 @@
import EventEmitter from "events";
import WebSocketLib from "ws";
export type MyWebSocket = WebSocketLib & EventEmitter;

View File

@ -3,9 +3,9 @@ import { Client } from '../../../../src/models/client';
import { TransmissionHandler } from '../../../../src/messageHandler/handlers'; import { TransmissionHandler } from '../../../../src/messageHandler/handlers';
import { Realm } from '../../../../src/models/realm'; import { Realm } from '../../../../src/models/realm';
import { MessageType } from '../../../../src/enums'; import { MessageType } from '../../../../src/enums';
import { MyWebSocket } from '../../../../src/services/webSocketServer/webSocket'; import type WebSocket from "ws";
const createFakeSocket = (): MyWebSocket => { const createFakeSocket = (): WebSocket => {
/* eslint-disable @typescript-eslint/no-empty-function */ /* eslint-disable @typescript-eslint/no-empty-function */
const sock = { const sock = {
send: (): void => { }, send: (): void => { },
@ -14,7 +14,7 @@ const createFakeSocket = (): MyWebSocket => {
}; };
/* eslint-enable @typescript-eslint/no-empty-function */ /* eslint-enable @typescript-eslint/no-empty-function */
return (sock as unknown as MyWebSocket); return (sock as unknown as WebSocket);
}; };
describe('Transmission handler', () => { describe('Transmission handler', () => {