socket.io-parser

4.2.44.2.6
~

Modified (13 files)

Index: package/LICENSE
===================================================================
--- package/LICENSE
+++ package/LICENSE
@@ -1,7 +1,7 @@
 (The MIT License)
 
-Copyright (c) 2014 Guillermo Rauch <[email protected]>
+Copyright (c) 2014-present Guillermo Rauch and Socket.IO contributors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy of
 this software and associated documentation files (the 'Software'), to deal in
 the Software without restriction, including without limitation the rights to
Index: package/build/cjs/binary.js
===================================================================
--- package/build/cjs/binary.js
+++ package/build/cjs/binary.js
@@ -1,7 +1,8 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.reconstructPacket = exports.deconstructPacket = void 0;
+exports.deconstructPacket = deconstructPacket;
+exports.reconstructPacket = reconstructPacket;
 const is_binary_js_1 = require("./is-binary.js");
 /**
  * Replaces every Buffer | ArrayBuffer | Blob | File in packet with a numbered placeholder.
  *
@@ -16,9 +17,8 @@
     pack.data = _deconstructPacket(packetData, buffers);
     pack.attachments = buffers.length; // number of binary 'attachments'
     return { packet: pack, buffers: buffers };
 }
-exports.deconstructPacket = deconstructPacket;
 function _deconstructPacket(data, buffers) {
     if (!data)
         return data;
     if ((0, is_binary_js_1.isBinary)(data)) {
@@ -56,9 +56,8 @@
     packet.data = _reconstructPacket(packet.data, buffers);
     delete packet.attachments; // no longer useful
     return packet;
 }
-exports.reconstructPacket = reconstructPacket;
 function _reconstructPacket(data, buffers) {
     if (!data)
         return data;
     if (data && data._placeholder === true) {
Index: package/build/cjs/index.js
===================================================================
--- package/build/cjs/index.js
+++ package/build/cjs/index.js
@@ -1,7 +1,8 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
 exports.Decoder = exports.Encoder = exports.PacketType = exports.protocol = void 0;
+exports.isPacketValid = isPacketValid;
 const component_emitter_1 = require("@socket.io/component-emitter");
 const binary_js_1 = require("./binary.js");
 const is_binary_js_1 = require("./is-binary.js");
 const debug_1 = require("debug"); // debug()
@@ -9,13 +10,13 @@
 /**
  * These strings must not be used as event names, as they have a special meaning.
  */
 const RESERVED_EVENTS = [
-    "connect",
-    "connect_error",
-    "disconnect",
-    "disconnecting",
-    "newListener",
+    "connect", // used on the client side
+    "connect_error", // used on the client side
+    "disconnect", // used on both sides
+    "disconnecting", // used on the server side
+    "newListener", // used by the Node.js EventEmitter
     "removeListener", // used by the Node.js EventEmitter
 ];
 /**
  * Protocol version.
@@ -31,9 +32,9 @@
     PacketType[PacketType["ACK"] = 3] = "ACK";
     PacketType[PacketType["CONNECT_ERROR"] = 4] = "CONNECT_ERROR";
     PacketType[PacketType["BINARY_EVENT"] = 5] = "BINARY_EVENT";
     PacketType[PacketType["BINARY_ACK"] = 6] = "BINARY_ACK";
-})(PacketType = exports.PacketType || (exports.PacketType = {}));
+})(PacketType || (exports.PacketType = PacketType = {}));
 /**
  * A socket.io Encoder instance
  */
 class Encoder {
@@ -107,26 +108,23 @@
         return buffers; // write all the buffers
     }
 }
 exports.Encoder = Encoder;
-// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
-function isObject(value) {
-    return Object.prototype.toString.call(value) === "[object Object]";
-}
 /**
  * A socket.io Decoder instance
  *
  * @return {Object} decoder
  */
 class Decoder extends component_emitter_1.Emitter {
     /**
      * Decoder constructor
-     *
-     * @param {function} reviver - custom reviver to pass down to JSON.stringify
      */
-    constructor(reviver) {
+    constructor(opts) {
         super();
-        this.reviver = reviver;
+        this.opts = Object.assign({
+            reviver: undefined,
+            maxAttachments: 10,
+        }, typeof opts === "function" ? { reviver: opts } : opts);
     }
     /**
      * Decodes an encoded packet string into packet JSON.
      *
@@ -195,9 +193,16 @@
             const buf = str.substring(start, i);
             if (buf != Number(buf) || str.charAt(i) !== "-") {
                 throw new Error("Illegal attachments");
             }
-            p.attachments = Number(buf);
+            const n = Number(buf);
+            if (!isInteger(n) || n < 0) {
+                throw new Error("Illegal attachments");
+            }
+            else if (n > this.opts.maxAttachments) {
+                throw new Error("too many attachments");
+            }
+            p.attachments = n;
         }
         // look up namespace (if any)
         if ("/" === str.charAt(i + 1)) {
             const start = i + 1;
@@ -242,9 +247,9 @@
         return p;
     }
     tryParse(str) {
         try {
-            return JSON.parse(str, this.reviver);
+            return JSON.parse(str, this.opts.reviver);
         }
         catch (e) {
             return false;
         }
@@ -318,4 +323,45 @@
         this.reconPack = null;
         this.buffers = [];
     }
 }
+function isNamespaceValid(nsp) {
+    return typeof nsp === "string";
+}
+// see https://caniuse.com/mdn-javascript_builtins_number_isinteger
+const isInteger = Number.isInteger ||
+    function (value) {
+        return (typeof value === "number" &&
+            isFinite(value) &&
+            Math.floor(value) === value);
+    };
+function isAckIdValid(id) {
+    return id === undefined || isInteger(id);
+}
+// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
+function isObject(value) {
+    return Object.prototype.toString.call(value) === "[object Object]";
+}
+function isDataValid(type, payload) {
+    switch (type) {
+        case PacketType.CONNECT:
+            return payload === undefined || isObject(payload);
+        case PacketType.DISCONNECT:
+            return payload === undefined;
+        case PacketType.EVENT:
+            return (Array.isArray(payload) &&
+                (typeof payload[0] === "number" ||
+                    (typeof payload[0] === "string" &&
+                        RESERVED_EVENTS.indexOf(payload[0]) === -1)));
+        case PacketType.ACK:
+            return Array.isArray(payload);
+        case PacketType.CONNECT_ERROR:
+            return typeof payload === "string" || isObject(payload);
+        default:
+            return false;
+    }
+}
+function isPacketValid(packet) {
+    return (isNamespaceValid(packet.nsp) &&
+        isAckIdValid(packet.id) &&
+        isDataValid(packet.type, packet.data));
+}
Index: package/build/esm-debug/index.js
===================================================================
--- package/build/esm-debug/index.js
+++ package/build/esm-debug/index.js
@@ -6,13 +6,13 @@
 /**
  * These strings must not be used as event names, as they have a special meaning.
  */
 const RESERVED_EVENTS = [
-    "connect",
-    "connect_error",
-    "disconnect",
-    "disconnecting",
-    "newListener",
+    "connect", // used on the client side
+    "connect_error", // used on the client side
+    "disconnect", // used on both sides
+    "disconnecting", // used on the server side
+    "newListener", // used by the Node.js EventEmitter
     "removeListener", // used by the Node.js EventEmitter
 ];
 /**
  * Protocol version.
@@ -103,26 +103,23 @@
         buffers.unshift(pack); // add packet info to beginning of data list
         return buffers; // write all the buffers
     }
 }
-// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
-function isObject(value) {
-    return Object.prototype.toString.call(value) === "[object Object]";
-}
 /**
  * A socket.io Decoder instance
  *
  * @return {Object} decoder
  */
 export class Decoder extends Emitter {
     /**
      * Decoder constructor
-     *
-     * @param {function} reviver - custom reviver to pass down to JSON.stringify
      */
-    constructor(reviver) {
+    constructor(opts) {
         super();
-        this.reviver = reviver;
+        this.opts = Object.assign({
+            reviver: undefined,
+            maxAttachments: 10,
+        }, typeof opts === "function" ? { reviver: opts } : opts);
     }
     /**
      * Decodes an encoded packet string into packet JSON.
      *
@@ -191,9 +188,16 @@
             const buf = str.substring(start, i);
             if (buf != Number(buf) || str.charAt(i) !== "-") {
                 throw new Error("Illegal attachments");
             }
-            p.attachments = Number(buf);
+            const n = Number(buf);
+            if (!isInteger(n) || n < 0) {
+                throw new Error("Illegal attachments");
+            }
+            else if (n > this.opts.maxAttachments) {
+                throw new Error("too many attachments");
+            }
+            p.attachments = n;
         }
         // look up namespace (if any)
         if ("/" === str.charAt(i + 1)) {
             const start = i + 1;
@@ -238,9 +242,9 @@
         return p;
     }
     tryParse(str) {
         try {
-            return JSON.parse(str, this.reviver);
+            return JSON.parse(str, this.opts.reviver);
         }
         catch (e) {
             return false;
         }
@@ -313,4 +317,45 @@
         this.reconPack = null;
         this.buffers = [];
     }
 }
+function isNamespaceValid(nsp) {
+    return typeof nsp === "string";
+}
+// see https://caniuse.com/mdn-javascript_builtins_number_isinteger
+const isInteger = Number.isInteger ||
+    function (value) {
+        return (typeof value === "number" &&
+            isFinite(value) &&
+            Math.floor(value) === value);
+    };
+function isAckIdValid(id) {
+    return id === undefined || isInteger(id);
+}
+// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
+function isObject(value) {
+    return Object.prototype.toString.call(value) === "[object Object]";
+}
+function isDataValid(type, payload) {
+    switch (type) {
+        case PacketType.CONNECT:
+            return payload === undefined || isObject(payload);
+        case PacketType.DISCONNECT:
+            return payload === undefined;
+        case PacketType.EVENT:
+            return (Array.isArray(payload) &&
+                (typeof payload[0] === "number" ||
+                    (typeof payload[0] === "string" &&
+                        RESERVED_EVENTS.indexOf(payload[0]) === -1)));
+        case PacketType.ACK:
+            return Array.isArray(payload);
+        case PacketType.CONNECT_ERROR:
+            return typeof payload === "string" || isObject(payload);
+        default:
+            return false;
+    }
+}
+export function isPacketValid(packet) {
+    return (isNamespaceValid(packet.nsp) &&
+        isAckIdValid(packet.id) &&
+        isDataValid(packet.type, packet.data));
+}
Index: package/build/esm/index.js
===================================================================
--- package/build/esm/index.js
+++ package/build/esm/index.js
@@ -4,13 +4,13 @@
 /**
  * These strings must not be used as event names, as they have a special meaning.
  */
 const RESERVED_EVENTS = [
-    "connect",
-    "connect_error",
-    "disconnect",
-    "disconnecting",
-    "newListener",
+    "connect", // used on the client side
+    "connect_error", // used on the client side
+    "disconnect", // used on both sides
+    "disconnecting", // used on the server side
+    "newListener", // used by the Node.js EventEmitter
     "removeListener", // used by the Node.js EventEmitter
 ];
 /**
  * Protocol version.
@@ -99,26 +99,23 @@
         buffers.unshift(pack); // add packet info to beginning of data list
         return buffers; // write all the buffers
     }
 }
-// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
-function isObject(value) {
-    return Object.prototype.toString.call(value) === "[object Object]";
-}
 /**
  * A socket.io Decoder instance
  *
  * @return {Object} decoder
  */
 export class Decoder extends Emitter {
     /**
      * Decoder constructor
-     *
-     * @param {function} reviver - custom reviver to pass down to JSON.stringify
      */
-    constructor(reviver) {
+    constructor(opts) {
         super();
-        this.reviver = reviver;
+        this.opts = Object.assign({
+            reviver: undefined,
+            maxAttachments: 10,
+        }, typeof opts === "function" ? { reviver: opts } : opts);
     }
     /**
      * Decodes an encoded packet string into packet JSON.
      *
@@ -187,9 +184,16 @@
             const buf = str.substring(start, i);
             if (buf != Number(buf) || str.charAt(i) !== "-") {
                 throw new Error("Illegal attachments");
             }
-            p.attachments = Number(buf);
+            const n = Number(buf);
+            if (!isInteger(n) || n < 0) {
+                throw new Error("Illegal attachments");
+            }
+            else if (n > this.opts.maxAttachments) {
+                throw new Error("too many attachments");
+            }
+            p.attachments = n;
         }
         // look up namespace (if any)
         if ("/" === str.charAt(i + 1)) {
             const start = i + 1;
@@ -233,9 +237,9 @@
         return p;
     }
     tryParse(str) {
         try {
-            return JSON.parse(str, this.reviver);
+            return JSON.parse(str, this.opts.reviver);
         }
         catch (e) {
             return false;
         }
@@ -308,4 +312,45 @@
         this.reconPack = null;
         this.buffers = [];
     }
 }
+function isNamespaceValid(nsp) {
+    return typeof nsp === "string";
+}
+// see https://caniuse.com/mdn-javascript_builtins_number_isinteger
+const isInteger = Number.isInteger ||
+    function (value) {
+        return (typeof value === "number" &&
+            isFinite(value) &&
+            Math.floor(value) === value);
+    };
+function isAckIdValid(id) {
+    return id === undefined || isInteger(id);
+}
+// see https://stackoverflow.com/questions/8511281/check-if-a-value-is-an-object-in-javascript
+function isObject(value) {
+    return Object.prototype.toString.call(value) === "[object Object]";
+}
+function isDataValid(type, payload) {
+    switch (type) {
+        case PacketType.CONNECT:
+            return payload === undefined || isObject(payload);
+        case PacketType.DISCONNECT:
+            return payload === undefined;
+        case PacketType.EVENT:
+            return (Array.isArray(payload) &&
+                (typeof payload[0] === "number" ||
+                    (typeof payload[0] === "string" &&
+                        RESERVED_EVENTS.indexOf(payload[0]) === -1)));
+        case PacketType.ACK:
+            return Array.isArray(payload);
+        case PacketType.CONNECT_ERROR:
+            return typeof payload === "string" || isObject(payload);
+        default:
+            return false;
+    }
+}
+export function isPacketValid(packet) {
+    return (isNamespaceValid(packet.nsp) &&
+        isAckIdValid(packet.id) &&
+        isDataValid(packet.type, packet.data));
+}
Index: package/build/cjs/is-binary.js
===================================================================
--- package/build/cjs/is-binary.js
+++ package/build/cjs/is-binary.js
@@ -1,7 +1,8 @@
 "use strict";
 Object.defineProperty(exports, "__esModule", { value: true });
-exports.hasBinary = exports.isBinary = void 0;
+exports.isBinary = isBinary;
+exports.hasBinary = hasBinary;
 const withNativeArrayBuffer = typeof ArrayBuffer === "function";
 const isView = (obj) => {
     return typeof ArrayBuffer.isView === "function"
         ? ArrayBuffer.isView(obj)
@@ -23,9 +24,8 @@
     return ((withNativeArrayBuffer && (obj instanceof ArrayBuffer || isView(obj))) ||
         (withNativeBlob && obj instanceof Blob) ||
         (withNativeFile && obj instanceof File));
 }
-exports.isBinary = isBinary;
 function hasBinary(obj, toJSON) {
     if (!obj || typeof obj !== "object") {
         return false;
     }
@@ -51,5 +51,4 @@
         }
     }
     return false;
 }
-exports.hasBinary = hasBinary;
Index: package/package.json
===================================================================
--- package/package.json
+++ package/package.json
@@ -1,12 +1,16 @@
 {
   "name": "socket.io-parser",
-  "version": "4.2.4",
+  "version": "4.2.6",
   "description": "socket.io protocol parser",
+  "homepage": "https://github.com/socketio/socket.io/tree/main/packages/socket.io-client#readme",
   "repository": {
     "type": "git",
-    "url": "https://github.com/socketio/socket.io-parser.git"
+    "url": "git+https://github.com/socketio/socket.io.git"
   },
+  "bugs": {
+    "url": "https://github.com/socketio/socket.io/issues"
+  },
   "files": [
     "build/"
   ],
   "main": "./build/cjs/index.js",
@@ -14,35 +18,17 @@
   "types": "./build/esm/index.d.ts",
   "exports": {
     "import": {
       "node": "./build/esm-debug/index.js",
+      "development": "./build/esm-debug/index.js",
       "default": "./build/esm/index.js"
     },
     "require": "./build/cjs/index.js"
   },
   "dependencies": {
     "@socket.io/component-emitter": "~3.1.0",
-    "debug": "~4.3.1"
+    "debug": "~4.4.1"
   },
-  "devDependencies": {
-    "@babel/core": "~7.9.6",
-    "@babel/preset-env": "~7.9.6",
-    "@babel/register": "^7.18.9",
-    "@types/debug": "^4.1.5",
-    "@types/node": "^14.11.1",
-    "@wdio/cli": "^7.26.0",
-    "@wdio/local-runner": "^7.26.0",
-    "@wdio/mocha-framework": "^7.26.0",
-    "@wdio/sauce-service": "^7.26.0",
-    "@wdio/spec-reporter": "^7.26.0",
-    "benchmark": "2.1.2",
-    "expect.js": "0.3.1",
-    "mocha": "^10.1.0",
-    "prettier": "^2.1.2",
-    "rimraf": "^3.0.2",
-    "typescript": "^4.0.3",
-    "wdio-geckodriver-service": "^4.0.0"
-  },
   "scripts": {
     "compile": "rimraf ./build && tsc && tsc -p tsconfig.esm.json && ./postcompile.sh",
     "test": "npm run format:check && npm run compile && if test \"$BROWSERS\" = \"1\" ; then npm run test:browser; else npm run test:node; fi",
     "test:node": "mocha --reporter dot --bail test/index.js",
Index: package/build/cjs/index.d.ts
===================================================================
--- package/build/cjs/index.d.ts
+++ package/build/cjs/index.d.ts
@@ -52,22 +52,32 @@
 }
 interface DecoderReservedEvents {
     decoded: (packet: Packet) => void;
 }
+type JSONReviver = (this: any, key: string, value: any) => any;
+export interface DecoderOptions {
+    /**
+     * Custom reviver to pass down to JSON.parse()
+     */
+    reviver?: JSONReviver;
+    /**
+     * Maximum number of binary attachments per packet
+     * @default 10
+     */
+    maxAttachments?: number;
+}
 /**
  * A socket.io Decoder instance
  *
  * @return {Object} decoder
  */
 export declare class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
-    private reviver?;
     private reconstructor;
+    private opts;
     /**
      * Decoder constructor
-     *
-     * @param {function} reviver - custom reviver to pass down to JSON.stringify
      */
-    constructor(reviver?: (this: any, key: string, value: any) => any);
+    constructor(opts?: DecoderOptions | JSONReviver);
     /**
      * Decodes an encoded packet string into packet JSON.
      *
      * @param {String} obj - encoded packet
@@ -86,5 +96,6 @@
      * Deallocates a parser's resources
      */
     destroy(): void;
 }
+export declare function isPacketValid(packet: Packet): boolean;
 export {};
Index: package/build/esm-debug/index.d.ts
===================================================================
--- package/build/esm-debug/index.d.ts
+++ package/build/esm-debug/index.d.ts
@@ -52,22 +52,32 @@
 }
 interface DecoderReservedEvents {
     decoded: (packet: Packet) => void;
 }
+type JSONReviver = (this: any, key: string, value: any) => any;
+export interface DecoderOptions {
+    /**
+     * Custom reviver to pass down to JSON.parse()
+     */
+    reviver?: JSONReviver;
+    /**
+     * Maximum number of binary attachments per packet
+     * @default 10
+     */
+    maxAttachments?: number;
+}
 /**
  * A socket.io Decoder instance
  *
  * @return {Object} decoder
  */
 export declare class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
-    private reviver?;
     private reconstructor;
+    private opts;
     /**
      * Decoder constructor
-     *
-     * @param {function} reviver - custom reviver to pass down to JSON.stringify
      */
-    constructor(reviver?: (this: any, key: string, value: any) => any);
+    constructor(opts?: DecoderOptions | JSONReviver);
     /**
      * Decodes an encoded packet string into packet JSON.
      *
      * @param {String} obj - encoded packet
@@ -86,5 +96,6 @@
      * Deallocates a parser's resources
      */
     destroy(): void;
 }
+export declare function isPacketValid(packet: Packet): boolean;
 export {};
Index: package/build/esm/index.d.ts
===================================================================
--- package/build/esm/index.d.ts
+++ package/build/esm/index.d.ts
@@ -52,22 +52,32 @@
 }
 interface DecoderReservedEvents {
     decoded: (packet: Packet) => void;
 }
+type JSONReviver = (this: any, key: string, value: any) => any;
+export interface DecoderOptions {
+    /**
+     * Custom reviver to pass down to JSON.parse()
+     */
+    reviver?: JSONReviver;
+    /**
+     * Maximum number of binary attachments per packet
+     * @default 10
+     */
+    maxAttachments?: number;
+}
 /**
  * A socket.io Decoder instance
  *
  * @return {Object} decoder
  */
 export declare class Decoder extends Emitter<{}, {}, DecoderReservedEvents> {
-    private reviver?;
     private reconstructor;
+    private opts;
     /**
      * Decoder constructor
-     *
-     * @param {function} reviver - custom reviver to pass down to JSON.stringify
      */
-    constructor(reviver?: (this: any, key: string, value: any) => any);
+    constructor(opts?: DecoderOptions | JSONReviver);
     /**
      * Decodes an encoded packet string into packet JSON.
      *
      * @param {String} obj - encoded packet
@@ -86,5 +96,6 @@
      * Deallocates a parser's resources
      */
     destroy(): void;
 }
+export declare function isPacketValid(packet: Packet): boolean;
 export {};
Index: package/build/cjs/is-binary.d.ts
===================================================================
--- package/build/cjs/is-binary.d.ts
+++ package/build/cjs/is-binary.d.ts
@@ -3,5 +3,5 @@
  *
  * @private
  */
 export declare function isBinary(obj: any): boolean;
-export declare function hasBinary(obj: any, toJSON?: boolean): any;
+export declare function hasBinary(obj: any, toJSON?: boolean): boolean;
Index: package/build/esm-debug/is-binary.d.ts
===================================================================
--- package/build/esm-debug/is-binary.d.ts
+++ package/build/esm-debug/is-binary.d.ts
@@ -3,5 +3,5 @@
  *
  * @private
  */
 export declare function isBinary(obj: any): boolean;
-export declare function hasBinary(obj: any, toJSON?: boolean): any;
+export declare function hasBinary(obj: any, toJSON?: boolean): boolean;
Index: package/build/esm/is-binary.d.ts
===================================================================
--- package/build/esm/is-binary.d.ts
+++ package/build/esm/is-binary.d.ts
@@ -3,5 +3,5 @@
  *
  * @private
  */
 export declare function isBinary(obj: any): boolean;
-export declare function hasBinary(obj: any, toJSON?: boolean): any;
+export declare function hasBinary(obj: any, toJSON?: boolean): boolean;