Node.js Socket.io HTTPS - transport polling - node.js

I am using nginx with my ssl certificates and it's giving me the https version of my site which is great. The problem is my socket.io communications don't work unless i use a regular http connection. I apologize if this is a bit long, but i'm not sure what i'm doing here and wanted to make sure you guys had everything you might need to know. I have tried the solutions of various different sites some of which were on here, but none of them worked.
I tried manually creating the https server instead of letting express do it but that resulted in nothing loading at all, with the current implementation i can at least see the site.
upstream project {
server example.org:4000;
}
server {
listen 80;
return https://$host$request_uri;
}
server {
listen 443 ssl default_server;
listen [::]:443 ssl default_server;
ssl_certificate /home/adam/SSL/public.crt;
ssl_certificate_key /home/adam/SSL/example.org.key;
ssl_prefer_server_ciphers on;
location / {
proxy_pass http://example.org;
}
}
That seems to be working as when i go to my site, it automatically takes me to the https version and the page is loaded. The issue is when is when the client side tries to connect i keep getting:
"https://MY_SERVER_IP:4040/socket.io/?EIO=3&transport=polling&t=M0CPjUDnet::ERR_CONNECTION_CLOSED"
printed to the console
Here's my client and server code:
var IPaddress = 'https://MY_SERVER_IP:4040';
var socket = io.connect(IPaddress,{secure:true});
socket.on('connect', function (socket) {
console.log('Connected!');
});
server code:
var express = require('express');
var app = express();
var privateKey = fs.readFileSync(__dirname+'/SSL/example.com.key','utf8');
var certificate = fs.readFileSync(__dirname+'/SSL/public.crt','utf8');
var intermediate = fs.readFileSync(__dirname+'/SSL/intermediate.crt','utf8');
var options = {key:privateKey,cert:certificate,ca:intermediate};
var io = require('socket.io').listen(4040,options);
//var io = require('socket.io').listen(4040);
io.sockets.on('connection', function (socket) {
socket.on('disconnect',function(){
console.log("A client has left us :(");
});
});
app.listen(4000);
Update - 02/12/2017
In my code i have this line:
require('./routes.js')(app);
which contains:
module.exports = function(app) {
app.get('/main',function(req,res){
if (req.session.user == null){
// if user is not logged-in redirect back to login page //
res.redirect('/');
} else{
res.sendFile(path.join(__dirname + '/FrontEnd/main.html'));
}
});
// viewed at http://localhost:8080
app.get('/', function(req, res) {
if(req.cookies.user == undefined || req.cookies.pass == undefined){
res.sendFile(path.join(__dirname + '/FrontEnd/login.html'));
}else {
//attempt automatic login
AM.autoLogin(req.cookies.user,req.cookies.pass,function(o){
if(o !=null){
req.session.user = o;
res.sendFile(path.join(__dirname + '/FrontEnd/home.html'));
}else{
res.sendFile(path.join(__dirname + '/FrontEnd/login.html'));
}
});
}
});
......
Could this be causing the 502 bad gateway error?

Expanding on my comment, in your current server code, both express and socket.io are only accepting regular HTTP connections. The socket.io listen(port[, options]) function does not accept HTTPS connections.
You started on the right approach with manually creating an HTTPS server. You then need to attach express and socket.io to that server.
var fs = require('fs');
var express = require('express');
var app = express();
var privateKey = fs.readFileSync(__dirname + '/SSL/example.com.key', 'utf8');
var certificate = fs.readFileSync(__dirname + '/SSL/public.crt', 'utf8');
var intermediate = fs.readFileSync(__dirname+'/SSL/intermediate.crt', 'utf8');
var options = { key: privateKey, cert: certificate, ca: intermediate };
// Create our HTTPS server here and attach express to it
var server = require('https').createServer(options, app);
// Attach socket.io to our existing HTTPS server
var io = require('socket.io')(server);
io.sockets.on('connection', function (socket) {
socket.on('disconnect', function() {
console.log("A client has left us :(");
});
});
server.listen(4000);

Related

Making Node js apps https secure

I am creating a chaincode project , in which nodejs is consuming the chaincoe smartcontract.
My project structure includes index.js - swagger specs , app.js - to consumer swagger specs and bin/www - where http specification is defined .
I have defined http with basic auth and it works fine. For making all the services https secure , I have downloaded open ssl in my linux machine and have generated the certificate and the private key. (https://www.linuxhelp.com/how-to-install-and-update-openssl-on-ubuntu-16-04/)
I have made changes in the bin/www.js for the https part :
#!/usr/bin/env node
var app = require('../app');
var fs = require('fs');
var http = require('http');
var https = require('https');
require("dotenv").config();
var privateKey = fs.readFileSync('key.pem').toString();
var certificate = fs.readFileSync('cert.pem').toString();
var port = normalizePort(process.env.PORT || '8080');
app.set('port', port);
var hostname = process.env.HOSTNAME;
function normalizePort(val) {
var port = parseInt(val, 10);
if (isNaN(port)) {
// named pipe
return val;
}
if (port >= 0) {
// port number
return port;
}
return false;
}
https.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.write('Hello World!');
res.end();
}).listen(8080);
but this is not working . I have also imported the certificate and key in the mozilla. Request all to kindly help on this.
Thanks in advance.
You need to add the key and cert to the createServer function.
const options = {
key: fs.readFileSync('key.pem').toString();
cert: fs.readFileSync('cert.pem').toString();
}
https
.createServer(options, function (req, res) {
res.writeHead(200);
res.end("hello world\n");
})
.listen(443, function(){
console.log("Server listening on localhost:443");
});
Now, as #aditi said in the comments, the callback in createServer is a request handler. That means it will trigger when there is a request event. A request event is triggered by mostly HTTP requesting the server. So, if you open localhost:443 it will show you the "hello world" text.
If you want to console log something when the server is started (listing) you need to add the callback in the listen function. Which you have done.
it worked ,
I used
https.createServer(httpsOptions,app)
.listen(port,function(){
console.log("Inside HTTPS creation");
})
Thanks all.

