mirror of
				https://github.com/therootcompany/greenlock-express.js.git
				synced 2024-11-16 17:28:59 +00:00 
			
		
		
		
	
		
			
	
	
		
			129 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
		
		
			
		
	
	
			129 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
	
	
|  | "use strict"; | ||
|  | 
 | ||
|  | var Servers = module.exports; | ||
|  | 
 | ||
|  | var http = require("http"); | ||
|  | var HttpMiddleware = require("./http-middleware.js"); | ||
|  | var HttpsMiddleware = require("./https-middleware.js"); | ||
|  | var sni = require("./sni.js"); | ||
|  | 
 | ||
|  | Servers.create = function(greenlock, opts) { | ||
|  | 	var servers = {}; | ||
|  | 	var _httpServer; | ||
|  | 	var _httpsServer; | ||
|  | 
 | ||
|  | 	function startError(e) { | ||
|  | 		explainError(e); | ||
|  | 		process.exit(1); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	servers.httpServer = function(defaultApp) { | ||
|  | 		if (_httpServer) { | ||
|  | 			return _httpServer; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		_httpServer = http.createServer(HttpMiddleware.create(opts.greenlock, defaultApp)); | ||
|  | 		_httpServer.once("error", startError); | ||
|  | 
 | ||
|  | 		return _httpServer; | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	servers.httpsServer = function(secureOpts, defaultApp) { | ||
|  | 		if (_httpsServer) { | ||
|  | 			return _httpsServer; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		if (!secureOpts) { | ||
|  | 			secureOpts = {}; | ||
|  | 		} | ||
|  | 
 | ||
|  | 		_httpsServer = createSecureServer( | ||
|  | 			wrapDefaultSniCallback(opts, greenlock, secureOpts), | ||
|  | 			HttpsMiddleware.create(greenlock, defaultApp) | ||
|  | 		); | ||
|  | 		_httpsServer.once("error", startError); | ||
|  | 
 | ||
|  | 		return _httpsServer; | ||
|  | 	}; | ||
|  | 
 | ||
|  | 	servers.serveApp = function(app) { | ||
|  | 		return new Promise(function(resolve, reject) { | ||
|  | 			if ("function" !== typeof app) { | ||
|  | 				reject(new Error("glx.serveApp(app) expects a node/express app in the format `function (req, res) { ... }`")); | ||
|  | 				return; | ||
|  | 			} | ||
|  | 
 | ||
|  | 			var plainServer = servers.httpServer(require("redirect-https")()); | ||
|  | 			var plainAddr = "0.0.0.0"; | ||
|  | 			var plainPort = 80; | ||
|  | 			plainServer.listen(plainPort, plainAddr, function() { | ||
|  | 				console.info("Listening on", plainAddr + ":" + plainPort, "for ACME challenges, and redirecting to HTTPS"); | ||
|  | 
 | ||
|  | 				// TODO fetch greenlock.servername
 | ||
|  | 				var secureServer = servers.httpsServer(app); | ||
|  | 				var secureAddr = "0.0.0.0"; | ||
|  | 				var securePort = 443; | ||
|  | 				secureServer.listen(securePort, secureAddr, function() { | ||
|  | 					console.info("Listening on", secureAddr + ":" + securePort, "for secure traffic"); | ||
|  | 
 | ||
|  | 					plainServer.removeListener("error", startError); | ||
|  | 					secureServer.removeListener("error", startError); | ||
|  | 					resolve(); | ||
|  | 				}); | ||
|  | 			}); | ||
|  | 		}); | ||
|  | 	}; | ||
|  | 	return servers; | ||
|  | }; | ||
|  | 
 | ||
|  | function explainError(e) { | ||
|  | 	console.error(); | ||
|  | 	console.error("Error: " + e.message); | ||
|  | 	if ("EACCES" === e.errno) { | ||
|  | 		console.error("You don't have prmission to access '" + e.address + ":" + e.port + "'."); | ||
|  | 		console.error('You probably need to use "sudo" or "sudo setcap \'cap_net_bind_service=+ep\' $(which node)"'); | ||
|  | 	} else if ("EADDRINUSE" === e.errno) { | ||
|  | 		console.error("'" + e.address + ":" + e.port + "' is already being used by some other program."); | ||
|  | 		console.error("You probably need to stop that program or restart your computer."); | ||
|  | 	} else { | ||
|  | 		console.error(e.code + ": '" + e.address + ":" + e.port + "'"); | ||
|  | 	} | ||
|  | 	console.error(); | ||
|  | } | ||
|  | 
 | ||
|  | function wrapDefaultSniCallback(opts, greenlock, secureOpts) { | ||
|  | 	// I'm not sure yet if the original SNICallback
 | ||
|  | 	// should be called before or after, so I'm just
 | ||
|  | 	// going to delay making that choice until I have the use case
 | ||
|  | 	/* | ||
|  | 		if (!secureOpts.SNICallback) { | ||
|  | 			secureOpts.SNICallback = function(servername, cb) { | ||
|  | 				cb(null, null); | ||
|  | 			}; | ||
|  | 		} | ||
|  |   */ | ||
|  | 	if (secureOpts.SNICallback) { | ||
|  | 		console.warn(); | ||
|  | 		console.warn("[warning] Ignoring the given tlsOptions.SNICallback function."); | ||
|  | 		console.warn(); | ||
|  | 		console.warn("          We're very open to implementing support for this,"); | ||
|  | 		console.warn("          we just don't understand the use case yet."); | ||
|  | 		console.warn("          Please open an issue to discuss. We'd love to help."); | ||
|  | 		console.warn(); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	secureOpts.SNICallback = sni.create(opts, greenlock, secureOpts); | ||
|  | 	return secureOpts; | ||
|  | } | ||
|  | 
 | ||
|  | function createSecureServer(secureOpts, fn) { | ||
|  | 	var major = process.versions.node.split(".")[0]; | ||
|  | 
 | ||
|  | 	// TODO can we trust earlier versions as well?
 | ||
|  | 	if (major >= 12) { | ||
|  | 		return require("http2").createSecureServer(secureOpts, fn); | ||
|  | 	} else { | ||
|  | 		return require("https").createServer(secureOpts, fn); | ||
|  | 	} | ||
|  | } |