Compare commits
	
		
			No commits in common. "c10a310c20f0db1cc453b64183aa65dc517b6b3c" and "7375a550eb936814a17f1db154a315579b28afad" have entirely different histories.
		
	
	
		
			c10a310c20
			...
			7375a550eb
		
	
		
							
								
								
									
										97
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										97
									
								
								README.md
									
									
									
									
									
								
							| @ -2,11 +2,11 @@ | |||||||
| 
 | 
 | ||||||
| Secure-by-default redirects from HTTP to HTTPS. | Secure-by-default redirects from HTTP to HTTPS. | ||||||
| 
 | 
 | ||||||
| -   Browsers get a 301 + Location redirect | * Browsers get a 301 + Location redirect | ||||||
| -   Only developers, bots, and APIs see security warning (advising to use HTTPS) | * Only developers, bots, and APIs see security warning (advising to use HTTPS) | ||||||
| -   Always uses meta redirect as a fallback, for everyone | * Always uses meta redirect as a fallback, for everyone | ||||||
| -   '/' always gets a 301 (for `curl | bash` installers) | * '/' always gets a 301 (for `curl | bash` installers) | ||||||
| -   minimally configurable, don't get fancy | * minimally configurable, don't get fancy | ||||||
| 
 | 
 | ||||||
| See <https://coolaj86.com/articles/secure-your-redirects/> | See <https://coolaj86.com/articles/secure-your-redirects/> | ||||||
| 
 | 
 | ||||||
| @ -17,16 +17,14 @@ npm install --save redirect-https | |||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| "use strict"; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| var express = require("express"); | var express = require('express'); | ||||||
| var app = express(); | var app = express(); | ||||||
| 
 | 
 | ||||||
| var redirector = require("redirect-https")({ | app.use('/', require('redirect-https')({ | ||||||
|     body: "<!-- Hello Developer! Please use HTTPS instead: {{ URL }} -->" |   body: '<!-- Hello Mr Developer! Please use HTTPS instead -->' | ||||||
| }); | })); | ||||||
| 
 |  | ||||||
| app.use("/", redirector); |  | ||||||
| 
 | 
 | ||||||
| module.exports = app; | module.exports = app; | ||||||
| ``` | ``` | ||||||
| @ -42,37 +40,10 @@ module.exports = app; | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| -   This module will call `next()` if the connection is already tls / https. | * 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 `trustProxy` is true, and `X-Forward-Proto` is https, `next()` will be called. | ||||||
| -   `{{ URL }}` in the body text will be replaced with a URI encoded and HTML escaped url (it'll look just like it is) | * If you use `{{URL}}` in the body text it will be replaced with a URI encoded and HTML escaped url (it'll look just like it is) | ||||||
| -   `{{ HTML_URL }}` in the body text will be replaced with a URI decoded and HTML escaped url (it'll look just like it would in Chrome's URL bar) | * If you use `{{HTML_URL}}` in the body text it will be replaced with a URI decoded and HTML escaped url (it'll look just like it would in Chrome's URL bar) | ||||||
| -   `{{ UNSAFE_URL }}` is the raw, original url |  | ||||||
| 
 |  | ||||||
| ## Demo |  | ||||||
| 
 |  | ||||||
| ```javascript |  | ||||||
| "use strict"; |  | ||||||
| 
 |  | ||||||
| var http = require("http"); |  | ||||||
| var server = http.createServer(); |  | ||||||
| var securePort = process.argv[2] || 8443; |  | ||||||
| var insecurePort = process.argv[3] || 8080; |  | ||||||
| 
 |  | ||||||
| var redirector = require("redirect-https")({ |  | ||||||
|     port: securePort, |  | ||||||
|     body: "<!-- Hello! Please use HTTPS instead: {{ URL }} -->", |  | ||||||
|     trustProxy: true // default is false |  | ||||||
| }); |  | ||||||
| 
 |  | ||||||
| server.on("request", redirector); |  | ||||||
| 
 |  | ||||||
| server.listen(insecurePort, function () { |  | ||||||
|     console.log( |  | ||||||
|         "Listening on http://localhost.rootprojects.org:" + |  | ||||||
|             server.address().port |  | ||||||
|     ); |  | ||||||
| }); |  | ||||||
| ``` |  | ||||||
| 
 | 
 | ||||||