Node.js, socket.io https connection

Server side code:
var io = require('socket.io').listen(8150);
io.sockets.on('connection', function (socket){
});
Client side code:
var socketIO = io('*.*.*.*:8150');
socketIO.once('connect', function(){
});
On http it's worked on https in same page it not connected.
Searched many examples, but all example for express. I dont create any http server in node.js need only to socket.io work.
When running the client over HTTPS, socket.io is attempting to connect to your server over HTTPS as well. Currently your server is only accepting HTTP connections, the listen(port) function does not support HTTPS.
You'll need to create an HTTPS server and then attach socket.io to it, something like this.
var fs = require('fs');
var options = {
key: fs.readFileSync('certs/privkey.pem'),
cert: fs.readFileSync('certs/fullchain.pem')
};
var app = require('https').createServer(options);
var io = require('socket.io').listen(app);
app.listen(8150);
io.sockets.on('connection', function (socket) {
});
And if you need both HTTP and HTTPS, you can start two servers and attach socket.io to both.
var fs = require('fs');
var options = {
key: fs.readFileSync('certs/privkey.pem'),
cert: fs.readFileSync('certs/fullchain.pem')
};
var httpServer = require('http').createServer();
var httpsServer = require('https').createServer(options);
var ioServer = require('socket.io');
var io = new ioServer();
io.attach(httpServer);
io.attach(httpsServer);
httpServer.listen(8150);
httpsServer.listen(8151);
io.sockets.on('connection', function (socket) {
});
Then on the client side you can determine which port to connect to based on whether the page was accessed over HTTP or HTTPS.
var port = location.protocol === 'https:' ? 8151 : 8150;
var socketIO = io('*.*.*.*:' + port);
socketIO.once('connect', function() {
});
Use letsencrypt with Plesk for a valid SSL certificat.
options = {
key: fs.readFileSync('/usr/local/psa/var/modules/letsencrypt/etc/live/mydomain.com/privkey.pem'),
cert: fs.readFileSync('/usr/local/psa/var/modules/letsencrypt/etc/live/mydomain.com/cert.pem'),
ca: fs.readFileSync('/usr/local/psa/var/modules/letsencrypt/etc/live/mydomain.com/chain.pem'),
rejectUnauthorized: false,
requestCert: true,
agent: false
}

