NodeJS - Establish a Connection WebSocket with protocol HTTPS - node.js

I have a problem with an HTTPS and a WebSocket connection (I use Node.JS as a server).
I have generated SSL certificates with OpenSSL and I imported them to the server with the following code:
const https = require('https');
var app = express();
...
const WebSocket = require('ws');
...
var serverHttps = https.createServer({
key: fs.readFileSync(path.join(pathCertificati, 'key.pem')),
cert: fs.readFileSync(path.join(pathCertificati, 'cert.pem'))
}, app).listen(3000, () => {
console.log('In ascolto sulla porta 3000 HTTPS.')
})
const wss = new WebSocket.Server({
server: serverHttps,
adress: '192.168.12.40',
port: 9000
});
With this code I should have a WebSocket handling an HTTPS connection, correct?
Client side, I have the following code:
socket = new WebSocket("wss://192.168.12.40:9000");
socket.onopen = function ()...
socket.onclose = function ()...
socket.onerror = function (error) {
console.log("Errore nella connessione!");
console.log(error);
}
When I load the page using the address: https://192.168.12.40:3000 and the above code is executed, the error message appears:
WebSocketScript.js:26 WebSocket connection to 'wss://192.168.12.40:9000/' failed: Error in connection establishment: net::ERR_SSL_PROTOCOL_ERROR
Do you have any ideas to establish the WebSocket Connection on an HTTPS page?
Thanks a lot.

I have found the solution to the problem. The solution is:
Server-side code:
var serverHttps = https.createServer({
key: fs.readFileSync(path.join(pathCertificati, 'key.pem')),
cert: fs.readFileSync(path.join(pathCertificati, 'cert.pem'))
}, app).listen(3000, () => {
// Messaggio di attivazione del server in ascolto sulla porta 3000
console.log('Listening ' + 3000 + ' HTTPS.');
})
serverHttps.on('upgrade', function upgrade(request, socket, head) {
const pathname = url.parse(request.url).pathname;
if (pathname === "/") {
wss.handleUpgrade(request, socket, head, function done(ws) {
wss.emit('connection', ws, request);
});
}
});
// Create WebSocket
const wss = new WebSocket.Server({ noServer: true });
wss.on('error', function () {...}
wss.on('connection', function (ws) {...}
Client side:
socket = new WebSocket("wss://192.168.12.40:3000);
This is the same address used on the server side and it fire the event "serverHttps.on('upgrade'"
Thanks a log...

Related

socket.io not working locally, but ws work fine

So I have been searching for a solution for over 4 hours. I'm currently at the end of my resources.
Some background:
I have been trying to implement a socket.io solution for a WebSocket server - I like the extra functionality from this stack. However, I ran a ws server before, and didn't have any issue connecting to it.
I tried connecting to the server by using Postman, and my url that I want to connect to is ws://localhost:3001 and this is the error I'm receiving:
Error: socket hang up
Handshake Details
Request URL: http://localhost:3001/
Request Method: GET
Request Headers
Sec-WebSocket-Version: 13
Sec-WebSocket-Key: cShC021nW+/sgNEMisMOaw==
Connection: Upgrade
Upgrade: websocket
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits
Host: localhost:3001
Here is my code that I am running on my local server for testing purposes for socket.io:
const express = require('express');
const socketIO = require('socket.io');
const port = process.env.PORT || 3001;
let app = express();
let server = http.createServer(app);
let io = socketIO(server);
io.on('connection', (socket) => {
console.log('A new user just connected');
});
server.listen(port, () => {
console.log(`Server is up on port ${port}`);
});
Here is my code for ws that is working fine:
const app = express();
const server = require('http').createServer(app);
const WebSocket = require('ws');
const { uuid } = require('uuidv4');
const wss = new WebSocket.Server({ server: server });
wss.on('connection', (ws) => {
let initMsg = {
id: uuid(),
msg: 'Welcome to the server, please take your ticket',
};
ws.on('message', (msg) => {
wss.clients.forEach((client) => {
if (client !== ws && client.readyState === WebSocket.OPEN) {
client.send(msg.toString());
}
});
});
});
server.listen(3002, () => {
console.log('listening on port 3000');
});
Package.json:
"dependencies": {
"express": "^4.17.2",
"moment": "^2.29.1",
"socket.io": "^2.4.1"
}
Thanks in advance... :)

websocket connection to 'wss://url_from_aws_domain/socket.io/?EIO=4&transport=websocket' failed?

I have implemented a real time notification using socket.io(https://cdnjs.com/libraries/socket.io) on my local and it is working fine. But when I try to implement it on the live server deployed at AWS domain, the frontend that is establishing socket connection to server got error, websocket is unable to connect on the server throwing error:
websocket connection to
'wss://url_from_aws_server/socket.io/?EIO=4&transport=websocket'
failed?
Front-end Side(notification sender)
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.0.1/socket.io.min.js"></script>
<script>
var socket = io('https://app.url_from_aws_server.com:4492', { transports: ['websocket', 'polling', 'flashsocket'] });
$(document).on("click",'#confirmSlot',function(){
socket.emit("notify_platform", {
"shop": locationName,
"therapist": therapistName,
"date": therapistDate,
"time": therapistTime,
});
}
</script>
Server Side
const express = require('express');
const app = express();
...
const sslOptions = {
key: fs.readFileSync(path.join(__dirname, '../ssl/key.pem')),
cert: fs.readFileSync(path.join(__dirname, '../ssl/cert.pem')),
requestCert: false,
rejectUnauthorized: false,
};
const https = require('https').createServer(sslOptions, app);
const io = require('socket.io')(https, {
cors: {
origin: 'https://app.url_from_aws_server.com:4492',
methods: ['GET', 'POST'],
},
});
...
https.listen(process.env.SSL_PORT, () => {
console.log(
`HTTPS Server started at ${process.env.SSL_PORT}, Database - ${process.env.MONGODB_URI}`
);
io.on('connection', function(socket){
console.log('Auth value:' + socket.id);
socket.on('notify_platform', function(details){
socket.broadcast.emit('notify_platform', details);
})
})
});

NodeJS as Websocket client using ws

I need to send a message to a websocket server through request POST. The client is not a browser but a Node server.
I'm new to websocket.
When I run the code below.
var WebSocket = require("ws");
const express = require("express");
var app = express();
const client = new WebSocket(process.env.URL);
client.on("error", handleError);
client.onopen = () => {
client.send("Message From Client");
};
function handleError(error) {
console.log(error);
}
app.get("/echo", async function (req, res) {
client.once("connection", function connection(cli) {
cli.send(msg);
res.send("send");
});
});
app.listen(3333, function () {
console.log("Example app listening on port 3333!");
});
It shows the error
Error: write EPROTO 19524:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:c:\ws\deps\openssl\openssl\ssl\record\ssl3_record.c:332:
at WriteWrap.onWriteComplete [as oncomplete] (internal/stream_base_commons.js:92:16) {
errno: 'EPROTO',
code: 'EPROTO',
syscall: 'write'
}
I'm not sure how to do it with express, but it should be similar to https. Here is how to do it with https.
Basically it has to be the https server that should listen on certain port and also have certs and keys as option passed to it. Then you would pass the https server to websocket server.
When client connects, it'll connect to https and then upgrade to WSS.
Which means your client application can connect to wss://test.mysite.com:1234.
const https = require('https')
const options = {
cert: fs.readFileSync('/etc/ssl/test.mysite.com/cert.pem'),
key: fs.readFileSync('/etc/ssl/test.mysite.com/privkey.pem'),
ca: fs.readFileSync('/etc/ssl/test.mysite.com/chain.pem')
};
const httpsServer = https.createServer(options);
httpsServer.listen(1234, () => console.log('Https Server running on port 1234'));
var ws = new WebSocket.Server({
server: httpsServer
});
ws.on('connection', socket => {
console.log('Conencted')
});

Client-side websocket certificate in NodeJS

I have a NodeJS websocket client app, using ws https://www.npmjs.com/package/ws - this NodeJS app connects as a client to a websocket server.
I can use HTTPS by specifying wss:// as the protocol.
How can I make the TLS connection use a client certificate for authentication?
i.e. the websocket client should use a certificate to prove its identity to the server.
I found:
it('connects to secure websocket server with client side certificate', function(done) {
const server = https.createServer({
cert: fs.readFileSync('test/fixtures/certificate.pem'),
ca: [fs.readFileSync('test/fixtures/ca1-cert.pem')],
key: fs.readFileSync('test/fixtures/key.pem'),
requestCert: true
});
let success = false;
const wss = new WebSocket.Server({
verifyClient: (info) => {
success = !!info.req.client.authorized;
return true;
},
server
});
wss.on('connection', () => {
assert.ok(success);
server.close(done);
wss.close();
});
server.listen(0, () => {
const ws = new WebSocket(`wss://localhost:${server.address().port}`, {
cert: fs.readFileSync('test/fixtures/agent1-cert.pem'),
key: fs.readFileSync('test/fixtures/agent1-key.pem'),
rejectUnauthorized: false
});
});
});
on https://github.com/websockets/ws/blob/14d9088391ac4495d04e64d76c3b83d4e75f80e2/test/websocket.test.js

Create Websocket Secure on a HTTPS web server in express app

I have a application in express.js. Am unable to create wss on a HTTPS web server.
var fs = require('fs');
var express = require('express');
var app = express();
var cfg = {
ssl: true,
port: 8001,
ssl_key: 'sslcert/ssl.key',
ssl_cert: 'sslcert/ssl.crt'
};
var httpServ = (cfg.ssl) ? require('https') : require('http');
if (cfg.ssl) {
httpsServer = httpServ.createServer({
key: fs.readFileSync(cfg.ssl_key),
cert: fs.readFileSync(cfg.ssl_cert)
}, app)
.listen(cfg.port, function () {
console.log('Magic happening at https://Secure');
});
} else {
httpsServer = httpServ.createServer(app)
.listen(cfg.port, function () {
console.log('Magic happening at http://InSecure');
});
}
var WebSocketServer = require('websocket')
.server;
var wsServer = new WebSocketServer({
httpServer: httpsServer
});
wsServer.on('connection', function connection(ws) {
console.log('Socket Connected');
});
I'm under the impression that passing a reference of the web server to WebSocket, then WebSocket would know the port and SSL capabilities of the server. But every time I get an error in the console
WebSocket connection to 'ws://localhost:8001/?trackme=TUKOCVPAF' failed: Connection closed before receiving a handshake response
How can I create a wss://localhost:8001/?trackme=TUKOCVPAF' when creating the Websocket..??

Resources