Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Express won't serve static ejs files in vhosts

The closest I've been able to get is it will have the client download them. It will download the correct ejs files.

It's driving me crazy because I feel like it should work but it will not. If I put html files in there they serve just fine. It's a little messy because I've been trying all sorts of things.

var application_root = __dirname;
var express = require('express');
var vhost = require( 'vhost' );
var https = require('https');
var http = require('http');
var fs = require('fs');
var path = require("path");
var forceSSL = require('express-force-ssl');
//do something
var app = express();
var credentials = {};

var config = require('./config.json')[process.env.NODE_ENV || 'dev'];

//Use ejs?
app.set('view engine', 'ejs');
app.engine('html', require('ejs').renderFile);

//Ensure all are going to www.
app.all(/.*/, function(req, res, next) {
  var host = req.header("host");
  if (host.match(/^www\..*/i)) {
    next();
  } else {
    res.redirect(301, "http://www." + host);
  }
});

//Use the virtual hosts
app.use(vhost('*.seq.agency',express.static(path.join(__dirname + '/seq.agency'), {
  extensions: ['ejs'],
  index: 'index.ejs'
})));

app.get('/', function (req, res) {
  res.send('vhosts didn\'t catch this!')
});

var httpServer = http.createServer(app);
if(config.name == "prod"){
    /*var options = {
         key: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/privkey.pem'),
         cert: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/fullchain.pem'),
         ca: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/chain.pem')
    }*/
    console.log('starting on 443');
    //var httpsServer = https.createServer(options, app);
    //httpsServer.listen(443);
    //httpServer.listen(80);
    //app.use(forceSSL);
}

console.log('['+config.name+'] starting on port',config.port);
httpServer.listen(config.port);
like image 443
Z2VvZ3Vp Avatar asked Feb 16 '18 02:02

Z2VvZ3Vp


1 Answers

The issue is that you are considering that static files are rendered. Static file as the name suggest is static and there is no dynamic behavior and template rendering needed for the same

That is why below code cannot work

app.use(vhost('*.seq.agency',express.static(path.join(__dirname + '/seq.agency'), {
  extensions: ['ejs'],
  index: 'index.ejs'
})));

As you are asking it to serve files as it is with no processing. So I modified your code a bit to show you an example how you could work something out on this

var application_root = __dirname;
var express = require('express');
var vhost = require( 'vhost' );
var https = require('https');
var http = require('http');
var fs = require('fs');
var path = require("path");
var forceSSL = require('express-force-ssl');
//do something
var app = express();
var credentials = {};

var config = require('./config.json')[process.env.NODE_ENV || 'dev'];

//Use ejs?
ejs = require("ejs");
app.set('view engine', 'html');
app.engine('html', ejs.renderFile);
app.engine('ejs', ejs.renderFile);

//Ensure all are going to www.
app.all(/.*/, function(req, res, next) {
    var host = req.header("host");
    if (host.match(/^www\..*/i)) {
        next();
    } else {
        res.redirect(301, "http://www." + host);
    }
});

//Use the virtual hosts
app.use(vhost('*.seq.agency',function (req, res, next)
{
    const reqPath = req.path;
    const paths =
        [
            reqPath + ".html",
            reqPath + "index.html",
            reqPath
        ]

    for (file of paths) {
        try {
            let checkPath = path.join(__dirname,"seq.agency", file);
            if (!fs.existsSync(checkPath))
                continue;

            let stat = fs.statSync(checkPath);
            if (stat && stat.isFile())
            {
                res.render(checkPath);
                return;
            }
        } finally {

        }
    }

    console.log(file);
}));

app.get('/', function (req, res) {
    res.send('vhosts didn\'t catch this!')
});

var httpServer = http.createServer(app);
if(config.name == "prod"){
    /*var options = {
         key: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/privkey.pem'),
         cert: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/fullchain.pem'),
         ca: fs.readFileSync('/etc/letsencrypt/live/kaleidoscope.wtf/chain.pem')
    }*/
    console.log('starting on 443');
    //var httpsServer = https.createServer(options, app);
    //httpsServer.listen(443);
    //httpServer.listen(80);
    //app.use(forceSSL);
}

console.log('['+config.name+'] starting on port',config.port);
httpServer.listen(config.port);

So the key is that we check a path in below order

reqPath + ".html",
reqPath + "index.html",
reqPath

And then if it exists then we render that in response. This is no way a production use code as it allows you to directory traversal attack, but this is to give you an idea of what you are doing wrong and how you should handle it

Working

like image 103
Tarun Lalwani Avatar answered Sep 18 '22 17:09

Tarun Lalwani