Socket.IO can't connect through https - javascript

I have a node.js app, that uses socket.IO. It works fine on http, but when trying to connect to the socket through https - nothing happens.
Here's some part of the code:
var fs = require('fs');
var ioHttp = require('socket.io').listen(8899, {
'flash policy port': -1
});
initSocket(ioHttp);
var ioHttps = require('socket.io').listen(8895, {
key: fs.readFileSync('/path/to/file/file.key'),
cert: fs.readFileSync('/path/to/file/file.crt'),
ca: [
fs.readFileSync('/path/to/file/sub.class1.server.ca.pem'),
fs.readFileSync('/path/to/file/ca.pem')
],
'flash policy port': -1
});
initSocket(ioHttps);
and the initSocket function:
function initSocket(io) {
io.enable('browser client minification');
io.enable('browser client etag');
io.enable('browser client gzip');
io.set('transports', [
'websocket',
'htmlfile',
'flashsocket',
'jsonp-polling'
]);
io.sockets.on('connection', function (client) {
//the connnection is handled here
});
}
The client connect like this:
var secureConnection = false;
var port = 8899;
if (window.location.protocol === 'https:') {
port = 8895;
secureConnection = true;
}
var socket = io.connect('domain.org', {port: port, secure: secureConnection});
As I said everything works fine on http, but connecting on https gives me "The connection was interrupted". What am I doing wrong?

You cannot initalize socket.io server like https server. You have to start a separate https server and then attach socket.io server to it.
var https = require('https'),
fs = require('fs');
var options = {
key: fs.readFileSync('ssl/server.key'),
cert: fs.readFileSync('ssl/server.crt'),
ca: fs.readFileSync('ssl/ca.crt')
};
var app = https.createServer(options);
io = require('socket.io').listen(app); //socket.io server listens to https connections
app.listen(8895, "0.0.0.0");

Related

Websocket connection error: returns 101, but does not upgrade

I am setting up some websockets using ws library. I am struggling to set up authorisation using a handshake. I have added a route to our server to upgrade to a websocket connection like so:
.get(
'/chat',
authorisationFunction,
upgradeConnection,
),
The websocket server:
const WebSocket = require('ws');
const wss = new WebSocket.Server({ port: 3030 });
This is the upgradeConnection function, which will run if authorisation is successful:
const upgradeConnection = (request, socket, head) => {
return wss.handleUpgrade(request, request.socket, head, function done(ws) {
return wss.emit('connection', ws, request);
});
}
I also have a function that listens to messages:
function webSocketsServer() {
wss.on('connection', (ws, request, client) => {
ws.on('message', message => {
ws.send(message);
});
});
}
A connection gets emitted, and from my server I get this response:
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: QyVvqadEcI1+ALka6j2pLKBkfNQ=
but then immediately on my client I get the error “WebSocket connection to 'ws://localhost:3000/chat’ failed: Invalid frame header”.
But when I bypass the handshake and connect directly to my websocket server, I can send messages successfully. The error is only on the client and not on the backend. What am I missing?
I am not 100% sure it is the only way but might help so I post it.
Based on this answer I would go for a server that uses the same port for http and websocket connections.
You can achieve it like this:
const { createServer } = require('http')
const ws = require('ws')
const express = require('express')
const app = express()
const server = createServer(app)
app.get('/', (req, res) => {
res.send('I am a normal http server response')
})
const wsServer = new ws.Server({
server,
path: '/websocket-path',
})
wsServer.on('connection', (connection) => {
connection.send('I am a websocket response')
})
server.listen(3030, () => {
console.log(`Server is now running on http://localhost:3030`)
console.log(`Websocket is now running on ws://localhost:3030/<websocket-path>`)
})
So your server listens on port 3030 for normal http requests. If it gets a websocket connection request on path '/websocket-path' it is passed to the the ws connection handler and from there you are good to go.

Is there a way to communicate with WebSocket over SSL from NativeScript app?

