Using https on heroku - ssl

I'm trying to get my app on heroku to be 'https everywhere'. So far the app is like this:
"use strict";
console.log('working');
//Initial setup
var path, https, privateKey, certificate, port, cdjshelp, util, cookies, oauth, twitter, crypto, _, options, express, auth, lodash, dust, dustjs,
dustjsHelpers, commonDustjsHelpers, app, db, fs, mongoose, mongooseTimes, Comment, Bird, Sighting, Site, User,
Backbone, io;
//node modules, express and dust declarations
path = require('path');
util = require('util');
fs = require('fs');
https = require('https');
privateKey = fs.readFileSync('./config/privatekey.pem').toString();
certificate = fs.readFileSync('./config/certificate.pem').toString();
crypto = require('crypto');
//APP Defn...
app = require('./config/appSetup')(dustjs);
//******** SERVER CONFIG **********//
var port = process.env['PORT'] = process.env.PORT || 4000; // Used by https on localhost
options = {
key: privateKey,
cert: certificate
}
https.createServer(options, app).listen(port, function() {
console.log("Express server listening with https on port %d in %s mode", this.address().port, app.settings.env);
});
I've used the openSSL CLI to generate a privatekey.pem and a certificate.pem and loaded them as options.
I know that heroku has a procedure if you're using DNS records to have the app serve to your own domain. I know that you have to go through the procedure listed here. I'm not remapping any urls or altering any records - my url is birdsapp.heroku.com.
Heroku uses piggyback SSL, so if you setup an http server your app will respond to https requests without any additional config. The problem there is that the http routes are still available, so I've stuck to setting an https server only - but it's timing out with nothing in the logs, so I think that there's a problem with the SSL setup.
Is the above setup correct? Is that the best way to do basic https server on heroku?

OK, it's actually much simpler than that...
You simply create an http server:
//******** SERVER CONFIG **********//
var port = process.env['PORT'] = process.env.PORT || 4000;
http.createServer(app).listen(port, function() {
console.log("Express server listening with http on port %d in %s mode", this.address().port, app.settings.env);
});
and add a route redirect:
app.all('*', function(req, res, next) {
if (req.headers['x-forwarded-proto'] != 'https')
res.redirect('https://' + req.headers.host + req.url)
else
next() /* Continue to other routes if we're not redirecting */
});
heroku takes care of the rest, setting up an http server which is a mirror of your http server and uses their certs, etc.

Related

Sending a self-signed certificate from proxy secure websocket to a secure websocket connection(wss)

I am trying to connect to wss(proxy) with self-signed certificate using wscat and browser but it giving me errors.
https running on 8443 with certificate cert.pem
proxy running on 8080 with secure true
Things I have tried to make sure my secure server is running properly.
I can reach https://localhost:8443 and receive "hello from a secure world"
I can connect to wss://localhost:8443 with wscat wscat -c wss://localhost:8443 --ca cert.pem and it works
Errors I get:
I cannot reach the proxy https://localhost:8080 from browser. I get This site can’t provide a secure connection and 500 status code
I cannot connect to wss://localhost:8080 with wscat -c wss://localhost:8080 --ca cert.pem I get error: write EPROTO 140266887743360:error:1408F10B:SSL routines:ssl3_get_record:wrong version number:../deps/openssl/openssl/ssl/record/ssl3_record.c:332:
What I think the issue is that my proxy server is unable to take the cert.pem and pass it to the https server. I have looked everywhere but I can't find how to connect to wss(proxy) with a self-signed certificate. I can't supress the
/server
const app = express()
app.use('/', function (req, res) {
res.writeHead(200);
res.end("hello from a secure world\n");
})
export const server = https.createServer({
cert: fs.readFileSync(path.resolve(__dirname, 'cert.pem'), 'utf-8'),
ca: fs.readFileSync(path.resolve(__dirname, 'cert.pem'), 'utf-8'),
key: fs.readFileSync(path.resolve(__dirname, 'server.key'), 'utf-8')
}, app)
const wss = new WebSocket.Server({ server });
wss.on('connection', function connection(ws) {
console.log("connected");
ws.on('message', function incoming(message) {
console.log('received: %s', message);
ws.send('hello from server!, the time is: ' + timestamp());
});
});
/Proxy
const wsProxy = createProxyMiddleware('/', {
target: `https://localhost:8443`,
changeOrigin: true,
secure: true,
ws: true,
ssl: {
cert: fs.readFileSync(path.resolve(__dirname, 'cert.pem')),
}
});
const app = express();
app.use(wsProxy);
const proxy = app.listen(8080)
proxy.on('upgrade', wsProxy.upgrade); // <-- subscribe to http 'upgrade'
Okay, it turned out that I was missing something crucial there. There wasn't really a "proxy websocket" I was confusing https proxy with websocket proxy. Once I made sense of that it solved my problem. I had to create a websocket with using https server(with cert and key) then I could just connect to the wss with the same cert and key :)

