basic handshake handling
This commit is contained in:
parent
ac6cdf7bc9
commit
641a978cbe
7 changed files with 139 additions and 0 deletions
28
example/example.html
Normal file
28
example/example.html
Normal file
|
@ -0,0 +1,28 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Wormhole test</title>
|
||||
|
||||
<script>
|
||||
// Create WebSocket connection.
|
||||
const socket = new WebSocket('ws://localhost:8080/hello');
|
||||
|
||||
// Connection opened
|
||||
socket.addEventListener('open', function (event) {
|
||||
socket.send('Hello Server!');
|
||||
});
|
||||
|
||||
socket.addEventListener('error', console.error)
|
||||
|
||||
// Listen for messages
|
||||
socket.addEventListener('message', function (event) {
|
||||
console.log('Message from server ', event.data);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
</body>
|
||||
</html>
|
3
example/example.js
Normal file
3
example/example.js
Normal file
|
@ -0,0 +1,3 @@
|
|||
const Wormhole = require('../index');
|
||||
|
||||
const wormhole = new Wormhole({ urls: [ '/hello' ] });
|
58
index.js
58
index.js
|
@ -0,0 +1,58 @@
|
|||
const http = require('http');
|
||||
|
||||
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 {
|
||||
constructor({ urls=[ '/bruh' ], port=8080 }) {
|
||||
this._urls = urls;
|
||||
this._port = port;
|
||||
|
||||
this._httpServer = http.createServer((req, res) => {
|
||||
if (req.method === 'GET' && req.url && this._urls.includes(req.url)) {
|
||||
handshakeLog(`Got connection request to ${req.url} on port ${this._port}`);
|
||||
|
||||
const failConnection = (status=400) => {
|
||||
res.writeHead(status);
|
||||
res.end();
|
||||
|
||||
console.trace();
|
||||
};
|
||||
|
||||
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);
|
||||
|
||||
handshakeLog(websocketKey, websocketAccept);
|
||||
|
||||
if (websocketAccept) {
|
||||
res.writeHead(101, {
|
||||
'Upgrade': 'websocket',
|
||||
'Connection': 'Upgrade',
|
||||
'Sec-WebSocket-Accept': websocketAccept
|
||||
});
|
||||
res.end();
|
||||
|
||||
const socket = new Socket({ socket: res.socket, initalState: 'CONNECTED' });
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return failConnection();
|
||||
}
|
||||
});
|
||||
|
||||
this._httpServer.listen(port);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Wormhole;
|
12
lib/Socket.js
Normal file
12
lib/Socket.js
Normal file
|
@ -0,0 +1,12 @@
|
|||
class Socket {
|
||||
constructor({ initialState='CONNECTING', socket }) {
|
||||
this._state = initialState;
|
||||
this._socket = socket;
|
||||
|
||||
this._socket.on('data', (e) => {
|
||||
console.log(e.toString());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = Socket;
|
5
lib/constants.js
Normal file
5
lib/constants.js
Normal file
|
@ -0,0 +1,5 @@
|
|||
module.exports = {
|
||||
handshakeGUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
||||
upgradeHeaderRequirement: 'websocket',
|
||||
websocketVersionRequirement: '13'
|
||||
}
|
17
lib/handshake.js
Normal file
17
lib/handshake.js
Normal file
|
@ -0,0 +1,17 @@
|
|||
const crypto = require('crypto');
|
||||
|
||||
const { handshakeGUID } = require('./constants');
|
||||
|
||||
const generateWebsocketAcceptValue = (websocketKey) => {
|
||||
if (typeof websocketKey !== 'string' || typeof handshakeGUID !== 'string') {
|
||||
// TODO: maybe throw error?
|
||||
return;
|
||||
}
|
||||
|
||||
const concatenated = websocketKey + handshakeGUID;
|
||||
const sha1HashedInBase64 = crypto.createHash('sha1').update(concatenated, 'binary').digest('base64');
|
||||
|
||||
return sha1HashedInBase64;
|
||||
};
|
||||
|
||||
module.exports = { generateWebsocketAcceptValue };
|
16
lib/logger.js
Normal file
16
lib/logger.js
Normal file
|
@ -0,0 +1,16 @@
|
|||
const logDebug = true;
|
||||
|
||||
module.exports = {
|
||||
createLog: (components) => (...args) => {
|
||||
let compString = '';
|
||||
for (const i in components) {
|
||||
const component = components[i];
|
||||
if (i >= (components.length - 1)) {
|
||||
compString += `[${component}]`;
|
||||
} else {
|
||||
compString += `[${component}] `;
|
||||
}
|
||||
}
|
||||
logDebug && console.log(compString, ...args);
|
||||
}
|
||||
};
|
Loading…
Reference in a new issue