Force http:// to https:// in a sails.js App - javascript

I try to force my Sails.js WebApp which is hosted on heroku(no nginx installed) from http:// to https:// and use this express middleware in my sail.js app:
In Express it would look like this:
app.use(forceDomain({
hostname: 'www.example.com',
port: 4000,
protocol: 'https'
}));
I tried to use it in my config/http.js file in my sails.js app:
middleware: {
forceDomain: function (req, res, next) {
forceDomain({
hostname: 'www.myurl.com',
port: 4000,
protocol: 'https'
});
next();
},
order: [
'forceDomain',
...
}
I don't understand exactly how to use this "app.use()" thing in sails.js.
It is here explained, but I didn't really understand. What I now have doesn't work(no errors, but also no redirecting). How can I fix this?
Installed this module - doesn't work either.

Here is the solution how to force ssl on a sails.js app running on heroku without nginx and without external modules:
In the config/http.js file there is an example of custom middleware:
****************************************************************************
* Example custom middleware; logs each request to the console. *
****************************************************************************
myRequestLogger: function (req, res, next) {
console.log("Requested :: ", req.method, req.url);
next();
}
I made my own custom middleware function which controls if the request is secure, and if not, it redirects the request to https:// or if its a websocket request it redirects the request to wss://
order: [
...
'forceSSL',
...
],
forceSSL: function (req, res, next) {
if (req.isSocket) {
return res.redirect('wss://' + req.headers.host + req.url);
} else if (req.headers["x-forwarded-proto"] == "http") {
return res.redirect('https://' + req.headers.host + req.url);
} else {
next(); //it's already secure
}
}
No need for extern modules or hookups. just that function and it works.

Every value in the sails.config.http.middleware dictionary (besides order) should be an Express-style middleware function -- that is, a function that accepts req, res, and next, which is exactly what the forcedomain module returns. The issue in your code is that you're wrapping that function in another function instead of just returning it. Try:
middleware: {
forceDomain: forceDomain({
hostname: 'www.myurl.com',
port: 4000,
protocol: 'https'
}), // <-- the call to `forceDomain()` returns a configured Express middleware fn.
order: [
'forceDomain',
...
}
This assumes that you have var forceDomain = require('forcedomain') at the top of that file!

Related

Making a conditional app.use() with Node and Express?

I would like to be able to set an app.use() path depending on the domain my Node.JS server receives the request as to return one set of files or another. I have tried with the following code, but when testing the files are never returned to the client.
app.use('/scripts', (req, res) => {
if (req.host == `mysite.com`) {
express.static(path.resolve(__dirname, 'landing', 'frontend/scripts'));
} else if (req.host == `admin.mysite.com`) {
express.static(path.resolve(__dirname, 'admin', 'frontend/scripts'));
}
});
I am using express as a dependancy to try and do this, but no avail, I am willing to try other packages if this can help solve my issue.
Not tested, but I would assume you can keep a reference to each static route and then just forward the requests, don't forget next so that normal 404 can be handled.
eg.
const static1 = express.static(path.resolve(__dirname, 'landing', 'frontend/scripts'));
const static2 = express.static(path.resolve(__dirname, 'admin', 'frontend/scripts'));
app.use('/scripts', (req, res, next) => {
if (req.hostname == `mysite.com`) {
static1(req, res, next);
} else if (req.hostname == `admin.mysite.com`) {
static2(req, res, next);
} else res.end(`host: ${req.hostname} not found`);
});

Single port route to different services

My question is: is http-proxy, reverse-proxy.js, or any other library(with exception of a web-server like nginx) capable of routing all requests that comes to the port 80 to another services based on the url?
If a request comes at the port 80 with that url localhost:80/route1 I want to redirect it to the service at localhost:3001
If a request comes at the port 80 with that url localhost:80/another-route I want to redirect it to the service at localhost:3002. And so on..
To summarize it: I want to expose 1 port(80), and then route the request to other services based on the URL pattern from the request.
So far I tried this approach below using reverse-proxy.js but it only works if the port changes
{
"port": 80,
"routes": {
"localhost/test": "localhost:3001",
"localhost/another-route": "localhost:3002",
"localhost/another-route-same-service": "localhost:3002",
"*": 80
}
}
Yes of course you can. It's a very common requirement. In Node you can do it natively using streams. Here's a full working example using only the standard Node http library.
const http = require('http');
const server = http.createServer();
let routes = {
'/test': {
hostname: 'portquiz.net',
port: 80
}
}
function proxy(req, res){
if (!routes[req.url]){
res.statusCode = 404;
res.end();
return;
}
let options = {
...routes[req.url],
path: '', // if you want to maintain the path use req.url
method: req.method,
headers: req.headers
}
let proxy = http.request(options, function(r){
res.writeHead(r.statusCode, r.headers);
r.pipe(res, { end: true });
})
req.pipe(proxy, { end: true }).on('error', err => console.log(err))
}
server.on('request', proxy);
server.listen(8080);

How to do whitelist of IP's in Express?

I need to block every IP address from accessing my site except one or two IP's provided by myself. I have tried many modules but nothing seems to work.
var express = require('express')
var AccessControl = require('express-ip-access-control');
var app = express()
app.get('/', function (req, res) {
res.send('Hello World!')
})
var middleware = AccessControl(options);
app.use(AccessControl(options));
var options = {
mode: 'deny',
denys: [],
allows: ['**8.1**.1.**'],
forceConnectionAddress: false,
log: function(clientIp, access) {
console.log(clientIp + (access ? ' accessed.' : ' denied.'));
},
statusCode: 401,
redirectTo: '',
message: 'Unauthorized'
};
app.listen(3000, function () {
console.log(' app listening on port 3000!')
})
on running and accessing my site from my above code i am getting the console message as
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
::ffff:127.0.0.1 accessed.
any help?
You can simply add your own middleware that checks the IPs, no need to include another module.
You can see the ip from the request with req.connection.remoteAddress.
Before you define your routes, add something like this:
// Custom Middleware
app.use((req, res, next) => {
let validIps = ['::12', '127.0.0.1']; // Put your IP whitelist in this array
if(validIps.includes(req.connection.remoteAddress)){
// IP is ok, so go on
console.log("IP ok");
next();
}
else{
// Invalid ip
console.log("Bad IP: " + req.connection.remoteAddress);
const err = new Error("Bad IP: " + req.connection.remoteAddress);
next(err);
}
})
This will throw an error if an invalid ip comes in. Below all your routes, add something like this:
// Error handler
app.use((err, req, res, next) => {
console.log('Error handler', err);
res.status(err.status || 500);
res.send("Something broke");
});
You need to define your options before you use them. Otherwise, you're passing in undefined to app.use(AccessControl(options)).
Not sure how this is compiling for you, but adding the following line to the top of your script might help show a few more errors that would help.
'use strict';
Secondly, according to the express-ip-access-control documentation:
'allow' mode (Whilelist):
Deny by default, only allow IPs in the whitelist (allows) and not excluded by the blacklist (denys).
So change options.mode from 'deny' to 'allow'.

node.js and express file uploader

So I am following this tutorial: http://thejackalofjavascript.com/uploading-files-made-fun/
I have followed the steps all the way up to where they create the routes and haven't actually created any views. It says
Thats it we are all done with our server. Restart your server and
navigate to http://localhost:3000/upload. You should see a JSON
response with the empty array of files.
However when I try to run app.js it sits for a few seconds and then just goes back to the command prompt. No errors are given and I am clueless as to how to fix this.
Here is my code in routes/uploadManager.js
var options = {
tmpDir: __dirname + '/../public/uploaded/tmp',
uploadDir: __dirname + '/../public/uploaded/files',
uploadUrl: '/uploaded/files/',
maxPostSize: 11000000000, // 11 GB
minFileSize: 1,
maxFileSize: 10000000000, // 10 GB
acceptFileTypes: /.+/i,
// Files not matched by this regular expression force a download dialog,
// to prevent executing any scripts in the context of the service domain:
inlineFileTypes: /\.(gif|jpe?g|png)/i,
imageTypes: /\.(gif|jpe?g|png)/i,
imageVersions: {
width: 80,
height: 80
},
accessControl: {
allowOrigin: '*',
allowMethods: 'OPTIONS, HEAD, GET, POST, PUT, DELETE',
allowHeaders: 'Content-Type, Content-Range, Content-Disposition'
},
storage : {
type : 'local'
}
};
var uploader = require('blueimp-file-upload-expressjs')(options);
module.exports = function (router) {
router.get('/upload', function (req, res) {
uploader.get(req, res, function (obj) {
res.send(JSON.stringify(obj));
});
});
router.post('/upload', function (req, res) {
uploader.post(req, res, function (obj) {
res.send(JSON.stringify(obj));
});
});
router.delete('/uploaded/files/:name', function (req, res) {
uploader.delete(req, res, function (obj) {
res.send(JSON.stringify(obj));
});
});
return router;
}
I apologize. I was trying to run node app.js when I was supposed to be running node bin/www since this is an express.js app.

how to get request path with express req object

I'm using express + node.js and I have a req object, the request in the browser is /account but when I log req.path I get '/' --- not '/account'.
//auth required or redirect
app.use('/account', function(req, res, next) {
console.log(req.path);
if ( !req.session.user ) {
res.redirect('/login?ref='+req.path);
} else {
next();
}
});
req.path is / when it should be /account ??
After having a bit of a play myself, you should use:
console.log(req.originalUrl)
Here is an example expanded from the documentation, which nicely wraps all you need to know about accessing the paths/URLs in all cases with express:
app.use('/admin', function (req, res, next) { // GET 'http://www.example.com/admin/new?a=b'
console.dir(req.originalUrl) // '/admin/new?a=b' (WARNING: beware query string)
console.dir(req.baseUrl) // '/admin'
console.dir(req.path) // '/new'
console.dir(req.baseUrl + req.path) // '/admin/new' (full path without query string)
next()
})
Based on: https://expressjs.com/en/api.html#req.originalUrl
Conclusion: As c1moore's answer states, use:
var fullPath = req.baseUrl + req.path;
In some cases you should use:
req.path
This gives you the path, instead of the complete requested URL. For example, if you are only interested in which page the user requested and not all kinds of parameters the url:
/myurl.htm?allkinds&ofparameters=true
req.path will give you:
/myurl.html
UPDATE 8 YEARS LATER:
req.path was already doing exactly same thing that I mentioned here. I don't remember how this answer solved issue and accepted as a correct answer but currently it's not a valid answer. Please ignore this answer. Thanks #mhodges for mentioning this.
Original answer:
If you want to really get only "path" without querystring, you can use url library to parse and get only path part of url.
var url = require('url');
//auth required or redirect
app.use('/account', function(req, res, next) {
var path = url.parse(req.url).pathname;
if ( !req.session.user ) {
res.redirect('/login?ref='+path);
} else {
next();
}
});
This can produce different results when calling directly in base module i.e. main file (e.g. index.js or app.js) vs calling from inside module via app.use() middleware i.e. route file (e.g. routes/users.js).
API call:
http://localhost:8000/api/users/profile/123/summary?view=grid&leng=en
We'll be comparing our outputs against above API call
1) First, we'll see the result from inside module:
We'll be placing our user module inside routes directory, with one route
routes/users.js
const router = (require('express')).Router();
router.get('/profile/:id/:details', (req, res) => {
console.log(req.protocol); // http or https
console.log(req.hostname); // only hostname (abc.com, localhost, etc)
console.log(req.headers.host); // hostname with port number (if any)
console.log(req.header('host')); // <same as above>
console.log(req.route.path); // exact defined route
console.log(req.baseUrl); // base path or group prefix
console.log(req.path); // relative path except path
console.log(req.url); // relative path with query|search params
console.log(req.originalUrl); // baseURL + url
// Full URL
console.log(`${req.protocol}://${req.header('host')}${req.originalUrl}`);
res.sendStatus(200);
});
module.exports = router;
index.js
const app = (require('express'))();
const users = require('./routes/users');
app.use('/api/users', users);
const server = require('http').createServer(app);
server.listen(8000, () => console.log('server listening'));
Output
http ....................................................................................... [protocol]
localhost .............................................................................. [hostname]
localhost:8000 ..................................................................... [headers.host]
localhost:8000 ..................................................................... [header('host')]
/profile/:id/:details ........................................................ [route.path]
/api/users ............................................................................. [baseUrl]
/profile/123/summary .......................................................... [path]
/profile/123/summary?view=grid&leng=en ........................ [url]
/api/users/profile/123/summary?view=grid&leng=en ..... [originalUrl]
Full URL:
http://localhost:8000/api/users/profile/123/summary?view=grid&leng=en
2) Now, directly from main module:
We'll define our route right in the starting file (i.e. app.js or index.js)
index.js
const app = (require('express'))();
app.get('/api/users/profile/:id/:details', (req, res) => {
console.log(req.protocol); // http or https
console.log(req.hostname); // only hostname (abc.com, localhost, etc)
console.log(req.headers.host); // hostname with port number (if any)
console.log(req.header('host')); // <same as above>
console.log(req.route.path); // exact defined route
console.log(req.baseUrl); // base path or group prefix
console.log(req.path); // relative path except path
console.log(req.url); // relative path with query|search params
console.log(req.originalUrl); // baseURL + url
// Full URL
console.log(`${req.protocol}://${req.header('host')}${req.originalUrl}`);
res.sendStatus(200);
});
const server = require('http').createServer(app);
server.listen(8000, () => console.log('server listening'));
Output
http ........................................................................ [protocol]
localhost ............................................................... [hostname]
localhost:8000 ...................................................... [headers.host]
localhost:8000 ...................................................... [header('host')]
/profile/:id/:details ......................................... [route.path]
.............................................................................. [baseUrl]
/profile/123/summary ........................................... [path]
/profile/123/summary?view=grid&leng=en ......... [url]
/profile/123/summary?view=grid&leng=en ......... [originalUrl]
Full URL:
http://localhost:8000/api/users/profile/123/summary?view=grid&leng=en
We can clearly see in above output that the only difference is of baseUrl which is empty string here. So, the originalUrl also changes & looks same as the url
//auth required or redirect
app.use('/account', function(req, res, next) {
console.log(req.path);
if ( !req.session.user ) {
res.redirect('/login?ref='+req.path);
} else {
next();
}
});
req.path is / when it should be /account ??
The reason for this is that Express subtracts the path your handler function is mounted on, which is '/account' in this case.
Why do they do this?
Because it makes it easier to reuse the handler function. You can make a handler function that does different things for req.path === '/' and req.path === '/goodbye' for example:
function sendGreeting(req, res, next) {
res.send(req.path == '/goodbye' ? 'Farewell!' : 'Hello there!')
}
Then you can mount it to multiple endpoints:
app.use('/world', sendGreeting)
app.use('/aliens', sendGreeting)
Giving:
/world ==> Hello there!
/world/goodbye ==> Farewell!
/aliens ==> Hello there!
/aliens/goodbye ==> Farewell!
It should be:
req.url
express 3.1.x
For version 4.x you can now use the req.baseUrl in addition to req.path to get the full path. For example, the OP would now do something like:
//auth required or redirect
app.use('/account', function(req, res, next) {
console.log(req.baseUrl + req.path); // => /account
if(!req.session.user) {
res.redirect('/login?ref=' + encodeURIComponent(req.baseUrl + req.path)); // => /login?ref=%2Faccount
} else {
next();
}
});
req.route.path is working for me
var pool = require('../db');
module.exports.get_plants = function(req, res) {
// to run a query we can acquire a client from the pool,
// run a query on the client, and then return the client to the pool
pool.connect(function(err, client, done) {
if (err) {
return console.error('error fetching client from pool', err);
}
client.query('SELECT * FROM plants', function(err, result) {
//call `done()` to release the client back to the pool
done();
if (err) {
return console.error('error running query', err);
}
console.log('A call to route: %s', req.route.path + '\nRequest type: ' + req.method.toLowerCase());
res.json(result);
});
});
};
after executing I see the following in the console and I get perfect result
in my browser.
Express server listening on port 3000 in development mode
A call to route: /plants
Request type: get
For those getting undefined from req.route.path that is correct.
Inside route handler, there's a route.
Inside middleware handlers, there's no route.
When using a middleware in express, your request object has several properties you can use to get the correct path:
req.baseUrl: /api/account
req.originalUrl: /api/account
req._parsedUrl.path: /account
req._parsedUrl.pathname: /account
req._parsedUrl.href: /account
req._parsedUrl._raw: /account
PLEASE NOTE: This applies to middlewares

Categories