2019-10-27 05:52:19 +00: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");
|
2019-10-28 07:06:43 +00:00
|
|
|
var cluster = require("cluster");
|
2019-10-27 05:52:19 +00:00
|
|
|
|
2019-10-28 09:43:42 +00:00
|
|
|
Servers.create = function(greenlock) {
|
2019-10-27 05:52:19 +00:00
|
|
|
var servers = {};
|
|
|
|
var _httpServer;
|
|
|
|
var _httpsServer;
|
|
|
|
|
|
|
|
function startError(e) {
|
|
|
|
explainError(e);
|
|
|
|
process.exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
servers.httpServer = function(defaultApp) {
|
|
|
|
if (_httpServer) {
|
|
|
|
return _httpServer;
|
|
|
|
}
|
|
|
|
|
2019-10-28 07:06:43 +00:00
|
|
|
_httpServer = http.createServer(HttpMiddleware.create(greenlock, defaultApp));
|
2019-10-27 05:52:19 +00:00
|
|
|
_httpServer.once("error", startError);
|
|
|
|
|
|
|
|
return _httpServer;
|
|
|
|
};
|
|
|
|
|
2019-10-28 07:06:43 +00:00
|
|
|
var _middlewareApp;
|
|
|
|
|
2019-10-27 05:52:19 +00:00
|
|
|
servers.httpsServer = function(secureOpts, defaultApp) {
|
2019-10-28 07:06:43 +00:00
|
|
|
if (defaultApp) {
|
|
|
|
// TODO guard against being set twice?
|
|
|
|
_middlewareApp = defaultApp;
|
|
|
|
}
|
|
|
|
|
2019-10-27 05:52:19 +00:00
|
|
|
if (_httpsServer) {
|
2019-10-28 07:06:43 +00:00
|
|
|
if (secureOpts && Object.keys(secureOpts)) {
|
|
|
|
throw new Error("Call glx.httpsServer(tlsOptions) before calling glx.serveApp(app)");
|
|
|
|
}
|
2019-10-27 05:52:19 +00:00
|
|
|
return _httpsServer;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!secureOpts) {
|
|
|
|
secureOpts = {};
|
|
|
|
}
|
|
|
|
|
|
|
|
_httpsServer = createSecureServer(
|
2019-10-28 09:43:42 +00:00
|
|
|
wrapDefaultSniCallback(greenlock, secureOpts),
|
2019-10-28 07:06:43 +00:00
|
|
|
HttpsMiddleware.create(greenlock, function(req, res) {
|
|
|
|
if (!_middlewareApp) {
|
|
|
|
throw new Error("Set app with `glx.serveApp(app)` or `glx.httpsServer(tlsOptions, app)`");
|
|
|
|
}
|
|
|
|
_middlewareApp(req, res);
|
|
|
|
})
|
2019-10-27 05:52:19 +00:00
|
|
|
);
|
|
|
|
_httpsServer.once("error", startError);
|
|
|
|
|
|
|
|
return _httpsServer;
|
|
|
|
};
|
|
|
|
|
2019-10-28 09:43:42 +00:00
|
|
|
servers.id = function() {
|
|
|
|
return (cluster.isWorker && cluster.worker.id) || "0";
|
|
|
|
};
|
2019-10-27 05:52:19 +00:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2019-10-28 07:06:43 +00:00
|
|
|
var id = cluster.isWorker && cluster.worker.id;
|
2019-10-28 09:43:42 +00:00
|
|
|
var idstr = (id && "#" + id + " ") || "";
|
2019-10-27 05:52:19 +00:00
|
|
|
var plainServer = servers.httpServer(require("redirect-https")());
|
|
|
|
var plainAddr = "0.0.0.0";
|
|
|
|
var plainPort = 80;
|
|
|
|
plainServer.listen(plainPort, plainAddr, function() {
|
2019-10-28 07:06:43 +00:00
|
|
|
console.info(
|
|
|
|
idstr + "Listening on",
|
|
|
|
plainAddr + ":" + plainPort,
|
|
|
|
"for ACME challenges, and redirecting to HTTPS"
|
|
|
|
);
|
2019-10-27 05:52:19 +00:00
|
|
|
|
|
|
|
// TODO fetch greenlock.servername
|
2019-10-28 07:06:43 +00:00
|
|
|
_middlewareApp = app || _middlewareApp;
|
2019-10-27 07:19:44 +00:00
|
|
|
var secureServer = servers.httpsServer({}, app);
|
2019-10-27 05:52:19 +00:00
|
|
|
var secureAddr = "0.0.0.0";
|
|
|
|
var securePort = 443;
|
|
|
|
secureServer.listen(securePort, secureAddr, function() {
|
2019-10-28 07:06:43 +00:00
|
|
|
console.info(idstr + "Listening on", secureAddr + ":" + securePort, "for secure traffic");
|
2019-10-27 05:52:19 +00:00
|
|
|
|
|
|
|
plainServer.removeListener("error", startError);
|
|
|
|
secureServer.removeListener("error", startError);
|
|
|
|
resolve();
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
};
|
2019-10-28 07:06:43 +00:00
|
|
|
|
2019-10-27 05:52:19 +00:00
|
|
|
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();
|
|
|
|
}
|
|
|
|
|
2019-10-28 09:43:42 +00:00
|
|
|
function wrapDefaultSniCallback(greenlock, secureOpts) {
|
2019-10-27 05:52:19 +00:00
|
|
|
// 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();
|
|
|
|
}
|
|
|
|
|
2019-10-28 09:43:42 +00:00
|
|
|
// TODO greenlock.servername for workers
|
|
|
|
secureOpts.SNICallback = sni.create(greenlock, secureOpts);
|
2019-10-27 05:52:19 +00:00
|
|
|
return secureOpts;
|
|
|
|
}
|
|
|
|
|
|
|
|
function createSecureServer(secureOpts, fn) {
|
|
|
|
var major = process.versions.node.split(".")[0];
|
|
|
|
|
|
|
|
// TODO can we trust earlier versions as well?
|
|
|
|
if (major >= 12) {
|
2019-10-27 07:19:44 +00:00
|
|
|
secureOpts.allowHTTP1 = true;
|
2019-10-27 05:52:19 +00:00
|
|
|
return require("http2").createSecureServer(secureOpts, fn);
|
|
|
|
} else {
|
|
|
|
return require("https").createServer(secureOpts, fn);
|
|
|
|
}
|
|
|
|
}
|