| ## Advanced Options | ## Advanced Options | ||||||
| 
 | 
 | ||||||
| @ -80,16 +51,40 @@ For the sake of `curl | bash` installers and the like there is also the option t | |||||||
| to get a certain redirect for an exact path match: | to get a certain redirect for an exact path match: | ||||||
| 
 | 
 | ||||||
| ```js | ```js | ||||||
| { | { paths: [ | ||||||
|     paths: [ |     { match: '/' | ||||||
|         { match: "/", redirect: 301 }, |     , redirect: 301 | ||||||
|         { match: /^\/$/, redirect: 301 } |     } | ||||||
|     ]; |   , { match: /^\/$/ | ||||||
|  |     , redirect: 301 | ||||||
|  |     } | ||||||
|  |   ] | ||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
| If you're using this, you're probably getting too fancy (but hey, I get too fancy sometimes too). | If you're using this, you're probably getting too fancy (but hey, I get too fancy sometimes too). | ||||||
| 
 | 
 | ||||||
|  | ## Demo | ||||||
|  | 
 | ||||||
|  | ```javascript | ||||||
|  | 'use strict'; | ||||||
|  | 
 | ||||||
|  | var http = require('http'); | ||||||
|  | var server = http.createServer(); | ||||||
|  | var securePort = process.argv[2] || 8443; | ||||||
|  | var insecurePort = process.argv[3] || 8080; | ||||||
|  | 
 | ||||||
|  | server.on('request', require('redirect-https')({ | ||||||
|  |   port: securePort | ||||||
|  | , body: '<!-- Hello! Please use HTTPS instead -->' | ||||||
|  | , trustProxy: true // default is false | ||||||
|  | })); | ||||||
|  | 
 | ||||||
|  | server.listen(insecurePort, function () { | ||||||
|  |   console.log('Listening on http://localhost.pplwink.com:' + server.address().port); | ||||||
|  | }); | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
| # Meta redirect by default, but why? | # Meta redirect by default, but why? | ||||||
| 
 | 
 | ||||||
| When something is broken (i.e. insecure), you don't want it to kinda work, you want developers to notice. | When something is broken (i.e. insecure), you don't want it to kinda work, you want developers to notice. | ||||||
| @ -113,6 +108,6 @@ If your application is properly separated between static assets and api, then it | |||||||
| The incoming URL is already URI encoded by the browser but, just in case, I run an html escape on it | 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: | so that no malicious links of this sort will yield unexpected behavior: | ||||||
| 
 | 
 | ||||||
| -   `http://localhost.rootprojects.org:8080/"><script>alert('hi')</script>` |   * `http://localhost.pplwink.com:8080/"><script>alert('hi')</script>` | ||||||
| -   `http://localhost.rootprojects.org:8080/';URL=http://example.com` |   * `http://localhost.pplwink.com:8080/';URL=http://example.com` | ||||||
| -   `http://localhost.rootprojects.org:8080/;URL=http://example.com` |   * `http://localhost.pplwink.com:8080/;URL=http://example.com` | ||||||
|  | |||||||
							
								
								
									
										77
									
								
								index.js
									
									
									
									
									
								
							
							
						
						
									
										77
									
								
								index.js
									
									
									
									
									
								
							| @ -1,7 +1,7 @@ | |||||||
| "use strict"; | 'use strict'; | ||||||
| 
 | 
 | ||||||
| module.exports = function (opts) { | module.exports = function (opts) { | ||||||
|     var escapeHtml = require("escape-html"); |   var escapeHtml = require('escape-html'); | ||||||
| 
 | 
 | ||||||
|   if (!opts) { |   if (!opts) { | ||||||
|     opts = {}; |     opts = {}; | ||||||
| @ -13,41 +13,40 @@ module.exports = function (opts) { | |||||||
|     opts.browsers = 301; |     opts.browsers = 301; | ||||||
|   } |   } | ||||||
|   if (!opts.apis) { |   if (!opts.apis) { | ||||||
|         opts.apis = "meta"; |     opts.apis = 'meta'; | ||||||
|   } |   } | ||||||
|   if (!Array.isArray(opts.paths)) { |   if (!Array.isArray(opts.paths)) { | ||||||
|         opts.paths = [{ match: "/" }]; |     opts.paths = [ { match: '/' } ]; | ||||||
|   } |   } | ||||||
|     if (!("body" in opts)) { |   if (!('body' in opts)) { | ||||||
|         opts.body = |     opts.body = "<!-- Hello Developer Person! We don't serve insecure resources around here." | ||||||
|             "<!-- Hello Developer Person! We don't serve insecure resources around here." + |       + "\n    Please use HTTPS instead. -->"; | ||||||
|             "\n    Please use HTTPS instead. -->"; |  | ||||||
|   } |   } | ||||||
|     opts.body = opts.body.replace(/{{\s+PORT\s+}}/gi, opts.port); |   opts.body = opts.body.replace(/{{\s+PORT\s+}}/ig, opts.port); | ||||||
| 
 | 
 | ||||||
|   return function (req, res, next) { |   return function (req, res, next) { | ||||||
|         if ( |     if (req.connection.encrypted | ||||||
|             req.connection.encrypted || |       || 'https' === req.protocol | ||||||
|             "https" === req.protocol || |       || (opts.trustProxy && 'https' === req.headers['x-forwarded-proto']) | ||||||
|             (opts.trustProxy && "https" === req.headers["x-forwarded-proto"]) |  | ||||||
|     ) { |     ) { | ||||||
|       next(); |       next(); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|         var url = req.originalUrl || req.url; |     var url = (req.originalUrl || req.url); | ||||||
|     // We don't want chrome showing the "Not Secure" badge during the redirect.
 |     // We don't want chrome showing the "Not Secure" badge during the redirect.
 | ||||||
|         var probablyBrowser = |     var probablyBrowser = (0 === (req.headers['user-agent']||'').indexOf('Mozilla/')); | ||||||
|             0 === (req.headers["user-agent"] || "").indexOf("Mozilla/"); |  | ||||||
|     // But we don't want devs, APIs, or Bots to accidentally browse insecure.
 |     // But we don't want devs, APIs, or Bots to accidentally browse insecure.
 | ||||||
|     var redirect = probablyBrowser ? opts.browsers : opts.apis; |     var redirect = probablyBrowser ? opts.browsers : opts.apis; | ||||||
|         var host = req.headers.host || ""; |     var host = req.headers.host || ''; | ||||||
| 		if (!/:\d+/.test(host) && 443 !== opts.port) { | 		if (!/:\d+/.test(host) && 443 !== opts.port) { | ||||||
| 			// we are using standard port 80, but we aren't using standard port 443
 | 			// we are using standard port 80, but we aren't using standard port 443
 | ||||||
|             host += ":80"; | 			host += ':80'; | ||||||
| 		} | 		} | ||||||
|         var newLocation = |     var newLocation = 'https://' | ||||||
|             "https://" + host.replace(/:\d+/, ":" + opts.port) + url; |       + host.replace(/:\d+/, ':' + opts.port) + url | ||||||
|  |       ; | ||||||
|  | 
 | ||||||
|     //var encodedLocation = encodeURI(newLocation);
 |     //var encodedLocation = encodeURI(newLocation);
 | ||||||
|     var escapedLocation = escapeHtml(newLocation); |     var escapedLocation = escapeHtml(newLocation); | ||||||
|     var decodedLocation; |     var decodedLocation; | ||||||
| @ -58,29 +57,29 @@ module.exports = function (opts) { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     var body = opts.body |     var body = opts.body | ||||||
|             .replace(/{{\s*HTML_URL\s*}}/gi, escapeHtml(decodedLocation)) |           .replace(/{{\s*HTML_URL\s*}}/ig, escapeHtml(decodedLocation)) | ||||||
|             .replace(/{{\s*URL\s*}}/gi, escapedLocation) |           .replace(/{{\s*URL\s*}}/ig, escapedLocation) | ||||||
|             .replace(/{{\s*UNSAFE_URL\s*}}/gi, newLocation); |           .replace(/{{\s*UNSAFE_URL\s*}}/ig, newLocation) | ||||||
|         var metaRedirect = |           ; | ||||||
|             "" + | 
 | ||||||
|             "<html>" + |     var metaRedirect = '' | ||||||
|             '\n<head><META http-equiv="refresh" content="0;URL=\'' + |       + '<html>\n' | ||||||
|             escapedLocation + |       + '<head>\n' | ||||||
|             "'\"></head>" + |       //+ '  <style>* { background-color: white; color: white; text-decoration: none; }</style>\n'
 | ||||||
|             "\n<body>" + |       + '  <META http-equiv="refresh" content="0;URL=\'' + escapedLocation + '\'">\n' | ||||||
|             body + |       + '</head>\n' | ||||||
|             "</body>" + |       + '<body>\n' + body + '\n</body>\n' | ||||||
|             "\n</html>\n"; |       + '</html>\n' | ||||||
|  |       ; | ||||||
|     var pathMatch; |     var pathMatch; | ||||||
| 
 | 
 | ||||||
|     opts.paths.some(function (p) { |     opts.paths.some(function (p) { | ||||||
|       if (!p.match) { |       if (!p.match) { | ||||||
|         // ignore
 |         // ignore
 | ||||||
|             } else if ("string" === typeof p.match) { |       } else if ('string' === typeof p.match) { | ||||||
|                 pathMatch = url === p.match && (p.redirect || 301); |         pathMatch = (url === p.match) && (p.redirect || 301); | ||||||
|       } else { |       } else { | ||||||
|                 pathMatch = |         pathMatch = p.match.test && p.match.test(url) && (p.redirect || 301); | ||||||
|                     p.match.test && p.match.test(url) && (p.redirect || 301); |  | ||||||
|       } |       } | ||||||
|       if (pathMatch) { |       if (pathMatch) { | ||||||
|         redirect = pathMatch; |         redirect = pathMatch; | ||||||
| @ -90,9 +89,9 @@ module.exports = function (opts) { | |||||||
|     // If it's not a non-0 number (because null is 0) then 'meta' is assumed.
 |     // If it's not a non-0 number (because null is 0) then 'meta' is assumed.
 | ||||||
|     if (redirect && isFinite(redirect)) { |     if (redirect && isFinite(redirect)) { | ||||||
|       res.statusCode = redirect; |       res.statusCode = redirect; | ||||||
|             res.setHeader("Location", newLocation); |       res.setHeader('Location', newLocation); | ||||||
|     } |     } | ||||||
|         res.setHeader("Content-Type", "text/html; charset=utf-8"); |     res.setHeader('Content-Type', 'text/html; charset=utf-8'); | ||||||
|     res.end(metaRedirect); |     res.end(metaRedirect); | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
|  | |||||||
							
								
								
									
										13
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										13
									
								
								package-lock.json
									
									
									
										generated
									
									
									
								
							| @ -1,13 +0,0 @@ | |||||||
| { |  | ||||||
|   "name": "redirect-https", |  | ||||||
|   "version": "1.3.1", |  | ||||||
|   "lockfileVersion": 1, |  | ||||||
|   "requires": true, |  | ||||||
|   "dependencies": { |  | ||||||
|     "escape-html": { |  | ||||||
|       "version": "1.0.3", |  | ||||||
|       "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", |  | ||||||
|       "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| } |  | ||||||
| @ -1,6 +1,6 @@ | |||||||
| { | { | ||||||
|   "name": "redirect-https", |   "name": "redirect-https", | ||||||
|   "version": "1.3.1", |   "version": "1.3.0", | ||||||
|   "description": "Redirect from HTTP to HTTPS using meta redirects", |   "description": "Redirect from HTTP to HTTPS using meta redirects", | ||||||
|   "main": "index.js", |   "main": "index.js", | ||||||
|   "scripts": { |   "scripts": { | ||||||
| @ -8,7 +8,7 @@ | |||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "git", |     "type": "git", | ||||||
|     "url": "https://git.coolaj86.com/coolaj86/redirect-https.js.git" |     "url": "git+https://git.coolaj86.com/coolaj86/redirect-https.js.git" | ||||||
|   }, |   }, | ||||||
|   "keywords": [ |   "keywords": [ | ||||||
|     "https", |     "https", | ||||||
| @ -27,6 +27,5 @@ | |||||||
|   "homepage": "https://git.coolaj86.com/coolaj86/redirect-https.js#readme", |   "homepage": "https://git.coolaj86.com/coolaj86/redirect-https.js#readme", | ||||||
|   "dependencies": { |   "dependencies": { | ||||||
|     "escape-html": "^1.0.3" |     "escape-html": "^1.0.3" | ||||||
|   }, |   } | ||||||
|   "devDependencies": {} |  | ||||||
| } | } | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user