nodejs can't work with SSL

Im trying to run nodejs app to work with my php project. the problem is I think with SSL which is enabled in the server.
I have two files that I found in my root directory after SSL install: domain.com.csr and domain.com.key and I tried to combine them to connection while creating https server, but nothing worked for me.
so far I have this code:
var socket = require('socket.io');
var express = require('express');
var http = require('http');
var app = express();
var server = http.createServer(app);
var io = socket.listen(server);
app.get('/test', function(req, res) {
res.send('hello world');
console.log('visited test')
});
io.sockets.on('connection', function (client) {
console.log("New client !");
client.on('message', function (data) {
console.log('Message received ' + data.name + ":" + data.message);
io.sockets.emit('message', {name: data.name, message: data.message});
});
});
server.listen(8080, function () {
console.log('listen me on: 8080');
});
and it works well when I'm trying to visit http://ip:8080/test so it means that node server is working, but when I try to create socket connection on my view file var socket = io.connect('http://ip:8080'); it gives me error:
The page at 'https://www.domain.com/' was loaded over HTTPS, but requested an insecure XMLHttpRequest endpoint 'http://ip:8080/socket.io/?EIO=3&transport=polling&t=1446818946199-0'. This request has been blocked; the content must be served over HTTPS.
so the problem is clear enough, but how to deal with it?
also I have tried this connection:
var socket = io.connect('https://www.domain.com:8080');
but the result is 404 GET Error. How to deal with it?
Update
now the part of code I should use, but don't know how to get cert of existing SSL in the server.
var socket = require('socket.io');
var express = require('express');
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('path/to/key.pem'), // dont have
cert: fs.readFileSync('path/to/cert.cert') // dont have
};
var app = express();
var server = https.createServer(options, app);
var io = socket.listen(server);
app.get('/test', function(req, res) {
res.send('hello world');
console.log('visited test')
});
io.sockets.on('connection', function (client) {
console.log("New client !");
client.on('message', function (data) {
console.log('Message received ' + data.name + ":" + data.message);
io.sockets.emit('message', {name: data.name, message: data.message});
});
});
server.listen(443, function () {
console.log('listen me on: 443');
});
I think you need to contact your certificate authority (the organization that issued your first ssl certificate) and get a copy of the certificate (the path/to/key.pem and path/to/cert.cert) or find the existing keys somewhere on your existing server.
If you're running apache, your configuration file will have a section with values for the paths of the .cert and .pem files labeled SSLCertificateFile and SSLCertificateKeyFile, then just update the paths in your node app to point to them. You also have to make sure that your SSL certificate meets the requirements (for example, needs to be Multi-domain if your node app runs on a different domain, or a Wildcard SSL certificate to run your node app on a subdomain).
The domain.com.csr and domain.com.key files you found are the private key and certificate request used to generate your initial SSL certificate and aren't going to do anything to enable SSL on your node app.

Intercept HTTP responses on an HTTPS server in Node.JS and Express

