Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

ws

Package Overview
Dependencies
Maintainers
4
Versions
169
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

ws - npm Package Compare versions

Comparing version 2.1.0 to 2.2.0

lib/Constants.js

49

lib/BufferUtil.js

@@ -14,3 +14,50 @@ 'use strict';

} catch (e) {
module.exports = require('./BufferUtil.fallback');
/**
* Merges an array of buffers into a target buffer.
*
* @param {Buffer} target The target buffer
* @param {Buffer[]} buffers The array of buffers to merge
* @public
*/
const merge = (target, buffers) => {
var offset = 0;
for (var i = 0; i < buffers.length; i++) {
const buf = buffers[i];
buf.copy(target, offset);
offset += buf.length;
}
};
/**
* Masks a buffer using the given mask.
*
* @param {Buffer} source The buffer to mask
* @param {Buffer} mask The mask to use
* @param {Buffer} output The buffer where to store the result
* @param {Number} offset The offset at which to start writing
* @param {Number} length The number of bytes to mask.
* @public
*/
const mask = (source, mask, output, offset, length) => {
for (var i = 0; i < length; i++) {
output[offset + i] = source[i] ^ mask[i & 3];
}
};
/**
* Unmasks a buffer using the given mask.
*
* @param {Buffer} buffer The buffer to unmask
* @param {Buffer} mask The mask to use
* @public
*/
const unmask = (buffer, mask) => {
// Required until https://github.com/nodejs/node/issues/9006 is resolved.
const length = buffer.length;
for (var i = 0; i < length; i++) {
buffer[i] ^= mask[i & 3];
}
};
module.exports = { merge, mask, unmask };
}

5

lib/EventTarget.js

@@ -31,3 +31,3 @@ 'use strict';

*
* @param {(String|Buffer|ArrayBuffer)} data The received data
* @param {(String|Buffer|ArrayBuffer|Buffer[])} data The received data
* @param {Boolean} isBinary Specifies if `data` is binary

@@ -104,5 +104,2 @@ * @param {WebSocket} target A reference to the target to which the event was dispatched

function onMessage (data, flags) {
if (flags.binary && this.binaryType === 'arraybuffer') {
data = new Uint8Array(data).buffer;
}
listener.call(this, new MessageEvent(data, !!flags.binary, this));

@@ -109,0 +106,0 @@ }

@@ -13,5 +13,4 @@ /*!

const ErrorCodes = require('./ErrorCodes');
const constants = require('./Constants');
const EMPTY_BUFFER = Buffer.alloc(0);
const GET_INFO = 0;

@@ -33,4 +32,6 @@ const GET_PAYLOAD_LENGTH_16 = 1;

* @param {Number} maxPayload The maximum allowed message length
* @param {String} binaryType The type for binary data
*/
constructor (extensions, maxPayload) {
constructor (extensions, maxPayload, binaryType) {
this.binaryType = binaryType || constants.BINARY_TYPES[0];
this.extensions = extensions || {};

@@ -90,3 +91,3 @@ this.maxPayload = maxPayload | 0;

dst = new Buffer(bytes);
dst = Buffer.allocUnsafe(bytes);

@@ -313,3 +314,3 @@ while (bytes > 0) {

getData () {
var data = EMPTY_BUFFER;
var data = constants.EMPTY_BUFFER;

@@ -360,16 +361,25 @@ if (this.payloadLength) {

if (this.fin) {
const buf = this.fragments.length > 1
? Buffer.concat(this.fragments, this.messageLength)
: this.fragments.length === 1
? this.fragments[0]
: EMPTY_BUFFER;
const messageLength = this.messageLength;
const fragments = this.fragments;
this.totalPayloadLength = 0;
this.fragments.length = 0;
this.messageLength = 0;
this.fragmented = 0;
this.fragments = [];
if (this.opcode === 2) {
this.onmessage(buf, { masked: this.masked, binary: true });
var data;
if (this.binaryType === 'nodebuffer') {
data = toBuffer(fragments, messageLength);
} else if (this.binaryType === 'arraybuffer') {
data = toArrayBuffer(toBuffer(fragments, messageLength));
} else {
data = fragments;
}
this.onmessage(data, { masked: this.masked, binary: true });
} else {
const buf = toBuffer(fragments, messageLength);
if (!isValidUTF8(buf)) {

@@ -519,1 +529,29 @@ this.error(new Error('invalid utf8 sequence'), 1007);

module.exports = Receiver;
/**
* Makes a buffer from a list of fragments.
*
* @param {Buffer[]} fragments The list of fragments composing the message
* @param {Number} messageLength The length of the message
* @return {Buffer}
* @private
*/
function toBuffer (fragments, messageLength) {
if (fragments.length === 1) return fragments[0];
if (fragments.length > 1) return Buffer.concat(fragments, messageLength);
return constants.EMPTY_BUFFER;
}
/**
* Converts a buffer to an `ArrayBuffer`.
*
* @param {Buffer} The buffer to convert
* @return {ArrayBuffer} Converted buffer
*/
function toArrayBuffer (buf) {
if (buf.byteOffset === 0 && buf.byteLength === buf.buffer.byteLength) {
return buf.buffer;
}
return buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
}

@@ -40,2 +40,67 @@ /*!

/**
* Frames a piece of data according to the HyBi WebSocket protocol.
*
* @param {Buffer} data The data to frame
* @param {Object} options Options object
* @param {Number} options.opcode The opcode
* @param {Boolean} options.readOnly Specifies whether `data` can be modified
* @param {Boolean} options.fin Specifies whether or not to set the FIN bit
* @param {Boolean} options.mask Specifies whether or not to mask `data`
* @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit
* @return {Buffer[]} The framed data as a list of `Buffer` instances
* @public
*/
static frame (data, options) {
const merge = data.length < 1024 || options.mask && options.readOnly;
var offset = options.mask ? 6 : 2;
var payloadLength = data.length;
if (data.length >= 65536) {
offset += 8;
payloadLength = 127;
} else if (data.length > 125) {
offset += 2;
payloadLength = 126;
}
const target = Buffer.allocUnsafe(merge ? data.length + offset : offset);
target[0] = options.fin ? options.opcode | 0x80 : options.opcode;
if (options.rsv1) target[0] |= 0x40;
if (payloadLength === 126) {
target.writeUInt16BE(data.length, 2, true);
} else if (payloadLength === 127) {
target.writeUInt32BE(0, 2, true);
target.writeUInt32BE(data.length, 6, true);
}
if (!options.mask) {
target[1] = payloadLength;
if (merge) {
data.copy(target, offset);
return [target];
}
return [target, data];
}
const mask = crypto.randomBytes(4);
target[1] = payloadLength | 0x80;
target[offset - 4] = mask[0];
target[offset - 3] = mask[1];
target[offset - 2] = mask[2];
target[offset - 1] = mask[3];
if (merge) {
bufferUtil.mask(data, mask, target, offset, data.length);
return [target];
}
bufferUtil.mask(data, mask, data, 0, data.length);
return [target, data];
}
/**
* Sends a close message to the other peer.

@@ -75,3 +140,3 @@ *

doClose (data, mask, cb) {
this.frameAndSend(data, {
this.sendFrame(Sender.frame(data, {
readOnly: false,

@@ -82,3 +147,3 @@ opcode: 0x08,

mask
}, cb);
}), cb);
}

@@ -96,3 +161,3 @@

if (data && !Buffer.isBuffer(data)) {
if (!Buffer.isBuffer(data)) {
if (data instanceof ArrayBuffer) {

@@ -124,3 +189,3 @@ data = Buffer.from(data);

doPing (data, mask, readOnly) {
this.frameAndSend(data, {
this.sendFrame(Sender.frame(data, {
opcode: 0x09,

@@ -131,3 +196,3 @@ rsv1: false,

mask
});
}));
}

@@ -145,3 +210,3 @@

if (data && !Buffer.isBuffer(data)) {
if (!Buffer.isBuffer(data)) {
if (data instanceof ArrayBuffer) {

@@ -173,3 +238,3 @@ data = Buffer.from(data);

doPong (data, mask, readOnly) {
this.frameAndSend(data, {
this.sendFrame(Sender.frame(data, {
opcode: 0x0a,

@@ -180,3 +245,3 @@ rsv1: false,

mask
});
}));
}

@@ -201,3 +266,3 @@

if (data && !Buffer.isBuffer(data)) {
if (!Buffer.isBuffer(data)) {
if (data instanceof ArrayBuffer) {

@@ -215,3 +280,3 @@ data = Buffer.from(data);

this.firstFragment = false;
if (rsv1 && data && this.perMessageDeflate) {
if (rsv1 && this.perMessageDeflate) {
rsv1 = data.length >= this.perMessageDeflate.threshold;

@@ -243,3 +308,3 @@ }

} else {
this.frameAndSend(data, {
this.sendFrame(Sender.frame(data, {
mask: options.mask,

@@ -250,3 +315,3 @@ fin: options.fin,

opcode
}, cb);
}), cb);
}

@@ -271,3 +336,3 @@ }

if (!options.compress) {
this.frameAndSend(data, options, cb);
this.sendFrame(Sender.frame(data, options), cb);
return;

@@ -285,3 +350,3 @@ }

options.readOnly = false;
this.frameAndSend(buf, options, cb);
this.sendFrame(Sender.frame(buf, options), cb);
this.deflating = false;

@@ -293,77 +358,2 @@ this.dequeue();

/**
* Frames and sends a piece of data according to the HyBi WebSocket protocol.
*
* @param {Buffer} data The data to send
* @param {Object} options Options object
* @param {Number} options.opcode The opcode
* @param {Boolean} options.readOnly Specifies whether `data` can be modified
* @param {Boolean} options.fin Specifies whether or not to set the FIN bit
* @param {Boolean} options.mask Specifies whether or not to mask `data`
* @param {Boolean} options.rsv1 Specifies whether or not to set the RSV1 bit
* @param {Function} cb Callback
* @private
*/
frameAndSend (data, options, cb) {
if (!data) {
const bytes = [options.opcode, 0];
if (options.fin) bytes[0] |= 0x80;
if (options.mask) {
bytes[1] |= 0x80;
bytes.push(0, 0, 0, 0);
}
sendFramedData(this, Buffer.from(bytes), null, cb);
return;
}
const mergeBuffers = data.length < 1024 || options.mask && options.readOnly;
var dataOffset = options.mask ? 6 : 2;
var payloadLength = data.length;
if (data.length >= 65536) {
dataOffset += 8;
payloadLength = 127;
} else if (data.length > 125) {
dataOffset += 2;
payloadLength = 126;
}
const outputBuffer = Buffer.allocUnsafe(
mergeBuffers ? data.length + dataOffset : dataOffset
);
outputBuffer[0] = options.fin ? options.opcode | 0x80 : options.opcode;
if (options.rsv1) outputBuffer[0] |= 0x40;
if (payloadLength === 126) {
outputBuffer.writeUInt16BE(data.length, 2, true);
} else if (payloadLength === 127) {
outputBuffer.writeUInt32BE(0, 2, true);
outputBuffer.writeUInt32BE(data.length, 6, true);
}
if (options.mask) {
const mask = getRandomMask();
outputBuffer[1] = payloadLength | 0x80;
outputBuffer[dataOffset - 4] = mask[0];
outputBuffer[dataOffset - 3] = mask[1];
outputBuffer[dataOffset - 2] = mask[2];
outputBuffer[dataOffset - 1] = mask[3];
if (mergeBuffers) {
bufferUtil.mask(data, mask, outputBuffer, dataOffset, data.length);
} else {
bufferUtil.mask(data, mask, data, 0, data.length);
}
} else {
outputBuffer[1] = payloadLength;
if (mergeBuffers) data.copy(outputBuffer, dataOffset);
}
sendFramedData(this, outputBuffer, mergeBuffers ? null : data, cb);
}
/**
* Executes queued send operations.

@@ -377,3 +367,3 @@ *

if (params[1]) this.bufferedBytes -= params[1].length;
this.bufferedBytes -= params[1].length;
params[0].apply(this, params.slice(1));

@@ -390,5 +380,21 @@ }

enqueue (params) {
if (params[1]) this.bufferedBytes += params[1].length;
this.bufferedBytes += params[1].length;
this.queue.push(params);
}
/**
* Sends a frame.
*
* @param {Buffer[]} list The frame to send
* @param {Function} cb Callback
* @private
*/
sendFrame (list, cb) {
if (list.length === 2) {
this._socket.write(list[0]);
this._socket.write(list[1], cb);
} else {
this._socket.write(list[0], cb);
}
}
}

@@ -414,29 +420,1 @@

}
/**
* Generates a random mask.
*
* @return {Buffer} The mask
* @private
*/
function getRandomMask () {
return crypto.randomBytes(4);
}
/**
* Sends a frame.
*
* @param {Sender} sender Sender instance
* @param {Buffer} outputBuffer The data to send
* @param {Buffer} data Additional data to send if frame is split into two buffers
* @param {Function} cb Callback
* @private
*/
function sendFramedData (sender, outputBuffer, data, cb) {
if (data) {
sender._socket.write(outputBuffer);
sender._socket.write(data, cb);
} else {
sender._socket.write(outputBuffer, cb);
}
}

@@ -16,3 +16,3 @@ /*!

} catch (e) {
module.exports = require('./Validation.fallback');
module.exports = () => true;
}

@@ -19,9 +19,8 @@ /*!

const Extensions = require('./Extensions');
const constants = require('./Constants');
const Receiver = require('./Receiver');
const Sender = require('./Sender');
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
const closeTimeout = 30 * 1000; // Allow 30 seconds to terminate the connection cleanly.
const protocolVersion = 13;
const noop = () => {};

@@ -57,4 +56,4 @@ /**

this._binaryType = constants.BINARY_TYPES[0];
this._finalize = this.finalize.bind(this);
this._binaryType = 'nodebuffer';
this._finalizeCalled = false;

@@ -104,7 +103,10 @@ this._closeMessage = null;

set binaryType (type) {
if (type === 'arraybuffer' || type === 'nodebuffer') {
this._binaryType = type;
} else {
throw new SyntaxError('unsupported binaryType: must be either "nodebuffer" or "arraybuffer"');
}
if (constants.BINARY_TYPES.indexOf(type) < 0) return;
this._binaryType = type;
//
// Allow to change `binaryType` on the fly.
//
if (this._receiver) this._receiver.binaryType = type;
}

@@ -123,3 +125,3 @@

this._receiver = new Receiver(this.extensions, this.maxPayload);
this._receiver = new Receiver(this.extensions, this.maxPayload, this.binaryType);
this._sender = new Sender(socket, this.extensions);

@@ -237,3 +239,3 @@ this._ultron = new Ultron(socket);

this.removeAllListeners();
this.on('error', noop); // Catch all errors after this.
this.on('error', constants.NOOP); // Catch all errors after this.
}

@@ -319,3 +321,3 @@

if (mask === undefined) mask = !this._isServer;
this._sender.ping(data, mask);
this._sender.ping(data || constants.EMPTY_BUFFER, mask);
}

@@ -339,3 +341,3 @@

if (mask === undefined) mask = !this._isServer;
this._sender.pong(data, mask);
this._sender.pong(data || constants.EMPTY_BUFFER, mask);
}

@@ -368,9 +370,8 @@

if (typeof data === 'number') data = data.toString();
else if (!data) data = '';
const opts = Object.assign({
fin: true,
binary: typeof data !== 'string',
mask: !this._isServer,
compress: true
compress: true,
fin: true
}, options);

@@ -382,3 +383,3 @@

this._sender.send(data, opts, cb);
this._sender.send(data || constants.EMPTY_BUFFER, opts, cb);
}

@@ -674,3 +675,3 @@

const digest = crypto.createHash('sha1')
.update(key + GUID, 'binary')
.update(key + constants.GUID, 'binary')
.digest('base64');

@@ -677,0 +678,0 @@

@@ -17,6 +17,5 @@ /*!

const Extensions = require('./Extensions');
const constants = require('./Constants');
const WebSocket = require('./WebSocket');
const GUID = '258EAFA5-E914-47DA-95CA-C5AB0DC85B11';
/**

@@ -219,3 +218,3 @@ * Class representing a WebSocket server.

const key = crypto.createHash('sha1')
.update(req.headers['sec-websocket-key'] + GUID, 'binary')
.update(req.headers['sec-websocket-key'] + constants.GUID, 'binary')
.digest('base64');

@@ -222,0 +221,0 @@

@@ -5,3 +5,3 @@ {

"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
"version": "2.1.0",
"version": "2.2.0",
"license": "MIT",

@@ -34,3 +34,3 @@ "main": "index.js",

"bufferutil": "~2.0.0",
"eslint": "~3.15.0",
"eslint": "~3.16.0",
"eslint-config-semistandard": "~7.0.0",

@@ -37,0 +37,0 @@ "eslint-config-standard": "~6.2.1",

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc