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

ws

Package Overview
Dependencies
Maintainers
3
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 1.0.1 to 1.1.0

SECURITY.md

2

lib/BufferUtil.fallback.js

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

module.exports.BufferUtil = {
exports.BufferUtil = {
merge: function(mergedBuffer, buffers) {

@@ -10,0 +10,0 @@ var offset = 0;

@@ -14,3 +14,3 @@

function PerMessageDeflate(options, isServer) {
function PerMessageDeflate(options, isServer,maxPayload) {
if (this instanceof PerMessageDeflate === false) {

@@ -25,2 +25,3 @@ throw new TypeError("Classes can't be function-called");

this.params = null;
this._maxPayload = maxPayload || 0;
}

@@ -241,2 +242,3 @@

var buffers = [];
var cumulativeBufferLength=0;

@@ -259,3 +261,13 @@ this._inflate.on('error', onError).on('data', onData);

function onData(data) {
buffers.push(data);
if(self._maxPayload!==undefined && self._maxPayload!==null && self._maxPayload>0){
cumulativeBufferLength+=data.length;
if(cumulativeBufferLength>self._maxPayload){
buffers=[];
cleanup();
var err={type:1009};
callback(err);
return;
}
}
buffers.push(data);
}

@@ -262,0 +274,0 @@

@@ -50,2 +50,3 @@ /*!

Receiver.prototype.add = function(data) {
if (this.dead) return;
var self = this;

@@ -157,4 +158,13 @@ function doAdd() {

Receiver.prototype.error = function (reason, terminate) {
if (this.dead) return;
this.reset();
this.onerror(reason, terminate);
if(typeof reason == 'string'){
this.onerror(new Error(reason), terminate);
}
else if(reason.constructor == Error){
this.onerror(reason, terminate);
}
else{
this.onerror(new Error("An error occured"),terminate);
}
return this;

@@ -161,0 +171,0 @@ };

@@ -18,7 +18,12 @@ /*!

function Receiver (extensions) {
function Receiver (extensions,maxPayload) {
if (this instanceof Receiver === false) {
throw new TypeError("Classes can't be function-called");
}
if(typeof extensions==='number'){
maxPayload=extensions;
extensions={};
}
// memory pool for fragmented messages

@@ -43,4 +48,5 @@ var fragmentedPoolPrevUsed = -1;

});
this.extensions = extensions || {};
this.maxPayload = maxPayload || 0;
this.currentPayloadLength = 0;
this.state = {

@@ -59,2 +65,3 @@ activeFragmentedOperation: null,

this.currentMessage = [];
this.currentMessageLength = 0;
this.messageHandlers = [];

@@ -82,2 +89,3 @@ this.expectHeader(2, this.processPacket);

Receiver.prototype.add = function(data) {
if (this.dead) return;
var dataLength = data.length;

@@ -251,2 +259,3 @@ if (dataLength == 0) return;

Receiver.prototype.endPacket = function() {
if (this.dead) return;
if (!this.state.fragmentedOperation) this.unfragmentedBufferPool.reset(true);

@@ -261,2 +270,3 @@ else if (this.state.lastFragment) this.fragmentedBufferPool.reset(true);

}
this.currentPayloadLength = 0;
this.state.lastFragment = false;

@@ -290,3 +300,5 @@ this.state.opcode = this.state.activeFragmentedOperation != null ? this.state.activeFragmentedOperation : 0;

this.currentMessage = [];
this.currentMessageLength = 0;
this.messageHandlers = [];
this.currentPayloadLength = 0;
};

@@ -307,16 +319,2 @@

/**
* Concatenates a list of buffers.
*
* @api private
*/
Receiver.prototype.concatBuffers = function(buffers) {
var length = 0;
for (var i = 0, l = buffers.length; i < l; ++i) length += buffers[i].length;
var mergedBuffer = new Buffer(length);
bufferUtil.merge(mergedBuffer, buffers);
return mergedBuffer;
};
/**
* Handles an error

@@ -328,4 +326,13 @@ *

Receiver.prototype.error = function (reason, protocolErrorCode) {
if (this.dead) return;
this.reset();
this.onerror(reason, protocolErrorCode);
if(typeof reason == 'string'){
this.onerror(new Error(reason), protocolErrorCode);
}
else if(reason.constructor == Error){
this.onerror(reason, protocolErrorCode);
}
else{
this.onerror(new Error("An error occured"),protocolErrorCode);
}
return this;

@@ -378,2 +385,23 @@ };

/**
* Checks payload size, disconnects socket when it exceeds maxPayload
*
* @api private
*/
Receiver.prototype.maxPayloadExceeded = function(length) {
if (this.maxPayload=== undefined || this.maxPayload === null || this.maxPayload < 1) {
return false;
}
var fullLength = this.currentPayloadLength + length;
if (fullLength < this.maxPayload) {
this.currentPayloadLength = fullLength;
return false;
}
this.error('payload cannot exceed ' + this.maxPayload + ' bytes', 1009);
this.messageBuffer=[];
this.cleanup();
return true;
};
/**
* Buffer utilities

@@ -438,2 +466,6 @@ */

if (firstLength < 126) {
if (self.maxPayloadExceeded(firstLength)){
self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
return;
}
opcodes['1'].getData.call(self, firstLength);

@@ -443,3 +475,8 @@ }

self.expectHeader(2, function(data) {
opcodes['1'].getData.call(self, readUInt16BE.call(data, 0));
var length = readUInt16BE.call(data, 0);
if (self.maxPayloadExceeded(length)){
self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
return;
}
opcodes['1'].getData.call(self, length);
});

@@ -453,2 +490,7 @@ }

}
var length = readUInt32BE.call(data, 4);
if (self.maxPayloadExceeded(length)){
self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
return;
}
opcodes['1'].getData.call(self, readUInt32BE.call(data, 4));

@@ -480,8 +522,25 @@ });

self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
if (err) return self.error(err.message, 1007);
if (buffer != null) self.currentMessage.push(buffer);
if (err) {
if(err.type===1009){
return self.error('Maximumpayload exceeded in compressed text message. Aborting...', 1009);
}
return self.error(err.message, 1007);
}
if (buffer != null) {
if( self.maxPayload==0 || (self.maxPayload > 0 && (self.currentMessageLength + buffer.length) < self.maxPayload) ){
self.currentMessage.push(buffer);
}
else{
self.currentMessage=null;
self.currentMessage = [];
self.currentMessageLength = 0;
self.error(new Error('Maximum payload exceeded. maxPayload: '+self.maxPayload), 1009);
return;
}
self.currentMessageLength += buffer.length;
}
if (state.lastFragment) {
var messageBuffer = self.concatBuffers(self.currentMessage);
var messageBuffer = Buffer.concat(self.currentMessage);
self.currentMessage = [];
self.currentMessageLength = 0;
if (!Validation.isValidUTF8(messageBuffer)) {

@@ -507,2 +566,6 @@ self.error('invalid utf8 sequence', 1007);

if (firstLength < 126) {
if (self.maxPayloadExceeded(firstLength)){
self.error('Max payload exceeded in compressed text message. Aborting...', 1009);
return;
}
opcodes['2'].getData.call(self, firstLength);

@@ -512,3 +575,8 @@ }

self.expectHeader(2, function(data) {
opcodes['2'].getData.call(self, readUInt16BE.call(data, 0));
var length = readUInt16BE.call(data, 0);
if (self.maxPayloadExceeded(length)){
self.error('Max payload exceeded in compressed text message. Aborting...', 1009);
return;
}
opcodes['2'].getData.call(self, length);
});

@@ -522,3 +590,8 @@ }

}
opcodes['2'].getData.call(self, readUInt32BE.call(data, 4, true));
var length = readUInt32BE.call(data, 4, true);
if (self.maxPayloadExceeded(length)){
self.error('Max payload exceeded in compressed text message. Aborting...', 1009);
return;
}
opcodes['2'].getData.call(self, length);
});

