1

Hi I am having a problem to https every single view in NodeJS. Currently I am using Handlebars as server side templating. To render a view, for example, res.render(loginDir, {login: false, admin: false, header: "Welcome!!"}); Every route I access is http://blablabla. I want it to be https://blablabla. Please help me with this...thanks in advance

The following will be my code:

Uiroutes.ts

import express = require('express');
import path = require('path');

var app = express();

class Uiroutes {

    get uiroutes() {

        var rootManageDir = path.join(__dirname,'../../../client/management/manage');
        var rootExecutionDir = path.join(__dirname,'../../../client/execution/execution');
        var rootUserHomeDir = path.join(__dirname,'../../../client/userhome/userhome');
        var loginDir = path.join(__dirname,'../../../client/login/login');



        app.get('/management',this.adminAuth, (req: express.Request, res: express.Response) => {
            res.render(rootManageDir, {login: true, admin: true, header: "Admin, Welcome back!"});
        });
        app.get('/execution',this.adminAuth, (req: express.Request, res: express.Response) => {
            res.render(rootExecutionDir, {login: true, admin: true, header: "Admin, Welcome back!"});
        });
        app.get('/userhome', this.userAuth, (req: express.Request, res: express.Response) => {
            let header = req.body.username + ', Welcome back!';
            res.render(rootUserHomeDir, {login: true, admin: false, header: header});
        });
        app.get('/login', (req: express.Request, res: express.Response) => {
            res.render(loginDir, {login: false, admin: false, header: "Welcome!!"});
        });
        app.get('/logout', this.logout, (req: express.Request, res: express.Response) => {
            res.redirect('/login');
        });
        return app;
    }

    userAuth(req, res, next) {
        if(req.session["user"]&&(req.session["user"].role == 'user')) {
            req.body.username = req.session["user"].username;
            next(); 
        } else {
            if(req.session["user"]&&(req.session["user"].role == 'admin')) {
                req.body.username = req.session["user"].username;
                res.redirect('/management');
            } else {
                res.redirect('/login');
            }
        }
    }

    adminAuth(req, res, next) {
        //console.log(req.session);
        if(req.session["user"]&&(req.session["user"].role == 'admin')) {
            req.body.username = req.session["user"].username;
            next();
        } else {
            if(req.session["user"]&&(req.session["user"].role == 'user')) {
                req.body.username = req.session["user"].username;
                res.redirect('/userhome');
            } else {
                res.redirect('/login');
            }
        }
    }

    logout(req, res, next) {
        if(req.session["user"]){
            console.log("logged in");
            delete req.session["user"];
            console.log(req.session["user"]);
            next();
        } else {
            delete req.session;
            next();
        }

    }
}
export = Uiroutes;

The above vars just for file to refer to .hbs view directory.

var rootManageDir = path.join(__dirname,'../../../client/management/manage');
var rootExecutionDir = path.join(__dirname,'../../../client/execution/execution');
var rootUserHomeDir = path.join(__dirname,'../../../client/userhome/userhome');
var loginDir = path.join(__dirname,'../../../client/login/login');

In my server.ts

//Set view engine
app.set('view engine', 'hbs');

var defaultDir = path.join(__dirname, '../client/layout/default');
var layoutDir = path.join(__dirname, '../client/layout');
var viewpath = path.join(__dirname, '../client')

//Config the view engine
app.engine('hbs', hbs.express4({
    defaultLayout: defaultDir,
    layoutsDir: layoutDir
}));

//config view path
app.set('views', viewpath);

app.use(new UIRoutes().uiroutes);

Edit:

The following is cert config on server side in order to use https

In server.ts

const fs = require('fs');
var app = require('../server').app;
const https = require('https');
var ip = '0.0.0.0';
var port = 8443;
var privateKey = fs.readFileSync('/opt/epaas/certs/key');
var certificate = fs.readFileSync('/opt/epaas/certs/cert');
var ca = fs.readFileSync('/opt/epaas/certs/ca');
var pass = fs.readFileSync('/opt/epaas/certs/pass','ascii');
var options = { 
    key: privateKey,
    cert: certificate,
    ca: ca,
    passphrase: pass,
    requestCert: true, 
    rejectUnauthorized: false 
};
var server = https.createServer(options, app);
server.listen(port, function(){
    console.log('This app is listening on port:' + port);
});

Our server is a cloud, all applications are deploy there. It is hard to tell what kind of server is that...

Mathers
  • 184
  • 9
  • Do you have a certificate for your domain? I am asking just in case.. It is best to keep HTTPS out of your node app and use a reverse proxy like NGINX to handle domain routing and https. I'll write a more detailed answer, but it would be easier if you told us first what server/service you are using (DigitalOcean+Ubuntu/Azure/Heroku...). – Erik Cupal Apr 21 '17 at 19:26
  • @Erik Cupal They are using certificate on server side. I will paste the certs config. Please see edit. – Mathers Apr 22 '17 at 16:34
  • @Erik Cupal Our server is a cloud platform, all applications are deployed there. So it is hard to tell what kind of server is that... – Mathers Apr 22 '17 at 16:44

2 Answers2

0

You can try to use a redirect of all routes HTTP to HTTPS.

Add a line before all the routes with:

app.get('*', (req, res, next) => {
   if(req.headers['x-forwarded-proto'] !== 'https') {
     res.redirect('https://' + req.headers.host + req.url);
   }
   next();
});

Is a check to look the header if the request is http and if is http do you redirect the user to https.

Willian Sabião
  • 134
  • 1
  • 6
  • Thanks for your solution. But where shall I insert this code snippet? – Mathers Apr 21 '17 at 18:43
  • Works fine, Mathers? – Willian Sabião Apr 21 '17 at 20:34
  • It indeed redirect me to the https urls but I cannot access the views – Mathers Apr 21 '17 at 20:48
  • I am going to test it on our dev server and see...It may work there :) – Mathers Apr 21 '17 at 20:53
  • It is not completely working for my case... everytime I switch to another route by `res.render(...)` it became http. But if I go to address bar and hit enter, it will redirect me to https... – Mathers Apr 21 '17 at 23:35
  • Do you using some lib on client side as angular/react? – Willian Sabião Apr 21 '17 at 23:39
  • Yes. I used angluar2 on client side. That causes the problems? – Mathers Apr 22 '17 at 16:29
  • Yes, is because of that. The angular manipulate the browser history, so your requests are be manipulated via javascript and never go back to the server when the user access another URL on your application. The solution on express is working only to the first access, where the user accesses the server. So to fix the angular routes too, you must read this question: http://stackoverflow.com/questions/38334894/angular-2-always-redirect-to-https-instead-of-using-http Is a solution to angular routes to force https. – Willian Sabião Apr 22 '17 at 17:07
  • That doesn't work for my case. I did not use Angular2 to redirect the route. I am using Handlebars to redirect – Mathers Apr 22 '17 at 18:57
  • Hello Mathers, try to read this articles: http://stackoverflow.com/questions/22689543/forcing-a-specific-page-to-use-https-with-angularjs and https://blog.meteor.com/ssl-support-handlebars-extensions-133183043550 Maybe it will help you with force SSL in handlebars. – Willian Sabião Apr 23 '17 at 23:35
  • Thanks Willian! I got the problem. Your solution is valid. I was forcing the app to redirect to http in my `service.ts`....So dumb :( – Mathers Apr 24 '17 at 21:38
0

You can use express-enforces-ssl which will handle this for you:

const fs = require('fs');
const https = require('https');
const http = require('http');
const express = require('express');
const express_enforces_ssl = require('express-enforces-ssl');

const app = express();

/*
*   Trust proxy must be set if you're behind a reverse proxy / load balancer
*
*/
app.enable('trust proxy');

app.use(express_enforces_ssl());


/*
*   Then you have to make sure your express server can handle https               
*/

http.createServer(app).listen(80);

https.createServer({
    key: fs.readFileSync('key.pem'),
    cert: fs.readFileSync('cert.pem')
}, app).listen(443);
Marcos Casagrande
  • 37,983
  • 8
  • 84
  • 98