| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | "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
 | 
					
						
							| 
									
										
										
										
											2019-10-27 01:19:44 -06:00
										 |  |  | 				var secureServer = servers.httpsServer({}, app); | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 				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]; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-27 01:19:44 -06:00
										 |  |  | 	console.log("debug set SNICallback:", secureOpts); | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 	// TODO can we trust earlier versions as well?
 | 
					
						
							|  |  |  | 	if (major >= 12) { | 
					
						
							| 
									
										
										
										
											2019-10-27 01:19:44 -06:00
										 |  |  | 		secureOpts.allowHTTP1 = true; | 
					
						
							| 
									
										
										
										
											2019-10-26 23:52:19 -06:00
										 |  |  | 		return require("http2").createSecureServer(secureOpts, fn); | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return require("https").createServer(secureOpts, fn); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |