diff --git a/index.js b/index.js index 50ff90e4..22099abf 100644 --- a/index.js +++ b/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, + }; } /** @@ -242,7 +246,7 @@ Decoder.prototype.add = function(obj) { if (this.reconstructor) { throw new Error("got plaintext data when reconstructing a packet"); } - packet = decodeString(obj); + 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); @@ -272,11 +276,12 @@ Decoder.prototype.add = function(obj) { * 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 = { @@ -295,7 +300,13 @@ function decodeString(str) { 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) @@ -432,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 + ); + }; diff --git a/test/parser.js b/test/parser.js index 7d560bf0..f2010a1b 100644 --- a/test/parser.js +++ b/test/parser.js @@ -101,5 +101,26 @@ describe('parser', function(){ 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$/); }); });