I'm just starting with node.js and express and I'm doing a simple HTTPS server. I've been working with nginx for some time and when I make an HTTP request to an HTTPS endpoint I get a "400 Bad Request" error. However, when using node.js the request never finishes.
How can I intercept an HTTP request in Express to be able to generate the "400 Bad Request" response?
This is my code:
var express = require('express');
var https = require('https');
var fs = require('fs');
var port = process.env.PORT || 8080;
var tls_options = {
key: fs.readFileSync('certs/server.key'),
cert: fs.readFileSync('certs/server.crt'),
ca: fs.readFileSync('certs/ca.crt'),
requestCert: true,
};
var app = express();
var router = express.Router();
router.get('/', function(req, res) {
res.json({ message: 'Checkpoint!!' });
});
app.use('/', router);
var secureServer = https.createServer(tls_options, app);
secureServer.listen(port);
console.log('Listening on port ' + port);
Until now the only thing I've been able to use is getting a 'connection' event every time a request arrives to the server:
secureServer.on('connection', function (stream) {
console.log('someone connected!');
});
Done. In fact, an HTTP request to an HTTPS socket ends after the default 120secs TLS handsahke timeout. This way I can end the request without waiting. I include the solution I used just for future references if anything needs the same functionality.
var secureServer = https.createServer(options, app);
secureServer.on('connection', function(socket) {
socket.on('data', function(data) {
var first_line = data.toString().split('\r\n')[0];
var pattern = /\bhttp\/1\.[01]$\b/i;
if (pattern.test(first_line)) {
var headers = {};
headers['Date'] = new Date().toUTCString();
headers['Connection'] = 'close';
var headers_string = '';
for (var name in headers) {
headers_string = headers_string + '\r\n' + name + ': ' + headers[name];
}
socket.end('HTTP/1.1 400 Bad Request' + headers_string);
}
});
There isn't a way of starting both HTTP and HTTPS servers on the same port. What most people do is either:
Start two servers (one HTTP and one HTTPS) on different ports, and redirect the HTTP traffic to HTTPS. Using Express it would mean the additional code:
// create two ports, one for HTTP and one for HTTPS
var port = process.env.PORT || 8080;
var httpsPort = 8081;
// redirect all HTTP requests to HTTPS
app.use(function(req, res, next) {
var hostname;
if (!req.secure) {
hostname = req.get("host").split(":")[0];
return res.redirect(["https://", hostname, ":", httpsPort, req.url].join(""));
}
next();
});
app.listen(port); // listen on HTTP
https.createServer(tls_options, app).listen(httpsPort); // listen on HTTPS
Or they use nginx or apache to handle outside connections (both HTTP and HTTPS) and redirect traffic to the Node server (which can then just run on HTTP).

Nodejs SSL for SockJS + Express

I've got a simple SockJS and Express server in nodejs. Now id like to add SSL support for these servers.
Here is my server code:
var sockjs = require('sockjs');
var my_http = require("http");
var https = require('https');
var fs = require('fs');
var options = {
key: fs.readFileSync('test/keys/key.pem'),
cert: fs.readFileSync('test/keys/cert.pem')
};
// Create a service (the app object is just a callback).
var app = express();
// Create an HTTP service.
http.createServer(app).listen(8008);
// Create an HTTPS service identical to the HTTP service.
https.createServer(options, app).listen(443);
var echo = sockjs.createServer({
log: function (severity, message) {}
});
echo.on('connection', function (conn) {
conn.on('data', function (message) {
conn.write(message);
});
conn.on('close', function () {
});
});
var server = my_http.createServer();
echo.installHandlers(server, {
prefix: '/echo'
});
server.listen(8081, '0.0.0.0');
var server_https = my_http.createServer(options);
echo.installHandlers(server_https, {
prefix: '/echo'
});
server_https.listen(443, '0.0.0.0');
app.get('/type/:channel', function (req, res) {
res.setHeader('Content-Type', 'application/json');
res.send("Hello");
res.end();
});
Problem is that i get the port already in use error:
Error: listen EADDRINUSE
I've got Nginx listening on 443 otherwise my site would not work on ssl.
Any ideas how to set this up?
Inside of your nginx config you should have your port listed in 'upstream'. In your case you probably have the same port listed under server. It shows that error when you do that. See below for proper configuration (If you change "listen 80" to "listen 8000" you'll see that error):
upstream app_yourAppName {
server 127.0.0.1:8000;
}
# the nginx server instance
server {
listen 80;
...
...
}

Resources