in experimental/traffic-portal/server.ts [198:346]
async function run(): Promise<number> {
const version = await getVersion();
const parser = new ArgumentParser({
// Nothing I can do about this, library specifies its interface.
/* eslint-disable @typescript-eslint/naming-convention */
add_help: true,
/* eslint-enable @typescript-eslint/naming-convention */
description: "Traffic Portal re-written in modern Angular"
});
parser.add_argument("-t", "--traffic-ops", {
dest: "trafficOps",
help: "Specify the Traffic Ops host/URL, including port. (Default: uses the `TO_URL` environment variable)",
type: (arg: string) => {
try {
return new URL(arg);
} catch (e) {
if (e instanceof TypeError) {
return new URL(`https://${arg}`);
}
throw e;
}
}
});
parser.add_argument("-u", "--tpv1-url", {
dest: "tpv1Url",
help: "Specify the Traffic Portal v1 URL. (Default: uses the `TP_V1_URL` environment variable)",
type: (arg: string) => {
try {
return new URL(arg);
} catch (e) {
if (e instanceof TypeError) {
return new URL(`https://${arg}`);
}
throw e;
}
}
});
parser.add_argument("-k", "--insecure", {
action: "store_true",
help: "Skip Traffic Ops server certificate validation. This affects requests from Traffic Portal to Traffic Ops AND signature" +
" verification of any passed SSL keys/certificates"
});
parser.add_argument("-p", "--port", {
default: defaultConfig.port,
help: "Specify the port on which Traffic Portal will listen (Default: 4200)",
type: "int"
});
parser.add_argument("-c", "--cert-path", {
dest: "certPath",
help: "Specify a location for an SSL certificate to be used by Traffic Portal. (Requires `-K`/`--key-path`. If both are omitted," +
" will serve using HTTP)",
type: "str"
});
parser.add_argument("-d", "--browser-folder", {
default: defaultConfig.browserFolder,
dest: "browserFolder",
help: "Specify location for the folder that holds the browser files",
type: "str"
});
parser.add_argument("-K", "--key-path", {
dest: "keyPath",
help: "Specify a location for an SSL certificate to be used by Traffic Portal. (Requires `-c`/`--cert-path`. If both are omitted," +
" will serve using HTTP)",
type: "str"
});
parser.add_argument("-C", "--config-file", {
default: defaultConfigFile,
dest: "configFile",
help: "Specify a path to a configuration file - options are overridden by command-line flags.",
type: "str"
});
parser.add_argument("-v", "--version", {
action: "version",
version: versionToString(version)
});
let config: ServerConfig;
try {
config = await getConfig(parser.parse_args(), version);
} catch (e) {
// Logger cannot be initialized before reading server configuration
// eslint-disable-next-line no-console
console.error(`Failed to initialize server configuration: ${e}`);
return 1;
}
const logger = new Logger(console, environment.production ? LogLevel.INFO : LogLevel.DEBUG);
// Start up the Node server
const server = await app(config);
if (config.useSSL) {
let cert: string;
let key: string;
let ca: Array<string>;
try {
cert = readFileSync(config.certPath, {encoding: "utf8"});
key = readFileSync(config.keyPath, {encoding: "utf8"});
ca = config.certificateAuthPaths.map(c => readFileSync(c, {encoding: "utf8"}));
} catch (e) {
logger.error("reading SSL key/cert:", String(e));
if (!environment.production) {
console.trace(e);
}
return 1;
}
createServer(
{
ca,
cert,
key,
rejectUnauthorized: !config.insecure,
},
server
).listen(config.port, () => {
logger.debug(`Node Express server listening on port ${config.port}`);
});
try {
const redirectServer = createRedirectServer(
(req, res) => {
if (!req.url) {
res.statusCode = 500;
logger.error("got HTTP request for redirect that had no URL");
res.end();
return;
}
res.statusCode = 308;
res.setHeader("Location", req.url.replace(/^[hH][tT][tT][pP]:/, "https:"));
res.end();
}
);
redirectServer.listen(80);
redirectServer.on("error", e => {
logger.error("redirect server encountered error:", String(e));
if (hasProperty(e, "code", "string") && e.code === "EACCES") {
logger.warn("access to port 80 not allowed; closing redirect server");
redirectServer.close();
}
});
} catch (e) {
logger.warn("Failed to initialize HTTP-to-HTTPS redirect listener:", e);
}
} else {
server.listen(config.port, () => {
logger.debug(`Node Express server listening on port ${config.port}`);
});
}
return 0;
}