Currently I am writing a NS app that will communicate with a WebSocket over SSL. Here is server's code (server.js):
var fs = require('fs');
var cfg = {
port: 8082,
ssl_key: fs.readFileSync('keys/server.key'),
ssl_cert: fs.readFileSync('keys/server.crt'),
ca: fs.readFileSync('keys/ca.crt')
};
var httpServ = require('https');
var WebSocketServer = require('ws').Server;
var app = null;
// dummy request processing
var processRequest = function( req, res ) {
res.writeHead(200);
res.end("All glory to WebSockets!\n");
};
app = httpServ.createServer({
// providing server with SSL key/cert
key: cfg.ssl_key,
cert: cfg.ssl_cert,
ca: cfg.ssl.ca,
passphrase: '1234',
requestCert: true,
rejectUnauthorized: false,
}, processRequest ).listen( cfg.port );
var wss = new WebSocketServer( { server: app } );
wss.on('connection', function(ws) {
console.log("Connected!");
ws.on('message', function(message) {
console.log('received: %s', message);
});
ws.send('something');
});
Server is running well without problem. Below is the client code (wsclient.js):
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:8082');
ws.on('open', function open() {
ws.send("dummy");
ws.on('error', function(evt) {
console.log("The socket had an error", evt.error);
});
});
When I ran the client by typing node wsclient.js, it throw the following error:
Error: unable to verify the first certificate
Obviously, the error was caused by not providing the certificate info to the request. But I have no idea how to get this done in my client code. Thanks a lot for any clues or suggestions.
Finally I found the answer:
const WebSocket = require('ws');
const ws = new WebSocket('wss://localhost:8082',{
key: fs.readFileSync('./keys/client.key'),
cert: fs.readFileSync('./keys/client.crt'),
ca: fs.readFileSync('./keys/ca.crt')
});
ws.on('open', function open() {
ws.send("dummy");
ws.on('error', function(evt) {
console.log("The socket had an error", evt.error);
});
});
Now it works!

ERR_SSL_PROTOCOL_ERROR - Socket.io and Node.js

I’m working with the Node.js server and using the Socket.io to manage connections by Socket but I’m having a problem with the SSL certificate.
Lot of users can access the Node.js server normally, but others users doesn’t access and they receive this error:
When I set my server I have this SSL options:
var privateKey = fs.readFileSync('/root/cert/key.key', 'utf8').toString();
var certificate = fs.readFileSync('/root/cert/cert.crt', 'utf8').toString();
var ca = fs.readFileSync('/root/cert/ca.crt').toString();
var credentials = { key: privateKey, cert: certificate, ca: ca };
var app = express();
var httpsServer = https.createServer(credentials, app);
var io = require('socket.io')(httpsServer);
Somebody knows how to resolve this error? The problem is only some users receive this error.
Well, as far as I can see, you are missing a listening port for you https server.
var httpsServer = https.createServer(credentials, app).listen(<port>);
I had so much trouble with ERR_SSL_PROTOCOL_ERROR that I have to give you my solution
NodeJS server 16.15.0 with "socket.io": "2.4.1" (I assume it works with other NodeJS versions)
const path = require("path");
const fs = require("fs");
const io = require("socket.io")();
const folder = path.join(__dirname, "ssl");
const privateKey = fs.readFileSync(path.join(folder, "server_key.pem"), "utf8");
const certificate = fs.readFileSync(path.join(folder, "server_cert.pem"), "utf8");
const optSsl = {
key: privateKey,
cert: certificate,
ca: [certificate],
requestCert: false, // put true if you want a client certificate, tested and it works
rejectUnauthorized: false,
};
const server = require("https");
const webServer = server.createServer(optSsl);
webServer.listen(8025); // port number
io.listen(webServer);
io.on("connection", (client) => {
/*...*/
});
/*...*/
Angular 10.2.7 with "ngx-socket-io": "3.2.0" (I assume it works also with other Angular versions)
import { Socket, SocketIoConfig } from 'ngx-socket-io';
/*...*/
socket: Socket;
socketConfig: SocketIoConfig;
socketConfig = {
url: "https://myserver:8025",
options: {},
};
socket = new Socket(socketConfig);
socket.connect();
Looks like your apache2 is not properly configured.
Check if you have your config file enabled:
a2ensite default-ssl
And then restart the server.

