Implementing / forcing SSL for LocomotiveJS apps (NodeJS / Express) - node.js

With MVC frameworks like LocomotiveJS now available for NodeJS / Express, I'm just wondering how it would be possible to implement SSL on part of an app?
For example, an ecommerce app.
I'd need all /checkout controllers to force SSL.
I've read tutorials like this one but not sure on how to implement this with Locomotive, since Express is effectively "wrapped" ?

Currently SSL is not directly supported by Locomotive, but should be soon, according to this Google Groups posting in April by Jared Hanson, the creator of Locomotive.
Currently, I've always been putting Locomotive behind a proxy that
terminates SSL. But, I'll be adding a command line option for this
shortly, for direct support.
That said, if you want a completely node-based solution without using a proxy, then for the time being you'll need to edit the Express instance in Locomotive. I've tested the below and it's working well.
As of writing, npm install locomotive uses Express 2.x, though the latest at github has since been updated to use Express 3.x.
If you're using Locomotive with Express 2.x, then I think you have to edit /locomotive/lib/locomotive/index.js, around line 180, to look something like:
var sslOptions = {
cert : fs.readFileSync('/path/to/your/ssl-cert/dev.crt')
, key : fs.readFileSync('/path/to/your/ssl-key/dev.key')
};
var self = this
, server = express.createServer(sslOptions)
, entry;
Additionally, you will probably still want to listen on HTTP and redirect all traffic to HTTPS. Sticking with an all node-based solution, you could simply start another Express server at the end of /locomotive/lib/locomotive/cli/server.js that redirects all its traffic to HTTPS, e.g.
...
debug('booting app at %s in %s environment', dir, env);
locomotive.boot(dir, env, function(err, server) {
if (err) { throw err; }
server.listen(port, address, function() {
var addr = this.address();
debug('listening on %s:%d', addr.address, addr.port);
});
// add an http server and redirect all request to https
var httpServer = require('express').createServer();
httpServer.all('*', function(req, res) {
res.redirect('https://' + address + ':' + port + req.url);
});
httpServer.listen(80); // probably change based on NODE_ENV
});
}
Lastly, start the server:
$ lcm server -p 443 # again, probably use different port in development

All those frameworks are based on top of Express which based is on connect which has HTTPS support.
Anyway in a real life situation you might want to want to have a nginx/or nother proxy handling the https for you anyway.

Related

force node.exe to go throw proxifier on windows 10

I am developing bots for telegram, I am from Iran and telegram url is blocked in my country and I am forced to use VPN/Proxy servers to access telegram api from my local dev machine.
But I have other apps running on my system that won't work throw a VPN, So I am forced to use proxifier, I can define rules for the apps that I need to go throw a proxy.
But node.exe is ignoring this rules for some reason, I can see in NetLimiter that the connection is coming from C:\Program Files (x86)\nodejs\node.exe, But adding this path to proxifier's rules has no effect, other apps like telegram itself and firefox and ... works fine with these rules ...
So has anyone managed to force node.exe to go throw proxifier?
I also tried to setup a proxcy with php in my host, but none of the proxy scripts I found was able to handle the file uploads
My last hope is to install some modules for apache and use it as a proxy or just install nginx ...
I also tried https://github.com/krisives/proxysocket and https://github.com/TooTallNate/node-https-proxy-agent with no success, its just keeps throwing errors :(
Ok, after hours of trying finally got this to work with proxifier.
https://github.com/TooTallNate/node-https-proxy-agent
new HttpsProxyAgent('http://username:password#127.0.0.1:8080')
Update :
This approach had its problems so I created a small personal proxy server with node-http-proxy on my server and connected to it:
process.env["NODE_TLS_REJECT_UNAUTHORIZED"] = 0;
const debug = require('debug')('app');
const http = require('http');
const httpProxy = require('http-proxy');
const proxy = httpProxy.createProxyServer({
secure : false
});
proxy.on('error', function (e) {
debug(e);
});
const server = http.createServer(function(req, res) {
// You can define here your custom logic to handle the request
// and then proxy the request.
proxy.web(req, res, { target: 'https://api.telegram.org', });
});
server.listen(3333);
And simply just redirected all the request to this server.

How to make Socket IO work over HTTPS using node.js

