wormhole/index.js

85 lines
No EOL
3.3 KiB
JavaScript

const EventEmitter = require('events');
const { createLog } = require('./lib/logger');
const handshake = require('./lib/handshake');
const constants = require('./lib/constants');
const Socket = require('./lib/Socket');
const handshakeLog = createLog([ 'Wormhole', 'Handshake' ]);
class Wormhole extends EventEmitter {
constructor({ urls=[ '/bruh' ], httpServer }) {
super();
this._urls = urls;
this._httpServer = httpServer;
this._sockets = [];
this._httpServer.on('request', ((req, res) => {
if (req.method === 'GET' && req.url && this._urls.includes(req.url)) {
handshakeLog(`Got connection request to ${req.url}`);
let socket = new Socket({ socket: res.socket, initalState: constants.states.CONNECTING });
const failConnection = (status=400) => {
socket._setConnectionState(constants.states.CLOSING);
res.writeHead(status);
res.end();
socket._setConnectionState(constants.states.CLOSED);
console.trace();
};
// TODO: check origin header
const websocketKey = req.headers['sec-websocket-key'];
const upgradeHeader = req.headers['upgrade'];
const websocketVersion = req.headers['sec-websocket-version'];
if (upgradeHeader !== constants.upgradeHeaderRequirement) return failConnection();
if (websocketVersion !== constants.websocketVersionRequirement) return failConnection();
const websocketAccept = handshake.generateWebsocketAcceptValue(websocketKey);
if (websocketAccept) {
const accept = () => {
try {
socket._setAccepted(true);
} catch(e) {
throw new Error('Tried to set socket fate (wether it is accept or not) more than once. Check if there are multiple listeners for the "connect" event or if you are somehow calling accept or reject multiple times.');
}
res.writeHead(101, {
'Upgrade': 'websocket',
'Connection': 'Upgrade',
'Sec-WebSocket-Accept': websocketAccept
});
res.end();
socket._setConnectionState(constants.states.OPEN);
return true;
};
const reject = (status=403) => {
try {
socket._setAccepted(false);
} catch(e) {
throw new Error('Tried to set socket fate (wether it is accept or not) more than once. Check if there are multiple listeners for the "connect" event or if you are somehow calling accept or reject multiple times.');
}
failConnection(status);
};
return this.emit('connect', { socket, accept, reject });
}
return failConnection();
}
}));
}
}
module.exports = Wormhole;