WebSockets: Reject handshake for wrong protocol used by client (nodejs) - node.js

I have a very basic websocket server / client in JS:
Server:
const WebSocket = require('ws');
const wss = new WebSocket.Server({port: 3300});
wss.on('connection', function connection(ws, req) {
});
Client:
var ws = new WebSocket('wss://example.com/socket', ['appProtocol']);
I want to reject the connection with the server when the Client is not using the
'appProtocol' protocol.
I feel like this should be pretty easy, still I cant find anything and cant get it done by myself. Any help is highly appreciated, thank you!

Nvm, I found a solution that works for me:
Server:
const WebSocket = require('ws');
const http = require('http');
const server = http.createServer();
const wss = new WebSocket.Server({noServer: true});
wss.on('connection', (ws, req) => {
console.log('Opened Connection with URL ' + req.url.substr(1));
ws.on('close', () => {
console.log('Closed Connection with URL ' + req.url.substr(1));
});
});
server.on('upgrade', (request, socket, head) => {
if (request.headers['sec-websocket-protocol'] === 'appProtocol') {
wss.handleUpgrade(request, socket, head, (ws) => {
wss.emit('connection', ws, request);
})
} else {
socket.destroy();
}
});
server.listen(3300);

Related

Express and Websocket to run on the same port on the same file

I'm running two apps that sends real-time messages to each other using websocket and also generate a random link using express.js, now i hosted the server with both react apps to my vps host and want to make the websocket connection secure (wss://) but i realize i'll have to get the express server on the same port too, so the ssl/tsl works for both - so how do i do that?
Here is my full code, all on the same file:
const webSocketServerPort = 8000;
const webSocketServer = require('websocket').server;
const http = require('http');
const server = http.createServer(); server.listen(webSocketServerPort); console.log('Listening on port 8000');
const wsServer = new webSocketServer({ httpServer: server })
//GEERTOOOO
const express = require('express'); const cors = require('cors'); const fs = require('fs'); const app = express();
app.use(cors({ origin: '*' }));
app.get('/', (req, res) => { // Generate a random 6-character string const linkId = Math.random().toString(36).substr(2, 6);
// Save the link in the lex.json file fs.readFile('lex.json', (err, data) => { if (err) { console.error(err); res.status(500).send('Error generating link'); return; }
const links = JSON.parse(data);
links[linkId] = {
destination: 'http://localhost:4000/',
expires: Date.now() + 1000 * 60 * 5 // expires in 5 minutes
};
fs.writeFile('lex.json', JSON.stringify(links), (err) => {
if (err) {
console.error(err);
res.status(500).send('Error generating link');
return;
}
// Send the link back to the client
res.send(`http://localhost:3000/${linkId}`);
});
}); });
app.get('/:linkId', (req, res) => {
fs.readFile('lex.json', (err, data) => {
if (err) { console.error(err); res.status(500).send('Error retrieving link');
return;
}
const links = JSON.parse(data);
const link = links[req.params.linkId];
if (!link) {
res.status(404).send('Link not found');
return;
}
// Check if the link has expired
if (link.expires < Date.now()) {
res.status(410).send('Link has expired');
return;
}
// Redirect to the destination
res.redirect(link.destination);
}); });
app.listen(3000, () => { console.log('Server listening on port 3000'); });
//GEERTOOOO
const clients = {};
const getUniqueID = () => { const s4 = () => Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return s4() + s4() + '-' + s4(); }
wsServer.on('request', (request) => { var userID = getUniqueID();
const connection = request.accept(null, request.origin); clients[userID] = connection;
connection.on('message', (message) => {
if (message.type === 'utf8') {
for(var key in clients) {
if (clients[key] !== clients[userID]) {
clients[key].sendUTF(message.utf8Data);
console.log(`Sent Message to: ${clients[key]}`);
}
}
}
}) })
Note: the express server is on port 3000 and the websocket server runs on port 8000.
I,ve tried just changing the port to same thing but i get an error when trying to use the websocket server for messages.
THE PURPOSE OF ALL THIS IS JUST TO MAKE THE WEBSOCKET CONNECTION AND EXPRESS CONNECCTION SECURE SO MY APPS (with letsencrypt ssl) can connect to the servers
It is not possible to create two separate server instances, both listening on the same port. But, specifically for a webSocket, you can share one server instance between Express and the webSocket server code. This is possible because a webSocket connection always starts with an http request (thus it can be listened for using your Express http server. And, because these http requests that initiate a webSocket all contain identifying headers they can be separated out from the regular http requests for Express by looking at the headers. The webSocket server code already knows how to do that for you.
To do that, first capture the Express server instance:
const server = app.listen(3000, () => { console.log('Server listening on port 3000'); });
Then, use that server instance when you create your webSocket server.
const wsServer = new webSocketServer({ httpServer: server });
Then, remove this code because you don't want to create yet another http server instance for the webSocket server:
const server = http.createServer();
server.listen(webSocketServerPort);
console.log('Listening on port 8000');

Why i have no response from my websocket?

I need your help because i have a node js server with websocket like this :
const app = require("../app"); // Basic app file
const server = require("http").createServer(app);
const WebSocket = require("ws");
const wss = new WebSocket.Server({ server });
wss.on("connection", (ws) => {
ws.send('message')
ws.on("close", () => {
console.log('connection closed'));
});
ws.on("message", (data) => {
console.log(data.toString());
});
});
server.listen();
And client side :
var ws = new WebSocket('wss://topicsall.fr',)
ws.onopen = function () {
console.log('open');
};
ws.onmessage = function () {
console.log('message');
};
I have no error message but the connection remains on hold and is interrupted after the elapsed time.
In dev mode I have no problem, it's only in production.
I've been stuck for 4 days, I really need your help! Thanks