This is frustrating me like crazy!
i'm using a proxy so that any requests that go to myurl/APP/ are answered by node.js at myurl:8001
I now need this to work over https. easy.... i thought.
i have Apache serving up the old version from the public folder. That is stand alone, and when i'm done building this, it will just be removed. but for now needs to remain in tact and accessible. Lets encrypt is setup on this. and https://myurl works fine, showing content from the public folder of course.
if i go to https://myurl:8001 then chrome says "site can't be reached". If i go to http://myurl:8001 it works fine. I think this is because https default port is 443. I have VPS not dedicated so i don't think i can alter that. And surely if i did alter the ssl port then it wont work for the public folder??
i'll show you the basics of whats going on;
app.js;
var express = require('express');
var app = express();
var serv = require('http').Server(app);
app.get('/',function(req, res) {
res.sendFile(__dirname + '/client/index.html');
});
app.use('/client',express.static(__dirname + '/client'));
serv.listen(8001);
console.log("Server started.");
var SOCKET_LIST = {};
var io = require('socket.io')(serv,{});
io.sockets.on('connection', function(socket){
socket.id = Math.random();
socket.x = 0;
socket.y = 0;
socket.number = "" + Math.floor(10 * Math.random());
SOCKET_LIST[socket.id] = socket;
socket.on('disconnect',function(){
delete SOCKET_LIST[socket.id];
});
});
setInterval(function(){
var pack = [];
for(var i in SOCKET_LIST){
var socket = SOCKET_LIST[i];
socket.x++;
socket.y++;
pack.push({
x:socket.x,
y:socket.y,
number:socket.number
});
}
for(var i in SOCKET_LIST){
var socket = SOCKET_LIST[i];
socket.emit('newPositions',pack);
}
},1000/25);
client/index.html;
<canvas id="ctx" width="500" height="500" style="border:1px solid #000000;"></canvas>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.0.3/socket.io.js"></script>
<script>
var ctx = document.getElementById("ctx").getContext("2d");
ctx.font = '30px Arial';
var socket = io.connect('http://www.myurl:8001', {path: "/socket.io"});
socket.on('newPositions',function(data){
ctx.clearRect(0,0,500,500);
for(var i = 0 ; i < data.length; i++)
ctx.fillText(data[i].number,data[i].x,data[i].y);
});
</script>
It works fine as the code is but only over http. I need this to work over SSL
i need this line to work when its https;
var socket = io.connect('https://www.myurl:8001', {path: "/socket.io"});
How is this possible?
any help is greatly appreciated.
Your server code is only creating an http server, not an https server and since socket.io uses your http server, it will only run on http. http and https servers are different (the https server implements certificate verification and data encryption which is not present with the http server).
To make an https server, change this:
var express = require('express');
var app = express();
var serv = require('http').Server(app);
to this:
const express = require('express');
const app = express();
const options = {...}; // fill in relevant certificate info here
const serv = require('https').createServer(options, app);
And, you will have to fill in the appropriate certificateinfo in the options data structure.
https.createServer() code examples are here.
You can then run your https server on any port you want as long as you connect to it with an https URL and the right port number. You are correct that the default port for an https URL is 443 so if not port number is specified, that's what a browser will attempt to use.
Ok this was a bit embarrasing... the actual problem i had was because of the following.
If you can follow this lol...
So in dreamhost they allow you to run apache and serve content in the usual way. there is a /public folder for this. fairly standard stuff.
Because i'm trying to branch out into being able to use sockets (please don't lecture me on using sockets with PHP... let it go!) So i was using dreamhost which allows a person to proxy a node.js app through a port. eg. port xxxx ends up at thewebsiteurl/whateverfolderyouchoose/
ok so in my node.js i was using express. now in express you can specify routing really easy. For some bizzare reason, i cant be bothered to actually find out why, if you know please enlighten me... i had to put double forward slash in the routing, like so "//whateverroute/". all the examples i was learning from use a single forward slash. eg "/whateverroute/" but that didn't work. if you know why, please tell us. So before i figured this out, i couldn't actually route anything correctly, hence having to use the url with the port number at the end. of course that messes up the https. example, https://www.theurl.com:xxxx wasnt secure, because the node.js app wasnt running an https res req server. Actually i did set up the https node server and thought that was the solution to the problem at first.
So the solution to this bizarre problem was the node.js routing. ofcourse its stupidly complicated because, hey life's like that when your learning from google and not someone who actually knows your exact setup.
What turns out to be funny is, i cant stand node.js. I can see the benefit to using it. But it seems like alot of ball ache for something as simple as what i'm making. Also i have now discovered phone/gap so php actually is ok for what i want to do. Ok so i'm hitting the server way to many times with AJAX requests but it's coping with a few hundred users right now and when it hits the 10'000 mark when the site probably wont work very well, i should be making enough to get a real node.js programmer in to learn from.... hopefully.
I do appreciate the help tho guys.

how do i correctly proxy https requests to another https server for cordova