socketIO over SSL on Smartphone Browser

I have an Apache webserver with a valid SSL certificate. It runs my web application on it. Let's call it Server A.
Then I have a second server running a Node-Js server with a valid SSL certificate. There also socket.IO runs. And this one we call Server B.
A client requests the web application at server A and gets the desired page displayed. If the page is set up at the client, a connection to server B is established via websockets. If another client should change something on the page, it will be adapted for all currently connected clients.
Websockets work as desired. As long as the page is accessed via a computer browser.
If I now go to the website with my smartphone (Iphone 7) via Safari or Chrome (WLAN), no connection to the websocket server (Server B) is established.
Then I set up a small websocket example on http without encryption.
There the websockets work on the smartphone browser.
I hope I could describe my problem understandably. I am very grateful for hints, examples or similar.
// This script run on my Server
const fs = require('fs');
const server = require('https').createServer({
key: fs.readFileSync('myserver.key', 'utf8'),
cert: fs.readFileSync('myserver.cer', 'utf8'),
passphrase: ''
});
let io = require('socket.io')(server);
server.listen(3003);
io.on('connection', function (socket) {
console.log("User Connected connect " + socket.id);
socket.on('disconnect', function () {
console.log("User has close the browser " + socket.id);
});
socket.on('feedback', function (data) {
io.sockets.emit('feedback', data);
});
});
// On Clientsite
socket = io.connect('wss://adressOfServer:3003', {
// secure: true,
transports: ['websocket'],
upgrade: false,
rejectUnauthorized: false
//Here I have already tried many combinations
});
socket.on('connect_error', function (error) {
// alert(error);
});

Express 4 middleware not calling routes on DigitalOcean server

I'm messing around with creating an API with io.js and Express 4, and I have no idea why this isn't working. I am currently running the program on a DigitalOcean droplet (Ubuntu 14.04) and it is not calling the next() method never gets called/executed. The program is being routed to by a reverse proxy with nginx at https://<redacted>/asdf.
var express = require('express');
var app = express();
var port = process.env.PORT || 3000;
var router = express.Router();
router.use(function(req, res, next) {
console.log("Request received.");
next();
});
router.post('/login', function(req, res) {
console.log('Route /login accessed');
});
app.use('/', router);
app.listen(port);
console.log("Server started on port " + port + ".");
When I run the program on my droplet and send a POST request to https://<redacted>/asdf/login, the console prints out "Request received" but does not print out "Route /login accessed". The odd thing is that this works perfectly fine on my local machine when a post request is sent to http://localhost:3000/login. Is there something I am doing wrong or is this a known thing that I am not aware of?
Express uses the request's url property when mapping routes, and I suspect that your nginx reverse proxy isn't removing the /asdf root from it. If so, your url's path would be /asdf/login which would explain why your /login post handler isn't being invoked. To test this hypothesis you could try adding the reverse proxy root to your use like this:
app.use('/asdf', router);
If this is the case, to fix this problem, you can configure nginx to rewrite the url for you like this
location /asdf {
rewrite /asdf(.*) $1 break;
proxy_pass http://localhost:3200;
proxy_redirect off;
proxy_set_header Host $host;
}
More details:
https://serverfault.com/questions/379675/nginx-reverse-proxy-url-rewrite
http://wiki.nginx.org/HttpRewriteModule#rewrite