@@ -549,7 +622,25 @@ }

self.applyExtensions(packet, state.lastFragment, state.compressed, function(err, buffer) {
if (err) return self.error(err.message, 1007);
if (buffer != null) self.currentMessage.push(buffer);
if (err) {
if(err.type===1009){
return self.error('Max payload exceeded in compressed binary message. Aborting...', 1009);
}
return self.error(err.message, 1007);
}
if (buffer != null) {
if( self.maxPayload==0 || (self.maxPayload > 0 && (self.currentMessageLength + buffer.length) < self.maxPayload) ){
self.currentMessage.push(buffer);
}
else{
self.currentMessage=null;
self.currentMessage = [];
self.currentMessageLength = 0;
self.error(new Error('Maximum payload exceeded'), 1009);
return;
}
self.currentMessageLength += buffer.length;
}
if (state.lastFragment) {
var messageBuffer = self.concatBuffers(self.currentMessage);
var messageBuffer = Buffer.concat(self.currentMessage);
self.currentMessage = [];
self.currentMessageLength = 0;
self.onbinary(messageBuffer, {masked: state.masked, buffer: messageBuffer});

@@ -556,0 +647,0 @@ }

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

outputBuffer[1] = secondByte | 0x80;
var mask = this._randomMask || (this._randomMask = getRandomMask());
var mask = getRandomMask();
outputBuffer[dataOffset - 4] = mask[0];

@@ -203,0 +203,0 @@ outputBuffer[dataOffset - 3] = mask[1];

@@ -6,4 +6,4 @@ /*!

*/
module.exports.Validation = {
exports.Validation = {
isValidUTF8: function(buffer) {

@@ -13,2 +13,1 @@ return true;

};

@@ -74,2 +74,3 @@ 'use strict';

this.extensions = {};
this._binaryType = 'nodebuffer';

@@ -376,2 +377,23 @@ if (Array.isArray(address)) {

/**
* Expose binaryType
*
* This deviates from the W3C interface since ws doesn't support the required
* default "blob" type (instead we define a custom "nodebuffer" type).
*
* @see http://dev.w3.org/html5/websockets/#the-websocket-interface
* @api public
*/
Object.defineProperty(WebSocket.prototype, 'binaryType', {
get: function get() {
return this._binaryType;
},
set: function set(type) {
if (type === 'arraybuffer' || type === 'nodebuffer')
this._binaryType = type;
else
throw new SyntaxError('unsupported binaryType: must be either "nodebuffer" or "arraybuffer"');
}
});
/**
* Emulates the W3C Browser based WebSocket interface using function members.

@@ -420,2 +442,4 @@ *

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

@@ -529,3 +553,4 @@ }

protocol: null,
extensions: {}
extensions: {},
maxPayload: 0
}).merge(options);

@@ -541,3 +566,3 @@

this._isServer = true;
this.maxPayload = options.value.maxPayload;
// establish connection

@@ -778,3 +803,3 @@ if (options.value.protocolVersion === 'hixie-76') {

this._receiver = new ReceiverClass(this.extensions);
this._receiver = new ReceiverClass(this.extensions,this.maxPayload);
this._socket = socket;

@@ -857,3 +882,3 @@

self.close(typeof errorCode !== 'undefined' ? errorCode : 1002, '');
self.emit('error', reason, errorCode);
self.emit('error', (reason instanceof Error) ? reason : (new Error(reason)));
};

@@ -921,3 +946,2 @@

var emitClose = this.readyState !== WebSocket.CONNECTING;
this.readyState = WebSocket.CLOSED;

@@ -928,11 +952,9 @@

if (emitClose) {
// If the connection was closed abnormally (with an error), or if
// the close control frame was not received then the close code
// must default to 1006.
if (error || !this._closeReceived) {
this._closeCode = 1006;
}
this.emit('close', this._closeCode || 1000, this._closeMessage || '');
// If the connection was closed abnormally (with an error), or if
// the close control frame was not received then the close code
// must default to 1006.
if (error || !this._closeReceived) {
this._closeCode = 1006;
}
this.emit('close', this._closeCode || 1000, this._closeMessage || '');

@@ -939,0 +961,0 @@ if (this._socket) {

@@ -39,3 +39,4 @@ /*!

clientTracking: true,
perMessageDeflate: true
perMessageDeflate: true,
maxPayload: null
}).merge(options);

@@ -76,9 +77,11 @@

}
if (this._server) this._server.once('listening', function() { self.emit('listening'); });
if (this._server) {
this._onceServerListening = function() { self.emit('listening'); };
this._server.once('listening', this._onceServerListening);
}
if (typeof this._server != 'undefined') {
this._server.on('error', function(error) {
self.emit('error', error)
});
this._server.on('upgrade', function(req, socket, upgradeHead) {
this._onServerError = function(error) { self.emit('error', error) };
this._server.on('error', this._onServerError);
this._onServerUpgrade = function(req, socket, upgradeHead) {
//copy upgradeHead to avoid retention of large slab buffers used in node core

@@ -92,3 +95,4 @@ var head = new Buffer(upgradeHead.length);

});
});
};
this._server.on('upgrade', this._onServerUpgrade);
}

@@ -140,2 +144,7 @@

finally {
if (this._server) {
this._server.removeListener('listening', this._onceServerListening);
this._server.removeListener('error', this._onServerError);
this._server.removeListener('upgrade', this._onServerUpgrade);
}
delete this._server;

@@ -263,3 +272,4 @@ }

protocol: protocol,
extensions: extensions
extensions: extensions,
maxPayload: self.options.maxPayload
});

@@ -367,4 +377,38 @@

// build the response header and return a Buffer
var buildResponseHeader = function() {
var headers = [
'HTTP/1.1 101 Switching Protocols'
, 'Upgrade: WebSocket'
, 'Connection: Upgrade'
, 'Sec-WebSocket-Location: ' + location
];
if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol);
if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin);
return new Buffer(headers.concat('', '').join('\r\n'));
};
// send handshake response before receiving the nonce
var handshakeResponse = function() {
socket.setTimeout(0);
socket.setNoDelay(true);
var headerBuffer = buildResponseHeader();
try {
socket.write(headerBuffer, 'binary', function(err) {
// remove listener if there was an error
if (err) socket.removeListener('data', handler);
return;
});
} catch (e) {
try { socket.destroy(); } catch (e) {}
return;
};
};
// handshake completion code to run once nonce has been successfully retrieved
var completeHandshake = function(nonce, rest) {
var completeHandshake = function(nonce, rest, headerBuffer) {
// calculate key

@@ -391,16 +435,6 @@ var k1 = req.headers['sec-websocket-key1']

var headers = [
'HTTP/1.1 101 Switching Protocols'
, 'Upgrade: WebSocket'
, 'Connection: Upgrade'
, 'Sec-WebSocket-Location: ' + location
];
if (typeof protocol != 'undefined') headers.push('Sec-WebSocket-Protocol: ' + protocol);
if (typeof origin != 'undefined') headers.push('Sec-WebSocket-Origin: ' + origin);
socket.setTimeout(0);
socket.setNoDelay(true);
try {
// merge header and hash buffer
var headerBuffer = new Buffer(headers.concat('', '').join('\r\n'));
var hashBuffer = new Buffer(md5.digest('binary'), 'binary');

@@ -444,7 +478,6 @@ var handshakeBuffer = new Buffer(headerBuffer.length + hashBuffer.length);

var rest = upgradeHead.length > nonceLength ? upgradeHead.slice(nonceLength) : null;
completeHandshake.call(self, nonce, rest);
completeHandshake.call(self, nonce, rest, buildResponseHeader());
}
else {
// nonce not present in upgradeHead, so we must wait for enough data
// data to arrive before continuing
// nonce not present in upgradeHead
var nonce = new Buffer(nonceLength);

@@ -462,6 +495,13 @@ upgradeHead.copy(nonce, 0);

if (toRead < data.length) rest = data.slice(toRead);
completeHandshake.call(self, nonce, rest);
// complete the handshake but send empty buffer for headers since they have already been sent
completeHandshake.call(self, nonce, rest, new Buffer(0));
}
}
// handle additional data as we receive it
socket.on('data', handler);
// send header response before we have the nonce to fix haproxy buffering
handshakeResponse();
}

@@ -501,4 +541,5 @@ }

var options = this.options.perMessageDeflate;
var maxPayload = this.options.maxPayload;
if (options && offer[PerMessageDeflate.extensionName]) {
var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true);
var perMessageDeflate = new PerMessageDeflate(options !== true ? options : {}, true, maxPayload);
perMessageDeflate.accept(offer[PerMessageDeflate.extensionName]);

@@ -505,0 +546,0 @@ extensions[PerMessageDeflate.extensionName] = perMessageDeflate;

@@ -5,4 +5,5 @@ {

"description": "simple to use, blazing fast and thoroughly tested websocket client, server and console for node.js, up-to-date against RFC-6455",
"version": "1.0.1",
"version": "1.1.0",
"license": "MIT",
"main": "index.js",
"keywords": [

@@ -33,2 +34,3 @@ "Hixie",

"expect.js": "0.3.x",
"istanbul": "^0.4.1",
"mocha": "2.3.x",

@@ -35,0 +37,0 @@ "should": "8.0.x",

@@ -34,3 +34,3 @@ # ws: a node.js websocket library

allows for faster processing of masked WebSocket frames and general buffer
operations.
operations.
- `npm install --save utf-8-validate`: The specification requires validation of

@@ -40,4 +40,4 @@ invalid UTF-8 chars, some of these validations could not be done in JavaScript

validating the input that you receive for security purposes leading to double
validation. But if you want to be 100% spec conform and fast validation of UTF-8
then this module is a must.
validation. But if you want to be 100% spec-conforming and have fast
validation of UTF-8 then this module is a must.

@@ -115,3 +115,3 @@ ### Sending and receiving text data

// or ws.upgradeReq.headers.cookie (see http://stackoverflow.com/a/16395220/151312)
ws.on('message', function incoming(message) {

@@ -167,3 +167,3 @@ console.log('received: %s', message);

var ws = new WebSocket('ws://echo.websocket.org/', {
protocolVersion: 8,
protocolVersion: 8,
origin: 'http://websocket.org'

@@ -190,9 +190,2 @@ });

### Browserify users
When including ws via a browserify bundle, ws returns global.WebSocket which has slightly different API.
You should use the standard WebSockets API instead.
https://developer.mozilla.org/en-US/docs/WebSockets/Writing_WebSocket_client_applications#Availability_of_WebSockets
### Other examples

@@ -199,0 +192,0 @@

Sorry, the diff of this file is not supported yet

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