I have a number of different servers running on my system, all of them running a secure connection on there own port, etc. 50001,50002,50003...
all of thees can be accessed directly from https://domain1.com:50001 ...
now, not only do I want to limit the number of ports, but also change the domain so etc.
https://domain1.com:50001 <- https://srv1.domain2.com:443
https://domain1.com:50002 <- https://srv2.domain2.com:443
https://domain1.com:50003 <- https://srv3.domain2.com:443
All of thees servers run separate nodejs instances.
Now I want to build a proxy than redirect this, and I have chosen nodejs since everything else we do is in nodejs.
what i have now:
var app = require('express')();
var options = {
key : fs.readFileSync(CONFIG.sslKey).toString(),
cert : fs.readFileSync(CONFIG.sslCertificate).toString(),
ca : fs.readFileSync(CONFIG.sslCA).toString()
};
var http = require('https').Server(options,app);
var httpProxy = require('http-proxy');
var proxy = httpProxy.createProxyServer({
ssl: {
key : fs.readFileSync(CONFIGsecure.sslKey).toString(),
cert : fs.readFileSync(CONFIGsecure.sslCertificate).toString(),
ca : fs.readFileSync(CONFIGsecure.sslCA).toString()
},
secure: true
});
var handleRequests = function(req, res){
proxyTo = "https://domain1.com:50001"; <= some logic chooses this based on req.headers.host
proxy.web(req, res, { target: proxyTo });
};
app.get('/*', handleRequests );
app.post('/*', handleRequests );
app.put('/*', handleRequests );
app.delete('/*', handleRequests );
http.listen(443, function(){});
okay so this actually works very well, everything is going where it should go in a browser, and in a cordova app using jquery ajax everything also works very well.
however if i use
FileTransfer().download(...)
I get error code 3 (connection error).
If I connect directly to https://domain1.com:50001 (direct) the app works, but if i connect to https://srv1.domain2.com:443 (the proxy) the app does not work.
All the certificates are valid, wildcard certificate on *.domain2.com and single certificate on domain1.com.
The end servers has domain1.com certificate installed and the proxy has *.domain2.com wildcard certificate installed.
Any idea on how to correctly setup a proxy server? The system is windows server 2012 R2 and I am open to use a real proxy if needed. However it would be nice with a solution as simple as possible.
I have tried example two form here:
http://blog.nodejitsu.com/http-proxy-intro/
however this is the same problem, and it is only GET requests.
I have also tried disabling https on the end server so thats it's only the proxy that is secure, however, same result...
Thanks...
Okay so i found the issue, for some reason req.headers.host string also contained the :port, and i was only switching on the address. now everything works perfekt.

Reverse proxy for a NodeJS website

I look for a reverse proxy for my NodeJS website. I thought of Varnish or nginx or something else.
What would you suggest me and why (do not necessarily focus on Varnish vs nginx)?
nginx would probably be the best stand-alone solution, however, when I'm working with Node.js, I prefer to keep everything in Node.js so I don't have to worry about the (relatively simple) configuration. I personally use node-reverse-proxy, which allows me to just specify some simple routes in a simple application, and then route it back to the individual applications.
This is the node-reverse-proxy sample code:
var node_reverse_proxy = require('node-reverse-proxy');
var ip = '127.0.0.1';
var reverse_proxy = new node_reverse_proxy({
'first_host.com' : ip + ':8082',
'my.second_host.com' : ip + ':8081',
'my.second_host.com/page/' : ip + ':8080',
'' : ip + ':8080' // catch all other routes
});
reverse_proxy.start(80);
You might find that nginx better suits your needs, but personally, for a simple reverse proxy setup, I do prefer node-reverse-proxy.

Node.js+express proxy ssl

I'm trying to write a reverse proxy in node.js using express, and it works fine for http requests. The problem is that when requesting https it never responds, and the browser states that the proxy refused to connect.
Here is the working code for http requests:
var app = express(),
http=require('http');
app.configure(function(){ /* express stuff to log and use routes and the like */ });
http.createServer(app).listen(8000, function(){
console.log("Express server listening on port " + 8000);
});
app.all('*', proxy);
var request=require('request');
var proxy=function(req,resp){
var data={
url:req.url,
headers: {
'Connection': 'keep-alive'
}
}
var proxy=request(req.url);
proxy.pipe(resp);
}
Now, as for SSL, i am currently trying with:
var https=require('https'),
fs=require('fs');
https.createServer({
key: fs.readFileSync(__dirname+'/ssl/server.key', 'utf8'),
cert: fs.readFileSync(__dirname+'/ssl/server.crt', 'utf8')
},app).listen(8001, function(){
console.log("Express server listening on port " + 8001);
});
The proxy can be used from anywhere requiring 50.56.195.215:8000 for HTTP and 50.56.195.215:8001 for SSL. It has no security whasoever, so don't log in to anything important =D
I'm using a self signed SSL Certificate, and i guess it's kind of silly of me to try to do such a thing, but i don't have any ideas left :P
My suggestion is use the great existing library node-http-proxy from Nodejitsu. If you want to write your own, at least study their source code academically.
Some notes on your approach above:
You aren't handling HTTP methods other than GET (POST, PUT, DELETE, etc). These exist. You must handle them if you want your proxy to actually work. Every time you call request(req.url), request is making a GET request by default.
For HTTPS, you need to be able to handle HTTP Connects and also impersonate the destination server. You will need to have a Certificate for this.
You can try using this.
https://github.com/noeltimothy/noelsproxy
Copy the directory "magical" that contains a certificate as well as a key and then use noelsproxy. Remember to add the ca.pem to your trusted root store on your system.
If you are using windows, do this:
certutil -addstore -enterprise -f \"Root\" ./magical/ca.pem
Let me know if you have any issues. I'm willing to fix them immediately.

Resources