Can't get socket.io and nodejs running with OpenShift

I can't get socket.io running on OpenShift. I googled for some hours now but nothing really helped me. Locally it works fine (with different ports and localhost as host of course).
This is my server.js file:
var port = process.env.OPENSHIFT_NODEJS_PORT || 8080;
var ipadr = process.env.OPENSHIFT_NODEJS_IP || "127.0.0.1";
var http = require('http').createServer(function(request, response) {
response.writeHead(200, {"Content-Type": "text/plain"});
response.end();
}).listen(port,ipadr);
console.log(port+":"+ipadr);
var io = require('socket.io').listen(http),
fs = require('fs'),
request = require('request'),
mysql = require('mysql'),
moment = require('moment'),
connectionsArray = [],
connection = mysql.createConnection({
host: 'xxx',
user: 'xxx',
password: 'xxx',
database: 'xxx',
port: 3306
}),
POLLING_INTERVAL = 1000,
pollingTimer;
io.on('connection', function(socket){
console.log('a user connected');
});
var updateSockets = function(data) {
// adding the time of the last update
t = new Date();
t = moment().format('H:mm:ss');
console.log('(%s) Connections: %s', t, connectionsArray.length);
// sending new data to all the sockets connected
connectionsArray.forEach(function(tmpSocket) {
tmpSocket.volatile.emit('notification', data);
});
};
console.log('server.js executed\n');
When I run this on SSH OpenShift it just shows the first console.log with my port and ipadress of OpenShift and the last line of my server.js code:
server.js executed
and that's it. So I don't get the "a user connected" message like when I test it locally.
This is how I want to connect in my client-side .js-file:
var socket = io.connect('http://njs-uniqo.rhcloud.com:8080/');
Browser (Chrome) Console outputs:
> ?s=product&id=10:1 XMLHttpRequest cannot load http://xxx.rhcloud.com:8000/socket.io/?EIO=3&transport=polling&t=1430395459829-1.
> No 'Access-Control-Allow-Origin' header is present on the requested
> resource. Origin 'http://localhost' is therefore not allowed access.
> The response had HTTP status code 503.
If I change the port to 8080 on the client-side .js-file I get ERR_CONNECTION_TIMED_OUT:
GET http://xxx.rhcloud.com:8080/socket.io/?EIO=3&transport=polling&t=1430395346761-6 net::ERR_CONNECTION_TIMED_OUT
You need to use port 8000. It's what openshift forces for websockets.
var socket = io.connect('http://yourapp.rhcloud.com:8000/',{'forceNew':true });
Port 8000 is for http and 8443 is for https
Source
You must edit package.json. Add...
"socket.io": "~0.9.16"
...under dependencies. The server then automatically downloads socket.io which is not present by default.

Connecting to a test websocket server works, but connecting to my Node.js server fails

I'm using the code below to test websockets on my browser:
this.webSocket = new WebSocket("ws://echo.websocket.org");
this.webSocket.onopen = function(evt) {
cc.log("Send Text WS was opened.");
};
this.webSocket.onmessage = function(evt) {
this.socketSendTextTimes++;
var textStr = "response text msg: " + evt.data + this.socketSendTextTimes;
cc.log(textStr);
};
The code works well, but if I connect to my own server running the code below:
var http = require('http');
var io = require('socket.io');
var server = http.createServer(function(req, res) {
// Send HTML headers and message
res.writeHead(200,{ 'Content-Type': 'text/html' });
res.end('<h1>Hello!</h1>');
});
var socket = io.listen(server);
socket.set('destroy upgrade', false);
socket.on('connection', function(client) {
client.on('message', function(event) {
console.log('Received message from client!', event);
});
client.on('disconnect', function() {
console.log('Server has disconnected');
});
});
server.listen(8080);
console.log('start to listen');
My browser displays:
hello!
But the listening socket does not do anything. How can I connect to the Socket.IO server using websockets?
Socket.IO uses alternate transport methods than the native websocket, even when emulating websockets themselves. You will need the client library to connect to Socket.IO sockets.

Categories

Resources