diff --git a/bin/genieacs-cwmp b/bin/genieacs-cwmp index f3356b3..eeaed5e 100755 --- a/bin/genieacs-cwmp +++ b/bin/genieacs-cwmp @@ -1,9 +1,4 @@ #!/usr/bin/env -S node -r esm -r ts-node/register/transpile-only -import * as path from "path"; -import * as fs from "fs"; - -process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), "..")); - import * as config from "../lib/config"; import * as logger from "../lib/logger"; import * as cluster from "../lib/cluster"; @@ -61,14 +56,10 @@ if (!cluster.worker) { cluster.stop(); }); } else { - let ssl; - if (config.get("CWMP_SSL")) { - ssl = { - key: path.resolve("" + config.get("CONFIG_DIR"), "cwmp.key"), - cert: path.resolve("" + config.get("CONFIG_DIR"), "cwmp.crt"), - ca: path.resolve("" + config.get("CONFIG_DIR"), "cwmp.ca-bundle") - }; - } + const ssl = { + key: config.get("CWMP_SSL_KEY"), + cert: config.get("CWMP_SSL_CERT") + }; process.on("uncaughtException", err => { if ((err as NodeJS.ErrnoException).code === "ERR_IPC_DISCONNECTED") return; diff --git a/bin/genieacs-ext b/bin/genieacs-ext index b8ac176..07130b0 100755 --- a/bin/genieacs-ext +++ b/bin/genieacs-ext @@ -69,7 +69,7 @@ process.on("message", message => { jobs.add(message[0]); if (!script) { - const cwd = process.env["GENIEACS_CONFIG_DIR"] + "/ext"; + const cwd = process.env["GENIEACS_EXT_DIR"]; process.chdir(cwd); script = require(`${cwd}/${fileName}`); } diff --git a/bin/genieacs-fs b/bin/genieacs-fs index d3a34a1..a772b91 100755 --- a/bin/genieacs-fs +++ b/bin/genieacs-fs @@ -1,9 +1,4 @@ #!/usr/bin/env -S node -r esm -r ts-node/register/transpile-only -import * as path from "path"; -import * as fs from "fs"; - -process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), "..")); - import * as config from "../lib/config"; import * as logger from "../lib/logger"; import * as cluster from "../lib/cluster"; @@ -57,14 +52,10 @@ if (!cluster.worker) { cluster.stop(); }); } else { - let ssl; - if (config.get("FS_SSL")) { - ssl = { - key: path.resolve("" + config.get("CONFIG_DIR"), "fs.key"), - cert: path.resolve("" + config.get("CONFIG_DIR"), "fs.crt"), - ca: path.resolve("" + config.get("CONFIG_DIR"), "fs.ca-bundle") - }; - } + const ssl = { + key: config.get("FS_SSL_KEY"), + cert: config.get("FS_SSL_CERT") + }; process.on("uncaughtException", err => { if ((err as NodeJS.ErrnoException).code === "ERR_IPC_DISCONNECTED") return; diff --git a/bin/genieacs-nbi b/bin/genieacs-nbi index f86e410..5a9208e 100755 --- a/bin/genieacs-nbi +++ b/bin/genieacs-nbi @@ -1,9 +1,4 @@ #!/usr/bin/env -S node -r esm -r ts-node/register/transpile-only -import * as path from "path"; -import * as fs from "fs"; - -process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), "..")); - import * as config from "../lib/config"; import * as logger from "../lib/logger"; import * as cluster from "../lib/cluster"; @@ -61,14 +56,10 @@ if (!cluster.worker) { cluster.stop(); }); } else { - let ssl; - if (config.get("NBI_SSL")) { - ssl = { - key: path.resolve("" + config.get("CONFIG_DIR"), "nbi.key"), - cert: path.resolve("" + config.get("CONFIG_DIR"), "nbi.crt"), - ca: path.resolve("" + config.get("CONFIG_DIR"), "nbi.ca-bundle") - }; - } + const ssl = { + key: config.get("NBI_SSL_KEY"), + cert: config.get("NBI_SSL_CERT") + }; process.on("uncaughtException", err => { if ((err as NodeJS.ErrnoException).code === "ERR_IPC_DISCONNECTED") return; diff --git a/bin/genieacs-ui b/bin/genieacs-ui index 02cb42c..9413d0c 100755 --- a/bin/genieacs-ui +++ b/bin/genieacs-ui @@ -1,9 +1,4 @@ #!/usr/bin/env -S node -r esm -r ts-node/register/transpile-only -import * as path from "path"; -import * as fs from "fs"; - -process.chdir(path.resolve(path.dirname(fs.realpathSync(__filename)), "..")); - import * as config from "../lib/config"; import * as logger from "../lib/logger"; import * as cluster from "../lib/cluster"; @@ -63,14 +58,10 @@ if (!cluster.worker) { cluster.stop(); }); } else { - let ssl; - if (config.get("UI_SSL")) { - ssl = { - key: path.resolve("" + config.get("CONFIG_DIR"), "ui.key"), - cert: path.resolve("" + config.get("CONFIG_DIR"), "ui.crt"), - ca: path.resolve("" + config.get("CONFIG_DIR"), "ui.ca-bundle") - }; - } + const ssl = { + key: config.get("UI_SSL_KEY"), + cert: config.get("UI_SSL_CERT") + }; let stopping = false; diff --git a/config/config-sample.json b/config/config-sample.json index 51251e3..3ade9ab 100644 --- a/config/config-sample.json +++ b/config/config-sample.json @@ -2,7 +2,6 @@ "MONGODB_CONNECTION_URL" : "mongodb://127.0.0.1/genieacs", "CWMP_INTERFACE" : "0.0.0.0", "CWMP_PORT" : 7547, - "CWMP_SSL" : false, "NBI_INTERFACE" : "0.0.0.0", "NBI_PORT" : 7557, "FS_INTERFACE" : "0.0.0.0", diff --git a/lib/config.ts b/lib/config.ts index d5645b1..37b9a5d 100644 --- a/lib/config.ts +++ b/lib/config.ts @@ -18,10 +18,24 @@ */ import { resolve } from "path"; -import { readFileSync } from "fs"; +import { readFileSync, existsSync } from "fs"; + +// Find project root directory +export let ROOT_DIR = resolve(__dirname, ".."); +while (!existsSync(`${ROOT_DIR}/package.json`)) { + const d = resolve(ROOT_DIR, ".."); + if (d === ROOT_DIR) { + ROOT_DIR = process.cwd(); + break; + } + ROOT_DIR = d; +} + +// For compatibility with v1.1 +let configDir, cwmpSsl, nbiSsl, fsSsl, uiSsl; const options = { - CONFIG_DIR: { type: "path", default: "config" }, + EXT_DIR: { type: "path", default: resolve(ROOT_DIR, "config/ext") }, MONGODB_CONNECTION_URL: { type: "string", default: "mongodb://127.0.0.1/genieacs" @@ -30,21 +44,24 @@ const options = { CWMP_WORKER_PROCESSES: { type: "int", default: 0 }, CWMP_PORT: { type: "int", default: 7547 }, CWMP_INTERFACE: { type: "string", default: "0.0.0.0" }, - CWMP_SSL: { type: "bool", default: false }, + CWMP_SSL_CERT: { type: "string", default: "" }, + CWMP_SSL_KEY: { type: "string", default: "" }, CWMP_LOG_FILE: { type: "path", default: "" }, CWMP_ACCESS_LOG_FILE: { type: "path", default: "" }, NBI_WORKER_PROCESSES: { type: "int", default: 0 }, NBI_PORT: { type: "int", default: 7557 }, NBI_INTERFACE: { type: "string", default: "0.0.0.0" }, - NBI_SSL: { type: "bool", default: false }, + NBI_SSL_CERT: { type: "string", default: "" }, + NBI_SSL_KEY: { type: "string", default: "" }, NBI_LOG_FILE: { type: "path", default: "" }, NBI_ACCESS_LOG_FILE: { type: "path", default: "" }, FS_WORKER_PROCESSES: { type: "int", default: 0 }, FS_PORT: { type: "int", default: 7567 }, FS_INTERFACE: { type: "string", default: "0.0.0.0" }, - FS_SSL: { type: "bool", default: false }, + FS_SSL_CERT: { type: "string", default: "" }, + FS_SSL_KEY: { type: "string", default: "" }, FS_HOSTNAME: { type: "string", default: "acs.example.com" }, FS_LOG_FILE: { type: "path", default: "" }, FS_ACCESS_LOG_FILE: { type: "path", default: "" }, @@ -52,7 +69,8 @@ const options = { UI_WORKER_PROCESSES: { type: "int", default: 0 }, UI_PORT: { type: "int", default: 3000 }, UI_INTERFACE: { type: "string", default: "0.0.0.0" }, - UI_SSL: { type: "bool", default: false }, + UI_SSL_CERT: { type: "string", default: "" }, + UI_SSL_KEY: { type: "string", default: "" }, UI_LOG_FILE: { type: "path", default: "" }, UI_ACCESS_LOG_FILE: { type: "path", default: "" }, UI_JWT_SECRET: { type: "string", default: "" }, @@ -95,6 +113,42 @@ const allConfig: { [name: string]: string | number } = {}; function setConfig(name, value, commandLineArgument = false): boolean { if (allConfig[name] != null) return true; + // For compatibility with v1.1 + if (name === "CONFIG_DIR" || name === "config-dir") + configDir = configDir || resolve(ROOT_DIR, value); + + if (name === "CWMP_SSL" || name === "cwmp-ssl") { + cwmpSsl = + cwmpSsl || + String(value) + .toLowerCase() + .trim(); + } + + if (name === "NBI_SSL" || name === "nbi-ssl") { + nbiSsl = + nbiSsl || + String(value) + .toLowerCase() + .trim(); + } + + if (name === "FS_SSL" || name === "fs-ssl") { + fsSsl = + fsSsl || + String(value) + .toLowerCase() + .trim(); + } + + if (name === "UI_SSL" || name === "ui-ssl") { + uiSsl = + uiSsl || + String(value) + .toLowerCase() + .trim(); + } + // For compatibility with v1.0 if (name === "PRESETS_CACHE_DURATION" || name === "presets-cache-duration") setConfig("MAX_CACHE_TTL", value); @@ -124,7 +178,7 @@ function setConfig(name, value, commandLineArgument = false): boolean { case "int": return Number(val); case "bool": - return ["true", "on", "yes", "1"].includes( + return ["true", "1"].includes( String(val) .trim() .toLowerCase() @@ -177,19 +231,45 @@ while (argv.length) { for (const [k, v] of Object.entries(process.env)) if (k.startsWith("GENIEACS_")) setConfig(k.slice(9), v); -// Use default config dir if none defined -setConfig("CONFIG_DIR", options["CONFIG_DIR"]["default"]); - // Configuration file -const configFile = JSON.parse( - readFileSync( - resolve(allConfig.CONFIG_DIR as string, "config.json") - ).toString() -); -for (const [k, v] of Object.entries(configFile)) { - if (!setConfig(k, v)) - // Pass as environment variable to be accessable by extensions - process.env[`GENIEACS_${k}`] = `${v}`; +const configFilename = configDir + ? `${configDir}/config.json` + : `${ROOT_DIR}/config/config.json`; + +if (existsSync(configFilename)) { + const configFile = JSON.parse(readFileSync(configFilename).toString()); + + for (const [k, v] of Object.entries(configFile)) { + if (!setConfig(k, v)) + // Pass as environment variable to be accessable by extensions + process.env[`GENIEACS_${k}`] = `${v}`; + } +} + +if (configDir) setConfig("EXT_DIR", `${configDir}/ext`); + +if (["true", "1"].includes(cwmpSsl)) { + const d = configDir || `${ROOT_DIR}/config`; + setConfig("CWMP_SSL_CERT", `${d}/cwmp.crt`); + setConfig("CWMP_SSL_KEY", `${d}/cwmp.key`); +} + +if (["true", "1"].includes(nbiSsl)) { + const d = configDir || `${ROOT_DIR}/config`; + setConfig("NBI_SSL_CERT", `${d}/cwmp.crt`); + setConfig("NBI_SSL_KEY", `${d}/cwmp.key`); +} + +if (["true", "1"].includes(fsSsl)) { + const d = configDir || `${ROOT_DIR}/config`; + setConfig("FS_SSL_CERT", `${d}/cwmp.crt`); + setConfig("FS_SSL_KEY", `${d}/cwmp.key`); +} + +if (["true", "1"].includes(uiSsl)) { + const d = configDir || `${ROOT_DIR}/config`; + setConfig("UI_SSL_CERT", `${d}/cwmp.crt`); + setConfig("UI_SSL_KEY", `${d}/cwmp.key`); } // Defaults diff --git a/lib/server.ts b/lib/server.ts index 95440d1..a8cf510 100644 --- a/lib/server.ts +++ b/lib/server.ts @@ -20,6 +20,8 @@ import * as fs from "fs"; import * as http from "http"; import * as https from "https"; +import * as path from "path"; +import { ROOT_DIR } from "./config"; let server: http.Server | https.Server; let listener: (...args) => void; @@ -57,22 +59,16 @@ export function start( ): void { listener = _listener; - if (ssl) { + if (ssl && ssl.key && ssl.cert) { const options = { - key: fs.readFileSync(ssl.key), - cert: fs.readFileSync(ssl.cert), - ca: null + key: ssl.key + .split(":") + .map(f => fs.readFileSync(path.resolve(ROOT_DIR, f.trim()))), + cert: ssl.cert + .split(":") + .map(f => fs.readFileSync(path.resolve(ROOT_DIR, f.trim()))) }; - try { - // Use intermediate certificates if available - options.ca = fs - .readFileSync(ssl.ca) - .toString() - .match(/-+BEGIN CERTIFICATE-+[0-9a-zA-Z+\-/=\s]+?-+END CERTIFICATE-+/g); - } catch (error) { - // No intermediate certificate - } server = https.createServer(options, listener); if (onConnection != null) server.on("secureConnection", onConnection); } else { diff --git a/lib/ui.ts b/lib/ui.ts index ca26fb8..e3cea59 100644 --- a/lib/ui.ts +++ b/lib/ui.ts @@ -157,6 +157,6 @@ koa.use( ); koa.use(router.routes()); -koa.use(koaStatic("./public")); +koa.use(koaStatic(config.ROOT_DIR + "/public")); export const listener = koa.callback();