Node express server, CORS API restriction, including an entry in my development machine’s hosts file

I am trying to use an API that has an API CORS policy that does not support browser requests from any domain. In order to allow clientside JavaScript code to access the API, whilst developing my application, I have been advised to I serve my webapp from '*.thisCompany.com' domain.
It was advised to include an entry in my development machine’s hosts file, as follows, which I have done:
$ echo '127.0.0.1 localhost.thisCompany.com' >> /etc/hosts
Following this command when I run sudo nano /private/etc/hosts
this is the screen that I see.
Host Database
localhost is used to configure the loopback interface
when the system is booting. Do not change this entry.
127.0.0.1 localhost
127.0.0.1 localhost.thisCompany.com
And then I have been told that I should be able access my webapp at http://localhost.thisCompany.com.
I am using node express as my server and the code in my server.js file looks like this
var express = require('express');
var server = express();
var path = require('path');
var port = process.env.PORT || 'thisCompany.com';
server.use(express.static(__dirname + '/public'));
server.use('/bower_components', express.static(__dirname + '/bower_components'));
server.get('/', function(request, response) {
response.sendFile(path.join(__dirname + '/views/index.html'));
});
server.listen(port, function() {
console.log("Node app is running at localhost:" + port)
});
Can anyone advise what steps I should follow to enable me to call this API and bypass the API CORS policy?
I have read various other posts here, and also other articles online, however I cannot find the solution. Really hoping someone on this can help.
Thanks, Paul
I misunderstood how I was supposed to view a page locally on my computer after amending the hosts file on my local machine. I didn't need to add anything to my express server. The express server code remained as follows:
var express = require('express');
var server = express();
var path = require('path');
var port = process.env.PORT || 3000;
server.use(express.static(__dirname + '/public'));
server.use('/bower_components', express.static(__dirname + '/bower_components'));
server.get('/', function(request, response) {
response.sendFile(path.join(__dirname + '/views/index.html'));
});
server.listen(port, function() {
console.log("Node app is running at localhost:" + port)
});
After adding the line mentioned in my original post to my hosts file on my local machine, I then needed to launch my server and access the page by following this link.
http://localhost.thisCompany.com:3000/
Although this is quite a niche issue, I hope this post helps someone in the future.

Node.js proxy for ws.audioscrobbler.com responds with 301 to www.last.fm

I’m trying to use Node.js to set up a proxy to Last.fm’s webservices. The problem is that every request to ws.audioscrobbler.com gets rewritten to www.last.fm. So for example $ curl http://localhost:8000/_api/test123 sends a 301 Moved Permanently to http://www.last.fm/test123.
var express = require('express'),
httpProxy = require('http-proxy');
// proxy server
var lastfmProxy = httpProxy.createServer(80, 'ws.audioscrobbler.com');
// target server
var app = express.createServer();
app.configure(function() {
app.use('/_api', lastfmProxy);
});
app.listen(8000);
At the same time $ curl http://ws.audioscrobbler.com/test123 returns a regular 404 Not Found. I’m not exactly sure what I’m missing here, or if I’m approaching this completely the wrong way.
The reason you get a 301 Moved Permanently is that ws.audioscrobbler.com gets an HTTP request with the hostname "localhost".
One solution is to let the proxy rewrite the hostname to "ws.audioscrobbler.com" before passing it on to the remote server:
var httpProxy = require('http-proxy');
var lastfmProxy = httpProxy.createServer(function (req, res, proxy) {
req.headers.host = 'ws.audioscrobbler.com';
proxy.proxyRequest(req, res, {
host: 'ws.audioscrobbler.com',
port: 80,
});
}).listen(8000);