Started adding slash commands, doesn't work though

This commit is contained in:
ION606
2022-09-26 15:41:20 +00:00
parent b6495eb886
commit ec4c1200d5
2214 changed files with 159174 additions and 42761 deletions
Generated Vendored
+9 -3
View File
@@ -68,6 +68,13 @@ necessarily need to have a C++ compiler installed on your machine.
- `npm install --save-optional utf-8-validate`: Allows to efficiently check if a
message contains valid UTF-8.
To not even try to require and use these modules, use the
[`WS_NO_BUFFER_UTIL`](./doc/ws.md#ws_no_buffer_util) and
[`WS_NO_UTF_8_VALIDATE`](./doc/ws.md#ws_no_utf_8_validate) environment
variables. These might be useful to enhance security in systems where a user can
put a package in the package search path of an application of another user, due
to how the Node.js resolver algorithm works.
## API docs
See [`/doc/ws.md`](./doc/ws.md) for Node.js-like documentation of ws classes and
@@ -252,8 +259,8 @@ server.listen(8080);
### Client authentication
```js
import WebSocket from 'ws';
import { createServer } from 'http';
import { WebSocketServer } from 'ws';
const server = createServer();
const wss = new WebSocketServer({ noServer: true });
@@ -485,5 +492,4 @@ We're using the GitHub [releases][changelog] for changelog entries.
[server-report]: http://websockets.github.io/ws/autobahn/servers/
[session-parse-example]: ./examples/express-session-parse
[socks-proxy-agent]: https://github.com/TooTallNate/node-socks-proxy-agent
[ws-server-options]:
https://github.com/websockets/ws/blob/master/doc/ws.md#new-websocketserveroptions-callback
[ws-server-options]: ./doc/ws.md#new-websocketserveroptions-callback
+20 -19
View File
@@ -99,28 +99,29 @@ function toBuffer(data) {
return buf;
}
try {
const bufferUtil = require('bufferutil');
module.exports = {
concat,
mask: _mask,
toArrayBuffer,
toBuffer,
unmask: _unmask
};
module.exports = {
concat,
mask(source, mask, output, offset, length) {
/* istanbul ignore else */
if (!process.env.WS_NO_BUFFER_UTIL) {
try {
const bufferUtil = require('bufferutil');
module.exports.mask = function (source, mask, output, offset, length) {
if (length < 48) _mask(source, mask, output, offset, length);
else bufferUtil.mask(source, mask, output, offset, length);
},
toArrayBuffer,
toBuffer,
unmask(buffer, mask) {
};
module.exports.unmask = function (buffer, mask) {
if (buffer.length < 32) _unmask(buffer, mask);
else bufferUtil.unmask(buffer, mask);
}
};
} catch (e) /* istanbul ignore next */ {
module.exports = {
concat,
mask: _mask,
toArrayBuffer,
toBuffer,
unmask: _unmask
};
};
} catch (e) {
// Continue regardless of the error.
}
}
+15 -14
View File
@@ -105,20 +105,21 @@ function _isValidUTF8(buf) {
return true;
}
try {
const isValidUTF8 = require('utf-8-validate');
module.exports = {
isValidStatusCode,
isValidUTF8: _isValidUTF8,
tokenChars
};
module.exports = {
isValidStatusCode,
isValidUTF8(buf) {
/* istanbul ignore else */
if (!process.env.WS_NO_UTF_8_VALIDATE) {
try {
const isValidUTF8 = require('utf-8-validate');
module.exports.isValidUTF8 = function (buf) {
return buf.length < 150 ? _isValidUTF8(buf) : isValidUTF8(buf);
},
tokenChars
};
} catch (e) /* istanbul ignore next */ {
module.exports = {
isValidStatusCode,
isValidUTF8: _isValidUTF8,
tokenChars
};
};
} catch (e) {
// Continue regardless of the error.
}
}
+82 -35
View File
@@ -230,21 +230,36 @@ class WebSocketServer extends EventEmitter {
handleUpgrade(req, socket, head, cb) {
socket.on('error', socketOnError);
const key =
req.headers['sec-websocket-key'] !== undefined
? req.headers['sec-websocket-key']
: false;
const key = req.headers['sec-websocket-key'];
const version = +req.headers['sec-websocket-version'];
if (
req.method !== 'GET' ||
req.headers.upgrade.toLowerCase() !== 'websocket' ||
!key ||
!keyRegex.test(key) ||
(version !== 8 && version !== 13) ||
!this.shouldHandle(req)
) {
return abortHandshake(socket, 400);
if (req.method !== 'GET') {
const message = 'Invalid HTTP method';
abortHandshakeOrEmitwsClientError(this, req, socket, 405, message);
return;
}
if (req.headers.upgrade.toLowerCase() !== 'websocket') {
const message = 'Invalid Upgrade header';
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
return;
}
if (!key || !keyRegex.test(key)) {
const message = 'Missing or invalid Sec-WebSocket-Key header';
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
return;
}
if (version !== 8 && version !== 13) {
const message = 'Missing or invalid Sec-WebSocket-Version header';
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
return;
}
if (!this.shouldHandle(req)) {
abortHandshake(socket, 400);
return;
}
const secWebSocketProtocol = req.headers['sec-websocket-protocol'];
@@ -254,7 +269,9 @@ class WebSocketServer extends EventEmitter {
try {
protocols = subprotocol.parse(secWebSocketProtocol);
} catch (err) {
return abortHandshake(socket, 400);
const message = 'Invalid Sec-WebSocket-Protocol header';
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
return;
}
}
@@ -279,7 +296,10 @@ class WebSocketServer extends EventEmitter {
extensions[PerMessageDeflate.extensionName] = perMessageDeflate;
}
} catch (err) {
return abortHandshake(socket, 400);
const message =
'Invalid or unacceptable Sec-WebSocket-Extensions header';
abortHandshakeOrEmitwsClientError(this, req, socket, 400, message);
return;
}
}
@@ -446,7 +466,7 @@ function emitClose(server) {
}
/**
* Handle premature socket errors.
* Handle socket errors.
*
* @private
*/
@@ -464,25 +484,52 @@ function socketOnError() {
* @private
*/
function abortHandshake(socket, code, message, headers) {
if (socket.writable) {
message = message || http.STATUS_CODES[code];
headers = {
Connection: 'close',
'Content-Type': 'text/html',
'Content-Length': Buffer.byteLength(message),
...headers
};
//
// The socket is writable unless the user destroyed or ended it before calling
// `server.handleUpgrade()` or in the `verifyClient` function, which is a user
// error. Handling this does not make much sense as the worst that can happen
// is that some of the data written by the user might be discarded due to the
// call to `socket.end()` below, which triggers an `'error'` event that in
// turn causes the socket to be destroyed.
//
message = message || http.STATUS_CODES[code];
headers = {
Connection: 'close',
'Content-Type': 'text/html',
'Content-Length': Buffer.byteLength(message),
...headers
};
socket.write(
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
Object.keys(headers)
.map((h) => `${h}: ${headers[h]}`)
.join('\r\n') +
'\r\n\r\n' +
message
);
}
socket.once('finish', socket.destroy);
socket.removeListener('error', socketOnError);
socket.destroy();
socket.end(
`HTTP/1.1 ${code} ${http.STATUS_CODES[code]}\r\n` +
Object.keys(headers)
.map((h) => `${h}: ${headers[h]}`)
.join('\r\n') +
'\r\n\r\n' +
message
);
}
/**
* Emit a `'wsClientError'` event on a `WebSocketServer` if there is at least
* one listener for it, otherwise call `abortHandshake()`.
*
* @param {WebSocketServer} server The WebSocket server
* @param {http.IncomingMessage} req The request object
* @param {(net.Socket|tls.Socket)} socket The socket of the upgrade request
* @param {Number} code The HTTP response status code
* @param {String} message The HTTP response body
* @private
*/
function abortHandshakeOrEmitwsClientError(server, req, socket, code, message) {
if (server.listenerCount('wsClientError')) {
const err = new Error(message);
Error.captureStackTrace(err, abortHandshakeOrEmitwsClientError);
server.emit('wsClientError', err, socket, req);
} else {
abortHandshake(socket, code, message);
}
}
+75 -34
View File
@@ -30,10 +30,11 @@ const {
const { format, parse } = require('./extension');
const { toBuffer } = require('./buffer-util');
const closeTimeout = 30 * 1000;
const kAborted = Symbol('kAborted');
const protocolVersions = [8, 13];
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
const subprotocolRegex = /^[!#$%&'*+\-.0-9A-Z^_`|a-z~]+$/;
const protocolVersions = [8, 13];
const closeTimeout = 30 * 1000;
/**
* Class representing a WebSocket.
@@ -647,7 +648,7 @@ function initAsClient(websocket, address, protocols, options) {
hostname: undefined,
protocol: undefined,
timeout: undefined,
method: undefined,
method: 'GET',
host: undefined,
path: undefined,
port: undefined
@@ -676,20 +677,20 @@ function initAsClient(websocket, address, protocols, options) {
}
const isSecure = parsedUrl.protocol === 'wss:';
const isUnixSocket = parsedUrl.protocol === 'ws+unix:';
let invalidURLMessage;
const isIpcUrl = parsedUrl.protocol === 'ws+unix:';
let invalidUrlMessage;
if (parsedUrl.protocol !== 'ws:' && !isSecure && !isUnixSocket) {
invalidURLMessage =
if (parsedUrl.protocol !== 'ws:' && !isSecure && !isIpcUrl) {
invalidUrlMessage =
'The URL\'s protocol must be one of "ws:", "wss:", or "ws+unix:"';
} else if (isUnixSocket && !parsedUrl.pathname) {
invalidURLMessage = "The URL's pathname is empty";
} else if (isIpcUrl && !parsedUrl.pathname) {
invalidUrlMessage = "The URL's pathname is empty";
} else if (parsedUrl.hash) {
invalidURLMessage = 'The URL contains a fragment identifier';
invalidUrlMessage = 'The URL contains a fragment identifier';
}
if (invalidURLMessage) {
const err = new SyntaxError(invalidURLMessage);
if (invalidUrlMessage) {
const err = new SyntaxError(invalidUrlMessage);
if (websocket._redirects === 0) {
throw err;
@@ -701,7 +702,7 @@ function initAsClient(websocket, address, protocols, options) {
const defaultPort = isSecure ? 443 : 80;
const key = randomBytes(16).toString('base64');
const get = isSecure ? https.get : http.get;
const request = isSecure ? https.request : http.request;
const protocolSet = new Set();
let perMessageDeflate;
@@ -712,11 +713,11 @@ function initAsClient(websocket, address, protocols, options) {
? parsedUrl.hostname.slice(1, -1)
: parsedUrl.hostname;
opts.headers = {
...opts.headers,
'Sec-WebSocket-Version': opts.protocolVersion,
'Sec-WebSocket-Key': key,
Connection: 'Upgrade',
Upgrade: 'websocket',
...opts.headers
Upgrade: 'websocket'
};
opts.path = parsedUrl.pathname + parsedUrl.search;
opts.timeout = opts.handshakeTimeout;
@@ -759,16 +760,22 @@ function initAsClient(websocket, address, protocols, options) {
opts.auth = `${parsedUrl.username}:${parsedUrl.password}`;
}
if (isUnixSocket) {
if (isIpcUrl) {
const parts = opts.path.split(':');
opts.socketPath = parts[0];
opts.path = parts[1];
}
let req;
if (opts.followRedirects) {
if (websocket._redirects === 0) {
websocket._originalHost = parsedUrl.host;
websocket._originalIpc = isIpcUrl;
websocket._originalSecure = isSecure;
websocket._originalHostOrSocketPath = isIpcUrl
? opts.socketPath
: parsedUrl.host;
const headers = options && options.headers;
@@ -783,15 +790,27 @@ function initAsClient(websocket, address, protocols, options) {
options.headers[key.toLowerCase()] = value;
}
}
} else if (parsedUrl.host !== websocket._originalHost) {
//
// Match curl 7.77.0 behavior and drop the following headers. These
// headers are also dropped when following a redirect to a subdomain.
//
delete opts.headers.authorization;
delete opts.headers.cookie;
delete opts.headers.host;
opts.auth = undefined;
} else if (websocket.listenerCount('redirect') === 0) {
const isSameHost = isIpcUrl
? websocket._originalIpc
? opts.socketPath === websocket._originalHostOrSocketPath
: false
: websocket._originalIpc
? false
: parsedUrl.host === websocket._originalHostOrSocketPath;
if (!isSameHost || (websocket._originalSecure && !isSecure)) {
//
// Match curl 7.77.0 behavior and drop the following headers. These
// headers are also dropped when following a redirect to a subdomain.
//
delete opts.headers.authorization;
delete opts.headers.cookie;
if (!isSameHost) delete opts.headers.host;
opts.auth = undefined;
}
}
//
@@ -803,9 +822,24 @@ function initAsClient(websocket, address, protocols, options) {
options.headers.authorization =
'Basic ' + Buffer.from(opts.auth).toString('base64');
}
}
let req = (websocket._req = get(opts));
req = websocket._req = request(opts);
if (websocket._redirects) {
//
// Unlike what is done for the `'upgrade'` event, no early exit is
// triggered here if the user calls `websocket.close()` or
// `websocket.terminate()` from a listener of the `'redirect'` event. This
// is because the user can also call `request.destroy()` with an error
// before calling `websocket.close()` or `websocket.terminate()` and this
// would result in an error being emitted on the `request` object with no
// `'error'` event listeners attached.
//
websocket.emit('redirect', websocket.url, req);
}
} else {
req = websocket._req = request(opts);
}
if (opts.timeout) {
req.on('timeout', () => {
@@ -814,7 +848,7 @@ function initAsClient(websocket, address, protocols, options) {
}
req.on('error', (err) => {
if (req === null || req.aborted) return;
if (req === null || req[kAborted]) return;
req = websocket._req = null;
emitErrorAndClose(websocket, err);
@@ -861,13 +895,18 @@ function initAsClient(websocket, address, protocols, options) {
websocket.emit('upgrade', res);
//
// The user may have closed the connection from a listener of the `upgrade`
// event.
// The user may have closed the connection from a listener of the
// `'upgrade'` event.
//
if (websocket.readyState !== WebSocket.CONNECTING) return;
req = websocket._req = null;
if (res.headers.upgrade.toLowerCase() !== 'websocket') {
abortHandshake(websocket, socket, 'Invalid Upgrade header');
return;
}
const digest = createHash('sha1')
.update(key + GUID)
.digest('base64');
@@ -947,10 +986,12 @@ function initAsClient(websocket, address, protocols, options) {
skipUTF8Validation: opts.skipUTF8Validation
});
});
req.end();
}
/**
* Emit the `'error'` and `'close'` event.
* Emit the `'error'` and `'close'` events.
*
* @param {WebSocket} websocket The WebSocket instance
* @param {Error} The error to emit
@@ -1007,6 +1048,7 @@ function abortHandshake(websocket, stream, message) {
Error.captureStackTrace(err, abortHandshake);
if (stream.setHeader) {
stream[kAborted] = true;
stream.abort();
if (stream.socket && !stream.socket.destroyed) {
@@ -1018,8 +1060,7 @@ function abortHandshake(websocket, stream, message) {
stream.socket.destroy();
}
stream.once('abort', websocket.emitClose.bind(websocket));
websocket.emit('error', err);
process.nextTick(emitErrorAndClose, websocket, err);
} else {
stream.destroy(err);
stream.once('error', websocket.emit.bind(websocket, 'error'));
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "ws",
"version": "8.5.0",
"version": "8.9.0",
"description": "Simple to use, blazing fast and thoroughly tested websocket client and server for Node.js",
"keywords": [
"HyBi",