mirror of
https://github.com/socketio/socket.io.git
synced 2026-04-30 03:00:39 -04:00
Compare commits
13 Commits
socket.io-
...
socket.io-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
17bc1d65cf | ||
|
|
2ba71db5c3 | ||
|
|
9d39f1f080 | ||
|
|
6b2f875339 | ||
|
|
1e9ebc6b7f | ||
|
|
ee00660749 | ||
|
|
cd11e38e1a | ||
|
|
fb21e422fc | ||
|
|
3b0a3925fd | ||
|
|
89197a05c4 | ||
|
|
25ca624b0d | ||
|
|
b51b39b78d | ||
|
|
4184e46534 |
35
.github/workflows/ci.yml
vendored
Normal file
35
.github/workflows/ci.yml
vendored
Normal file
@@ -0,0 +1,35 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- 'socket.io-parser/3.3.x'
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test-node:
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 10
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
node-version:
|
||||
- 16
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Use Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: ${{ matrix.node-version }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Run tests
|
||||
run: npm test
|
||||
31
.github/workflows/publish.yml
vendored
Normal file
31
.github/workflows/publish.yml
vendored
Normal file
@@ -0,0 +1,31 @@
|
||||
# reference: https://docs.npmjs.com/trusted-publishers#for-github-actions
|
||||
|
||||
name: Publish
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'socket.io-parser@*'
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
id-token: write
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Use Node.js 24
|
||||
uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: 24
|
||||
registry-url: 'https://registry.npmjs.org'
|
||||
|
||||
- name: Install dependencies
|
||||
run: npm ci
|
||||
|
||||
- name: Publish package
|
||||
run: npm publish --tag v2-latest
|
||||
@@ -7,7 +7,7 @@ git:
|
||||
depth: 1
|
||||
matrix:
|
||||
include:
|
||||
- node_js: node
|
||||
- node_js: 10
|
||||
env: BROWSERS=1
|
||||
cache:
|
||||
directories:
|
||||
|
||||
37
CHANGELOG.md
Normal file
37
CHANGELOG.md
Normal file
@@ -0,0 +1,37 @@
|
||||
## [3.3.5](https://github.com/socketio/socket.io-parser/compare/3.3.4...3.3.5) (2026-03-17)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add a limit to the number of binary attachments ([9d39f1f](https://github.com/socketio/socket.io/commit/9d39f1f080510f036782f2177fac701cc041faaf))
|
||||
|
||||
|
||||
|
||||
## [3.3.4](https://github.com/Automattic/socket.io-parser/compare/3.3.3...3.3.4) (2024-07-22)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the event name ([#125](https://github.com/Automattic/socket.io-parser/issues/125)) ([ee00660](https://github.com/Automattic/socket.io-parser/commit/ee006607495eca4ec7262ad080dd3a91439a5ba4))
|
||||
|
||||
|
||||
|
||||
## [3.3.3](https://github.com/Automattic/socket.io-parser/compare/3.3.2...3.3.3) (2022-11-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* check the format of the index of each attachment ([fb21e42](https://github.com/Automattic/socket.io-parser/commit/fb21e422fc193b34347395a33e0f625bebc09983))
|
||||
|
||||
|
||||
|
||||
## [3.3.2](https://github.com/Automattic/socket.io-parser/compare/3.3.1...3.3.2) (2021-01-09)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* prevent DoS (OOM) via massive packets ([#95](https://github.com/Automattic/socket.io-parser/issues/95)) ([89197a0](https://github.com/Automattic/socket.io-parser/commit/89197a05c43b18cc4569fd178d56e7bb8f403865))
|
||||
|
||||
|
||||
## [3.3.1](https://github.com/socketio/socket.io-parser/compare/3.3.0...3.3.1) (2020-09-30)
|
||||
|
||||
12
binary.js
12
binary.js
@@ -70,8 +70,16 @@ exports.reconstructPacket = function(packet, buffers) {
|
||||
function _reconstructPacket(data, buffers) {
|
||||
if (!data) return data;
|
||||
|
||||
if (data && data._placeholder) {
|
||||
return buffers[data.num]; // appropriate buffer (should be natural order anyway)
|
||||
if (data && data._placeholder === true) {
|
||||
var isIndexValid =
|
||||
typeof data.num === "number" &&
|
||||
data.num >= 0 &&
|
||||
data.num < buffers.length;
|
||||
if (isIndexValid) {
|
||||
return buffers[data.num]; // appropriate buffer (should be natural order anyway)
|
||||
} else {
|
||||
throw new Error("illegal attachments");
|
||||
}
|
||||
} else if (isArray(data)) {
|
||||
for (var i = 0; i < data.length; i++) {
|
||||
data[i] = _reconstructPacket(data[i], buffers);
|
||||
|
||||
74
index.js
74
index.js
@@ -218,8 +218,12 @@ function encodeAsBinary(obj, callback) {
|
||||
* @api public
|
||||
*/
|
||||
|
||||
function Decoder() {
|
||||
function Decoder(opts) {
|
||||
this.reconstructor = null;
|
||||
opts = opts || {};
|
||||
this.opts = {
|
||||
maxAttachments: opts.maxAttachments || 10,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +243,10 @@ Emitter(Decoder.prototype);
|
||||
Decoder.prototype.add = function(obj) {
|
||||
var packet;
|
||||
if (typeof obj === 'string') {
|
||||
packet = decodeString(obj);
|
||||
if (this.reconstructor) {
|
||||
throw new Error("got plaintext data when reconstructing a packet");
|
||||
}
|
||||
packet = decodeString(obj, this.opts.maxAttachments);
|
||||
if (exports.BINARY_EVENT === packet.type || exports.BINARY_ACK === packet.type) { // binary packet's json
|
||||
this.reconstructor = new BinaryReconstructor(packet);
|
||||
|
||||
@@ -265,15 +272,36 @@ Decoder.prototype.add = function(obj) {
|
||||
}
|
||||
};
|
||||
|
||||
function isPayloadValid(type, payload) {
|
||||
switch (type) {
|
||||
case 0: // CONNECT
|
||||
return typeof payload === "object";
|
||||
case 1: // DISCONNECT
|
||||
return payload === undefined;
|
||||
case 4: // ERROR
|
||||
return typeof payload === "string" || typeof payload === "object";
|
||||
case 2: // EVENT
|
||||
case 5: // BINARY_EVENT
|
||||
return (
|
||||
isArray(payload) &&
|
||||
(typeof payload[0] === "string" || typeof payload[0] === "number")
|
||||
);
|
||||
case 3: // ACK
|
||||
case 6: // BINARY_ACK
|
||||
return isArray(payload);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode a packet String (JSON data)
|
||||
*
|
||||
* @param {String} str
|
||||
* @param {Number} maxAttachments - the maximum number of binary attachments
|
||||
* @return {Object} packet
|
||||
* @api private
|
||||
*/
|
||||
|
||||
function decodeString(str) {
|
||||
function decodeString(str, maxAttachments) {
|
||||
var i = 0;
|
||||
// look up type
|
||||
var p = {
|
||||
@@ -286,26 +314,30 @@ function decodeString(str) {
|
||||
|
||||
// look up attachments if type binary
|
||||
if (exports.BINARY_EVENT === p.type || exports.BINARY_ACK === p.type) {
|
||||
var buf = '';
|
||||
while (str.charAt(++i) !== '-') {
|
||||
buf += str.charAt(i);
|
||||
if (i == str.length) break;
|
||||
}
|
||||
var start = i + 1;
|
||||
while (str.charAt(++i) !== '-' && i != str.length) {}
|
||||
var buf = str.substring(start, i);
|
||||
if (buf != Number(buf) || str.charAt(i) !== '-') {
|
||||
throw new Error('Illegal attachments');
|
||||
}
|
||||
p.attachments = Number(buf);
|
||||
var n = Number(buf);
|
||||
if (!isInteger(n) || n < 0) {
|
||||
throw new Error("Illegal attachments");
|
||||
} else if (n > maxAttachments) {
|
||||
throw new Error("too many attachments");
|
||||
}
|
||||
p.attachments = n;
|
||||
}
|
||||
|
||||
// look up namespace (if any)
|
||||
if ('/' === str.charAt(i + 1)) {
|
||||
p.nsp = '';
|
||||
var start = i + 1;
|
||||
while (++i) {
|
||||
var c = str.charAt(i);
|
||||
if (',' === c) break;
|
||||
p.nsp += c;
|
||||
if (i === str.length) break;
|
||||
}
|
||||
p.nsp = str.substring(start, i);
|
||||
} else {
|
||||
p.nsp = '/';
|
||||
}
|
||||
@@ -313,27 +345,25 @@ function decodeString(str) {
|
||||
// look up id
|
||||
var next = str.charAt(i + 1);
|
||||
if ('' !== next && Number(next) == next) {
|
||||
p.id = '';
|
||||
var start = i + 1;
|
||||
while (++i) {
|
||||
var c = str.charAt(i);
|
||||
if (null == c || Number(c) != c) {
|
||||
--i;
|
||||
break;
|
||||
}
|
||||
p.id += str.charAt(i);
|
||||
if (i === str.length) break;
|
||||
}
|
||||
p.id = Number(p.id);
|
||||
p.id = Number(str.substring(start, i + 1));
|
||||
}
|
||||
|
||||
// look up json data
|
||||
if (str.charAt(++i)) {
|
||||
var payload = tryParse(str.substr(i));
|
||||
var isPayloadValid = payload !== false && (p.type === exports.ERROR || isArray(payload));
|
||||
if (isPayloadValid) {
|
||||
if (isPayloadValid(p.type, payload)) {
|
||||
p.data = payload;
|
||||
} else {
|
||||
return error('invalid payload');
|
||||
throw new Error("invalid payload");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,3 +443,13 @@ function error(msg) {
|
||||
data: 'parser error: ' + msg
|
||||
};
|
||||
}
|
||||
|
||||
var isInteger =
|
||||
Number.isInteger ||
|
||||
function (value) {
|
||||
return (
|
||||
typeof value === "number" &&
|
||||
isFinite(value) &&
|
||||
Math.floor(value) === value
|
||||
);
|
||||
};
|
||||
|
||||
6961
package-lock.json
generated
Normal file
6961
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,10 +1,10 @@
|
||||
{
|
||||
"name": "socket.io-parser",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.5",
|
||||
"description": "socket.io protocol parser",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Automattic/socket.io-parser.git"
|
||||
"url": "git+https://github.com/socketio/socket.io.git"
|
||||
},
|
||||
"files": [
|
||||
"binary.js",
|
||||
@@ -12,8 +12,8 @@
|
||||
"is-buffer.js"
|
||||
],
|
||||
"dependencies": {
|
||||
"component-emitter": "~1.3.0",
|
||||
"debug": "~3.1.0",
|
||||
"component-emitter": "1.2.1",
|
||||
"isarray": "2.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||
@@ -50,7 +50,7 @@ describe('parser', function() {
|
||||
it('cleans itself up on close', function() {
|
||||
var packet = {
|
||||
type: parser.BINARY_EVENT,
|
||||
data: [new ArrayBuffer(2), new ArrayBuffer(3)],
|
||||
data: ["foo", new ArrayBuffer(2), new ArrayBuffer(3)],
|
||||
id: 0,
|
||||
nsp: '/'
|
||||
};
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
var parser = require('../index.js');
|
||||
var expect = require('expect.js');
|
||||
var helpers = require('./helpers.js');
|
||||
var encode = parser.encode;
|
||||
var decode = parser.decode;
|
||||
var Decoder = parser.Decoder;
|
||||
|
||||
describe('parser', function() {
|
||||
it('encodes a Buffer', function() {
|
||||
@@ -14,6 +13,15 @@ describe('parser', function() {
|
||||
});
|
||||
});
|
||||
|
||||
it("encodes a nested Buffer", function() {
|
||||
helpers.test_bin({
|
||||
type: parser.BINARY_EVENT,
|
||||
data: ["a", { b: ["c", Buffer.from("abc", "utf8")] }],
|
||||
id: 23,
|
||||
nsp: "/cool",
|
||||
});
|
||||
});
|
||||
|
||||
it('encodes a binary ack with Buffer', function() {
|
||||
helpers.test_bin({
|
||||
type: parser.BINARY_ACK,
|
||||
@@ -22,4 +30,39 @@ describe('parser', function() {
|
||||
nsp: '/back'
|
||||
})
|
||||
});
|
||||
|
||||
it("throws an error when adding an attachment with an invalid 'num' attribute (string)", function() {
|
||||
var decoder = new Decoder();
|
||||
|
||||
expect(function() {
|
||||
decoder.add('51-["hello",{"_placeholder":true,"num":"splice"}]');
|
||||
decoder.add(Buffer.from("world"));
|
||||
}).to.throwException(/^illegal attachments$/);
|
||||
});
|
||||
|
||||
it("throws an error when adding an attachment with an invalid 'num' attribute (out-of-bound)", function() {
|
||||
var decoder = new Decoder();
|
||||
|
||||
expect(function() {
|
||||
decoder.add('51-["hello",{"_placeholder":true,"num":1}]');
|
||||
decoder.add(Buffer.from("world"));
|
||||
}).to.throwException(/^illegal attachments$/);
|
||||
});
|
||||
|
||||
it("throws an error when adding an attachment without header", function() {
|
||||
var decoder = new Decoder();
|
||||
|
||||
expect(function() {
|
||||
decoder.add(Buffer.from("world"));
|
||||
}).to.throwException(/^got binary data when not reconstructing a packet$/);
|
||||
});
|
||||
|
||||
it("throws an error when decoding a binary event without attachments", function() {
|
||||
var decoder = new Decoder();
|
||||
|
||||
expect(function() {
|
||||
decoder.add('51-["hello",{"_placeholder":true,"num":0}]');
|
||||
decoder.add('2["hello"]');
|
||||
}).to.throwException(/^got plaintext data when reconstructing a packet$/);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -86,12 +86,41 @@ describe('parser', function(){
|
||||
}
|
||||
});
|
||||
|
||||
it('returns an error packet on parsing error', function(done){
|
||||
var decoder = new parser.Decoder();
|
||||
decoder.on('decoded', function(packet) {
|
||||
expect(packet).to.eql({ type: 4, data: 'parser error: invalid payload' });
|
||||
done();
|
||||
});
|
||||
decoder.add('442["some","data"');
|
||||
it('returns an error packet on parsing error', function(){
|
||||
function isInvalidPayload (str) {
|
||||
expect(function () {
|
||||
new parser.Decoder().add(str)
|
||||
}).to.throwException(/^invalid payload$/);
|
||||
}
|
||||
|
||||
isInvalidPayload('442["some","data"');
|
||||
isInvalidPayload('0/admin,"invalid"');
|
||||
isInvalidPayload("1/admin,{}");
|
||||
isInvalidPayload('2/admin,"invalid');
|
||||
isInvalidPayload("2/admin,{}");
|
||||
isInvalidPayload('2[{"toString":"foo"}]');
|
||||
isInvalidPayload('2[true,"foo"]');
|
||||
isInvalidPayload('2[null,"bar"]');
|
||||
|
||||
function isInvalidAttachmentCount (str) {
|
||||
expect(() => new parser.Decoder().add(str)).to.throwException(
|
||||
/^Illegal attachments$/,
|
||||
);
|
||||
}
|
||||
|
||||
isInvalidAttachmentCount("5");
|
||||
isInvalidAttachmentCount("51");
|
||||
isInvalidAttachmentCount("5a-");
|
||||
isInvalidAttachmentCount("51.23-");
|
||||
});
|
||||
|
||||
it("throws an error when receiving too many attachments", () => {
|
||||
const decoder = new parser.Decoder({ maxAttachments: 2 });
|
||||
|
||||
expect(() => {
|
||||
decoder.add(
|
||||
'53-["hello",{"_placeholder":true,"num":0},{"_placeholder":true,"num":1},{"_placeholder":true,"num":2}]',
|
||||
);
|
||||
}).to.throwException(/^too many attachments$/);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user