diff --git a/README.md b/README.md index a5c579f..524b5e3 100644 --- a/README.md +++ b/README.md @@ -2,18 +2,57 @@ Redirect from HTTP to HTTPS using meta redirects +## Installation and Usage + ```bash npm install --save redirect-https ``` +```js +'use strict'; + +var express = require('express'); +var app = express(); + +app.use('/', require('redirect-https')({ + body: '' +})); + +module.exports = app; +``` + +## Options + +``` +{ port: 443 // defaults to 443 +, body: '' // defaults to an html comment to use https +, trustProxy: true // useful if you haven't set this option in express +} +``` + +* This module will call `next()` if the connection is already tls / https. +* If `trustProxy` is true, and `X-Forward-Proto` is https, `next()` will be called. +* If you use `{{URL}}` in the body text it will be replaced with the url + +## Demo + ```javascript +'use strict'; + var http = require('http'); var server = http.createServer(); +var securePort = 8443; +var insecurePort = process.argv[2] || 8080; server.on('request', require('redirect-https')({ - port: 443 + port: securePort , body: '' +, trustProxy: true // default is false })); + +server.listen(insecurePort, function () { + console.log('Listening on http://localhost.daplie.com:' + server.address().port); +}); ``` # Why meta redirects? @@ -33,3 +72,12 @@ Using a meta redirect will break requests from `curl` and api calls from a progr # Other strategies If your application is properly separated between static assets and api, then it would probably be more beneficial to return a 200 OK with an error message inside + +# Security + +The incoming URL is already URI encoded by the browser but, just in case, I run an html escape on it +so that no malicious links of this sort will yield unexpected behavior: + + * `http://localhost.daplie.com:8080/">` + * `http://localhost.daplie.com:8080/';URL=http://example.com` + * `http://localhost.daplie.com:8080/;URL=http://example.com` diff --git a/example.js b/example.js new file mode 100644 index 0000000..3d22765 --- /dev/null +++ b/example.js @@ -0,0 +1,15 @@ +'use strict'; + +var http = require('http'); +var server = http.createServer(); +var port = process.argv[2] || 8080; + +server.on('request', require('./')({ + port: 8443 +, body: '{{URL}}' +, trustProxy: true // default is false +})); + +server.listen(port, function () { + console.log('Listening on http://localhost.daplie.com:' + server.address().port); +}); diff --git a/index.js b/index.js new file mode 100644 index 0000000..4259b0b --- /dev/null +++ b/index.js @@ -0,0 +1,52 @@ +'use strict'; + +module.exports = function (opts) { + var escapeHtml = require('escape-html'); + + if (!opts) { + opts = {}; + } + if (isNaN(opts.port)) { + opts.port = 443; + } + if (!('body' in opts)) { + opts.body = ""; + } + opts.body = opts.body.replace(/{{\s+PORT\s+}}/i, opts.port); + + return function (req, res, next) { + if (req.connection.encrypted + || 'https' === req.protocol + || (opts.trustProxy && 'https' === req.headers['x-forwarded-proto']) + ) { + next(); + return; + } + + var url = req.url; + var host = req.headers.host || ''; + var newLocation = 'https://' + + host.replace(/:\d+/, ':' + opts.port) + url + ; + //var encodedLocation = encodeURI(newLocation); + var escapedLocation = escapeHtml(newLocation); + var body = opts.body + .replace(/{{\s*URL\s*}}/ig, escapedLocation) + .replace(/{{\s*UNSAFE_URL\s*}}/ig, newLocation) + ; + + var metaRedirect = '' + + '\n' + + '
\n' + //+ ' \n' + + ' \n' + + '\n' + + '\n' + body + '\n\n' + + '\n' + ; + + res.setHeader('Content-Type', 'text/html; charset=utf-8'); + res.end(metaRedirect); + }; +}; diff --git a/package.json b/package.json new file mode 100644 index 0000000..7c9fcdd --- /dev/null +++ b/package.json @@ -0,0 +1,31 @@ +{ + "name": "redirect-https", + "version": "1.0.0", + "description": "Redirect from HTTP to HTTPS using meta redirects", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/Daplie/node-redirect-https.git" + }, + "keywords": [ + "https", + "http", + "redirect", + "force", + "upgrade", + "location", + "meta" + ], + "author": "AJ ONeal