From 4bd5b2339a66a5a675e20f689fff2e70ff12d236 Mon Sep 17 00:00:00 2001 From: Damien Arrachequesne Date: Mon, 12 Oct 2020 11:42:43 +0200 Subject: [PATCH] feat: throw upon reserved event names These events cannot be used by the end users, because they are part of the Socket.IO public API, so using them will now throw an error explicitly. --- dist/namespace.js | 13 ++----------- dist/socket.d.ts | 3 ++- dist/socket.js | 19 ++++++++----------- lib/namespace.ts | 17 +++-------------- lib/socket.ts | 19 +++++++------------ test/socket.io.ts | 24 ++++++++++++++++++++++++ 6 files changed, 46 insertions(+), 49 deletions(-) diff --git a/dist/namespace.js b/dist/namespace.js index f547362aed..7185862f7d 100644 --- a/dist/namespace.js +++ b/dist/namespace.js @@ -10,14 +10,6 @@ const socket_io_parser_1 = require("socket.io-parser"); const has_binary2_1 = __importDefault(require("has-binary2")); const debug_1 = __importDefault(require("debug")); const debug = debug_1.default("socket.io:namespace"); -/** - * Blacklisted events. - */ -const events = [ - "connect", - "connection", - "newListener" -]; class Namespace extends events_1.EventEmitter { /** * Namespace constructor. @@ -158,9 +150,8 @@ class Namespace extends events_1.EventEmitter { */ // @ts-ignore emit(ev, ...args) { - if (~events.indexOf(ev)) { - super.emit.apply(this, arguments); - return this; + if (socket_1.RESERVED_EVENTS.has(ev)) { + throw new Error(`"${ev}" is a reserved event name`); } // set up packet object args.unshift(ev); diff --git a/dist/socket.d.ts b/dist/socket.d.ts index f263f21ebe..b138833f9f 100644 --- a/dist/socket.d.ts +++ b/dist/socket.d.ts @@ -4,6 +4,7 @@ import { Client } from "./client"; import { Namespace } from "./namespace"; import { IncomingMessage } from "http"; import { Room, SocketId } from "socket.io-adapter"; +export declare const RESERVED_EVENTS: Set; /** * The handshake details */ @@ -76,7 +77,7 @@ export declare class Socket extends EventEmitter { * * @return {Socket} self */ - emit(ev: any): this; + emit(ev: string, ...args: any[]): this; /** * Targets a room when broadcasting. * diff --git a/dist/socket.js b/dist/socket.js index a4ef75cac7..a484cc55d6 100644 --- a/dist/socket.js +++ b/dist/socket.js @@ -3,7 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.Socket = void 0; +exports.Socket = exports.RESERVED_EVENTS = void 0; const events_1 = require("events"); const socket_io_parser_1 = require("socket.io-parser"); const has_binary2_1 = __importDefault(require("has-binary2")); @@ -11,17 +11,15 @@ const url_1 = __importDefault(require("url")); const debug_1 = __importDefault(require("debug")); const base64id_1 = __importDefault(require("base64id")); const debug = debug_1.default("socket.io:socket"); -/** - * Blacklisted events. - */ -const events = [ +exports.RESERVED_EVENTS = new Set([ "error", "connect", "disconnect", "disconnecting", + // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener "newListener", "removeListener" -]; +]); class Socket extends events_1.EventEmitter { /** * Interface to a `Client` for a given `Namespace`. @@ -69,12 +67,11 @@ class Socket extends events_1.EventEmitter { * @return {Socket} self */ // @ts-ignore - emit(ev) { - if (~events.indexOf(ev)) { - super.emit.apply(this, arguments); - return this; + emit(ev, ...args) { + if (exports.RESERVED_EVENTS.has(ev)) { + throw new Error(`"${ev}" is a reserved event name`); } - const args = Array.prototype.slice.call(arguments); + args.unshift(ev); const packet = { type: (this.flags.binary !== undefined ? this.flags.binary diff --git a/lib/namespace.ts b/lib/namespace.ts index 0fb65bbe20..8b099a000b 100644 --- a/lib/namespace.ts +++ b/lib/namespace.ts @@ -1,4 +1,4 @@ -import { Socket } from "./socket"; +import { Socket, RESERVED_EVENTS } from "./socket"; import { Server } from "./index"; import { Client } from "./client"; import { EventEmitter } from "events"; @@ -9,16 +9,6 @@ import { Adapter, Room, SocketId } from "socket.io-adapter"; const debug = debugModule("socket.io:namespace"); -/** - * Blacklisted events. - */ - -const events = [ - "connect", // for symmetry with client - "connection", - "newListener" -]; - export class Namespace extends EventEmitter { public readonly name: string; public readonly connected: Map = new Map(); @@ -176,9 +166,8 @@ export class Namespace extends EventEmitter { */ // @ts-ignore public emit(ev: string, ...args: any[]): Namespace { - if (~events.indexOf(ev)) { - super.emit.apply(this, arguments); - return this; + if (RESERVED_EVENTS.has(ev)) { + throw new Error(`"${ev}" is a reserved event name`); } // set up packet object args.unshift(ev); diff --git a/lib/socket.ts b/lib/socket.ts index a9347a367f..0ddbd9eff6 100644 --- a/lib/socket.ts +++ b/lib/socket.ts @@ -12,18 +12,15 @@ import base64id from "base64id"; const debug = debugModule("socket.io:socket"); -/** - * Blacklisted events. - */ - -const events = [ +export const RESERVED_EVENTS = new Set([ "error", "connect", "disconnect", "disconnecting", + // EventEmitter reserved events: https://nodejs.org/api/events.html#events_event_newlistener "newListener", "removeListener" -]; +]); /** * The handshake details @@ -133,13 +130,11 @@ export class Socket extends EventEmitter { * @return {Socket} self */ // @ts-ignore - public emit(ev) { - if (~events.indexOf(ev)) { - super.emit.apply(this, arguments); - return this; + public emit(ev: string, ...args: any[]) { + if (RESERVED_EVENTS.has(ev)) { + throw new Error(`"${ev}" is a reserved event name`); } - - const args = Array.prototype.slice.call(arguments); + args.unshift(ev); const packet: any = { type: (this.flags.binary !== undefined ? this.flags.binary diff --git a/test/socket.io.ts b/test/socket.io.ts index 4bdae1e69e..db32b20efa 100644 --- a/test/socket.io.ts +++ b/test/socket.io.ts @@ -693,6 +693,14 @@ describe("socket.io", () => { }); }); + it("should throw on reserved event", () => { + const sio = new Server(); + + expect(() => sio.emit("connect")).to.throwException( + /"connect" is a reserved event name/ + ); + }); + describe("dynamic namespaces", () => { it("should allow connections to dynamic namespaces with a regex", done => { const srv = createServer(); @@ -1657,6 +1665,22 @@ describe("socket.io", () => { }); }); }); + + it("should throw on reserved event", done => { + const srv = createServer(); + const sio = new Server(srv); + + srv.listen(() => { + const socket = client(srv); + sio.on("connection", s => { + expect(() => s.emit("error")).to.throwException( + /"error" is a reserved event name/ + ); + socket.close(); + done(); + }); + }); + }); }); describe("messaging many", () => {