wormhole/index.js

85 lines
3.3 KiB
JavaScript
Raw Normal View History

const EventEmitter = require('events');
2021-01-26 12:04:53 +02:00
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();
2021-01-26 12:04:53 +02:00
this._urls = urls;
this._httpServer = httpServer;
this._sockets = [];
2021-01-26 12:04:53 +02:00
this._httpServer.on('request', ((req, res) => {
2021-01-26 12:04:53 +02:00
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 });
2021-01-26 12:04:53 +02:00
const failConnection = (status=400) => {
socket._setConnectionState(constants.states.CLOSING);
2021-01-26 12:04:53 +02:00
res.writeHead(status);
res.end();
socket._setConnectionState(constants.states.CLOSED);
2021-01-26 12:04:53 +02:00
console.trace();
};
// TODO: check origin header
2021-01-26 12:04:53 +02:00
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 });
2021-01-26 12:04:53 +02:00
}
return failConnection();
}
}));
2021-01-26 12:04:53 +02:00
}
}
module.exports = Wormhole;