No response from websocket from my subdomain

I have a problem only in production mode, let me explain:
I created a subdomain on which I placed a websocket as follows:
const app = require("../app"); // app.js it's OK !
const server = require("http").createServer(app);
const WebSocket = require("ws");
const wss = new WebSocket.Server({ server });
wss.on("connection", (ws) => {
// Code is reduced for demo
console.log('New connection') // Is triggered by the client from my primary domain
ws.on("close", () => {
console.log(`Connection closed`);
});
});
server.listen()
I specify that the subdomain and the main domain are in https.
This is the client code on my main domain:
socket = new WebSocket('wss://my-subdomain.com/');
socket.addEventListener("open", () => {
console.log('Connection open'); // But it never fires
});
Does anyone know where the problem comes from? Thanks for your help !

client undefined in websocket server

when i print client in console logconsole.log(client ${client}); it shows undefined.
I think i should do something in my client code but don't know what.
Server code -
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 8080 });
wss.on('connection', function connection(ws, request, client) {
console.log(`client ${client}`);
ws.on('message', function message(msg) {
console.log(`Received message ${msg}`);
});
});
client code-
const Websocket = require('ws');
const ws = new Websocket('ws://localhost:8081');
function noop() {}
ws.on("message", function(event){
console.log(event);
});
const ping = function() {
ws.ping(noop);
}
setInterval(ping, 30000);
ws doesn't support client out of the box.
See: https://www.npmjs.com/package/ws#client-authentication
the gist of it is that you need to use an HTTP server to listen to any connections (not using ws to listen) and "manual" emit the connection event with additional data (like client).

How can i get the headers request from client side for sockets using NodeJS

I am quite new to this thing. I just wanted to know if it is possible to get the web sockets client side request header.
I'm using in the server side node.js:
Using ExpresJS I can get headers like:
router.post('/', function (req, res, next) {
console.log(req.headers);
});
Using Web Socket, its possible?
var WebSocket = require('ws');
var ws = new WebSocket('ws://www.host.com/path');
ws.on('open', function open() {
// how to get the headers
ws.send('something');
});
It is possible?
Thanks
WebSockets don't have headers, but their upgrade requests do.
var WebSocketServer = require('ws').Server
, wss = new WebSocketServer({ port: 8080 });
wss.on('connection', function connection(ws) {
console.log(ws.upgradeReq.headers);
ws.on('message', function incoming(message) {
console.log('received: %s', message);
});
ws.send('something');
});
Note you can't set headers as part of the ws request.

Resources