From d4cc2dd361bd2f166924dd18efdc57634d67bc19 Mon Sep 17 00:00:00 2001 From: Reto Date: Sun, 1 May 2022 21:12:39 +0200 Subject: [PATCH] Refactor config out of Helper (#4558) * Remove config from Helper Helper is the usual util grab bag of useful stuff. Somehow the config ended up there historically but structurally that doesn't make any sense. * Add cert folder to prettier ignore file --- .eslintrc.yml | 2 +- .prettierignore | 1 + src/client.js | 12 +- src/clientManager.js | 22 ++-- src/command-line/index.js | 11 +- src/command-line/install.js | 5 +- src/command-line/start.js | 14 +- src/command-line/uninstall.js | 4 +- src/command-line/upgrade.js | 4 +- src/command-line/users/add.js | 7 +- src/command-line/users/edit.js | 12 +- src/command-line/users/index.js | 2 +- src/command-line/users/remove.js | 6 +- src/command-line/users/reset.js | 7 +- src/command-line/utils.js | 3 +- src/config.js | 182 ++++++++++++++++++++++++++ src/helper.js | 189 --------------------------- src/identification.js | 11 +- src/models/chan.js | 12 +- src/models/network.js | 41 +++--- src/plugins/auth/ldap.js | 16 +-- src/plugins/clientCertificate.js | 10 +- src/plugins/inputs/part.js | 4 +- src/plugins/irc-events/connection.js | 7 +- src/plugins/irc-events/error.js | 6 +- src/plugins/irc-events/link.js | 32 ++--- src/plugins/messageStorage/sqlite.js | 10 +- src/plugins/messageStorage/text.js | 6 +- src/plugins/packages/index.js | 11 +- src/plugins/packages/themes.js | 4 +- src/plugins/storage.js | 8 +- src/plugins/sts.js | 4 +- src/plugins/uploader.js | 12 +- src/plugins/webpush.js | 4 +- src/server.js | 85 ++++++------ test/fixtures/env.js | 2 +- test/models/network.js | 24 ++-- test/plugins/auth/ldap.js | 24 ++-- test/plugins/clientCertificate.js | 16 +-- test/plugins/link.js | 8 +- test/plugins/sqlite.js | 24 ++-- test/plugins/storage.js | 10 +- test/server.js | 6 +- test/tests/mergeConfig.js | 30 ++--- 44 files changed, 457 insertions(+), 453 deletions(-) create mode 100644 src/config.js diff --git a/.eslintrc.yml b/.eslintrc.yml index b297f929..0c36982a 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -2,7 +2,7 @@ root: true parserOptions: - ecmaVersion: 2020 + ecmaVersion: 2022 env: es6: true diff --git a/.prettierignore b/.prettierignore index 2119df94..aa316e17 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,6 +1,7 @@ coverage/ public/ test/fixtures/.thelounge/logs/ +test/fixtures/.thelounge/certificates/ test/fixtures/.thelounge/storage/ *.log diff --git a/src/client.js b/src/client.js index a4729415..b19f9db6 100644 --- a/src/client.js +++ b/src/client.js @@ -7,7 +7,7 @@ const Chan = require("./models/chan"); const crypto = require("crypto"); const Msg = require("./models/msg"); const Network = require("./models/network"); -const Helper = require("./helper"); +const Config = require("./config"); const UAParser = require("ua-parser-js"); const {v4: uuidv4} = require("uuid"); const escapeRegExp = require("lodash/escapeRegExp"); @@ -72,13 +72,13 @@ function Client(manager, name, config = {}) { client.config.log = Boolean(client.config.log); client.config.password = String(client.config.password); - if (!Helper.config.public && client.config.log) { - if (Helper.config.messageStorage.includes("sqlite")) { + if (!Config.values.public && client.config.log) { + if (Config.values.messageStorage.includes("sqlite")) { client.messageProvider = new MessageStorage(client); client.messageStorage.push(client.messageProvider); } - if (Helper.config.messageStorage.includes("text")) { + if (Config.values.messageStorage.includes("text")) { client.messageStorage.push(new TextFileMessageStorage(client)); } @@ -236,7 +236,7 @@ Client.prototype.connect = function (args, isStartup = false) { const network = new Network({ uuid: args.uuid, name: String( - args.name || (Helper.config.lockNetwork ? Helper.config.defaults.name : "") || "" + args.name || (Config.values.lockNetwork ? Config.values.defaults.name : "") || "" ), host: String(args.host || ""), port: parseInt(args.port, 10), @@ -759,7 +759,7 @@ Client.prototype.unregisterPushSubscription = function (token) { Client.prototype.save = _.debounce( function SaveClient() { - if (Helper.config.public) { + if (Config.values.public) { return; } diff --git a/src/clientManager.js b/src/clientManager.js index e90489ea..dc31317c 100644 --- a/src/clientManager.js +++ b/src/clientManager.js @@ -8,7 +8,7 @@ const fs = require("fs"); const path = require("path"); const Auth = require("./plugins/auth"); const Client = require("./client"); -const Helper = require("./helper"); +const Config = require("./config"); const WebPush = require("./plugins/webpush"); module.exports = ClientManager; @@ -22,12 +22,12 @@ ClientManager.prototype.init = function (identHandler, sockets) { this.identHandler = identHandler; this.webPush = new WebPush(); - if (!Helper.config.public) { + if (!Config.values.public) { this.loadUsers(); // LDAP does not have user commands, and users are dynamically // created upon logon, so we don't need to watch for new files - if (!Helper.config.ldap.enable) { + if (!Config.values.ldap.enable) { this.autoloadUsers(); } } @@ -81,7 +81,7 @@ ClientManager.prototype.loadUsers = function () { ClientManager.prototype.autoloadUsers = function () { fs.watch( - Helper.getUsersPath(), + Config.getUsersPath(), _.debounce( () => { const loaded = this.clients.map((c) => c.name); @@ -145,12 +145,12 @@ ClientManager.prototype.loadUser = function (name) { }; ClientManager.prototype.getUsers = function () { - if (!fs.existsSync(Helper.getUsersPath())) { + if (!fs.existsSync(Config.getUsersPath())) { return []; } return fs - .readdirSync(Helper.getUsersPath()) + .readdirSync(Config.getUsersPath()) .filter((file) => file.endsWith(".json")) .map((file) => file.slice(0, -5)); }; @@ -160,7 +160,7 @@ ClientManager.prototype.addUser = function (name, password, enableLog) { throw new Error(`${name} is an invalid username.`); } - const userPath = Helper.getUserConfigPath(name); + const userPath = Config.getUserConfigPath(name); if (fs.existsSync(userPath)) { log.error(`User ${colors.green(name)} already exists.`); @@ -182,7 +182,7 @@ ClientManager.prototype.addUser = function (name, password, enableLog) { } try { - const userFolderStat = fs.statSync(Helper.getUsersPath()); + const userFolderStat = fs.statSync(Config.getUsersPath()); const userFileStat = fs.statSync(userPath); if ( @@ -231,7 +231,7 @@ ClientManager.prototype.saveUser = function (client, callback) { return; } - const pathReal = Helper.getUserConfigPath(client.name); + const pathReal = Config.getUserConfigPath(client.name); const pathTemp = pathReal + ".tmp"; try { @@ -253,7 +253,7 @@ ClientManager.prototype.saveUser = function (client, callback) { }; ClientManager.prototype.removeUser = function (name) { - const userPath = Helper.getUserConfigPath(name); + const userPath = Config.getUserConfigPath(name); if (!fs.existsSync(userPath)) { log.error(`Tried to remove non-existing user ${colors.green(name)}.`); @@ -266,7 +266,7 @@ ClientManager.prototype.removeUser = function (name) { }; function readUserConfig(name) { - const userPath = Helper.getUserConfigPath(name); + const userPath = Config.getUserConfigPath(name); if (!fs.existsSync(userPath)) { log.error(`Tried to read non-existing user ${colors.green(name)}`); diff --git a/src/command-line/index.js b/src/command-line/index.js index 0ad1a71d..cfea187e 100644 --- a/src/command-line/index.js +++ b/src/command-line/index.js @@ -6,6 +6,7 @@ const path = require("path"); const colors = require("chalk"); const program = require("commander"); const Helper = require("../helper"); +const Config = require("../config"); const Utils = require("./utils"); program @@ -20,7 +21,7 @@ program // Parse options from `argv` returning `argv` void of these options. const argvWithoutOptions = program.parseOptions(process.argv); -Helper.setHome(process.env.THELOUNGE_HOME || Utils.defaultHome()); +Config.setHome(process.env.THELOUNGE_HOME || Utils.defaultHome()); // Check config file owner and warn if we're running under a different user try { @@ -34,11 +35,11 @@ try { createPackagesFolder(); // Merge config key-values passed as CLI options into the main config -Helper.mergeConfig(Helper.config, program.opts().config); +Config.merge(program.opts().config); require("./start"); -if (!Helper.config.public) { +if (!Config.values.public) { require("./users"); } @@ -56,7 +57,7 @@ require("./outdated"); program.parse(argvWithoutOptions.operands.concat(argvWithoutOptions.unknown)); function createPackagesFolder() { - const packagesPath = Helper.getPackagesPath(); + const packagesPath = Config.getPackagesPath(); const packagesConfig = path.join(packagesPath, "package.json"); // Create node_modules folder, otherwise yarn will start walking upwards to find one @@ -95,7 +96,7 @@ function verifyFileOwner() { ); } - const configStat = fs.statSync(path.join(Helper.getHomePath(), "config.js")); + const configStat = fs.statSync(path.join(Config.getHomePath(), "config.js")); if (configStat && configStat.uid !== uid) { log.warn( diff --git a/src/command-line/install.js b/src/command-line/install.js index bc30a851..e85e8fed 100644 --- a/src/command-line/install.js +++ b/src/command-line/install.js @@ -5,6 +5,7 @@ const colors = require("chalk"); const semver = require("semver"); const program = require("commander"); const Helper = require("../helper"); +const Config = require("../config"); const Utils = require("./utils"); program @@ -17,8 +18,8 @@ program const path = require("path"); const packageJson = require("package-json"); - if (!fs.existsSync(Helper.getConfigPath())) { - log.error(`${Helper.getConfigPath()} does not exist.`); + if (!fs.existsSync(Config.getConfigPath())) { + log.error(`${Config.getConfigPath()} does not exist.`); return; } diff --git a/src/command-line/start.js b/src/command-line/start.js index 524b6503..2ccb3a3a 100644 --- a/src/command-line/start.js +++ b/src/command-line/start.js @@ -5,7 +5,7 @@ const colors = require("chalk"); const fs = require("fs"); const path = require("path"); const program = require("commander"); -const Helper = require("../helper"); +const Config = require("../config"); const Utils = require("./utils"); program @@ -21,15 +21,15 @@ program }); function initalizeConfig() { - if (!fs.existsSync(Helper.getConfigPath())) { - fs.mkdirSync(Helper.getHomePath(), {recursive: true}); - fs.chmodSync(Helper.getHomePath(), "0700"); + if (!fs.existsSync(Config.getConfigPath())) { + fs.mkdirSync(Config.getHomePath(), {recursive: true}); + fs.chmodSync(Config.getHomePath(), "0700"); fs.copyFileSync( path.resolve(path.join(__dirname, "..", "..", "defaults", "config.js")), - Helper.getConfigPath() + Config.getConfigPath() ); - log.info(`Configuration file created at ${colors.green(Helper.getConfigPath())}.`); + log.info(`Configuration file created at ${colors.green(Config.getConfigPath())}.`); } - fs.mkdirSync(Helper.getUsersPath(), {recursive: true, mode: 0o700}); + fs.mkdirSync(Config.getUsersPath(), {recursive: true, mode: 0o700}); } diff --git a/src/command-line/uninstall.js b/src/command-line/uninstall.js index 8686e668..a7565bc9 100644 --- a/src/command-line/uninstall.js +++ b/src/command-line/uninstall.js @@ -3,7 +3,7 @@ const log = require("../log"); const colors = require("chalk"); const program = require("commander"); -const Helper = require("../helper"); +const Config = require("../config"); const Utils = require("./utils"); program @@ -14,7 +14,7 @@ program const fs = require("fs"); const path = require("path"); - const packagesConfig = path.join(Helper.getPackagesPath(), "package.json"); + const packagesConfig = path.join(Config.getPackagesPath(), "package.json"); const packages = JSON.parse(fs.readFileSync(packagesConfig, "utf-8")); if ( diff --git a/src/command-line/upgrade.js b/src/command-line/upgrade.js index 6911ad72..57cc65b4 100644 --- a/src/command-line/upgrade.js +++ b/src/command-line/upgrade.js @@ -3,7 +3,7 @@ const log = require("../log"); const colors = require("chalk"); const program = require("commander"); -const Helper = require("../helper"); +const Config = require("../config"); const Utils = require("./utils"); program @@ -15,7 +15,7 @@ program const path = require("path"); // Get paths to the location of packages directory - const packagesConfig = path.join(Helper.getPackagesPath(), "package.json"); + const packagesConfig = path.join(Config.getPackagesPath(), "package.json"); const packagesList = JSON.parse(fs.readFileSync(packagesConfig, "utf-8")).dependencies; const argsList = ["upgrade", "--latest"]; diff --git a/src/command-line/users/add.js b/src/command-line/users/add.js index 4f3b9ba7..98140e16 100644 --- a/src/command-line/users/add.js +++ b/src/command-line/users/add.js @@ -5,6 +5,7 @@ const colors = require("chalk"); const program = require("commander"); const fs = require("fs"); const Helper = require("../../helper"); +const Config = require("../../config"); const Utils = require("../utils"); program @@ -14,8 +15,8 @@ program .option("--password [password]", "new password, will be prompted if not specified") .option("--save-logs", "if password is specified, this enables saving logs to disk") .action(function (name, cmdObj) { - if (!fs.existsSync(Helper.getUsersPath())) { - log.error(`${Helper.getUsersPath()} does not exist.`); + if (!fs.existsSync(Config.getUsersPath())) { + log.error(`${Config.getUsersPath()} does not exist.`); return; } @@ -76,5 +77,5 @@ function add(manager, name, password, enableLog) { manager.addUser(name, hash, enableLog); log.info(`User ${colors.bold(name)} created.`); - log.info(`User file located at ${colors.green(Helper.getUserConfigPath(name))}.`); + log.info(`User file located at ${colors.green(Config.getUserConfigPath(name))}.`); } diff --git a/src/command-line/users/edit.js b/src/command-line/users/edit.js index fc28f35d..0e9f4705 100644 --- a/src/command-line/users/edit.js +++ b/src/command-line/users/edit.js @@ -5,16 +5,16 @@ const program = require("commander"); const child = require("child_process"); const colors = require("chalk"); const fs = require("fs"); -const Helper = require("../../helper"); +const Config = require("../../config"); const Utils = require("../utils"); program .command("edit ") - .description(`Edit user file located at ${colors.green(Helper.getUserConfigPath(""))}`) + .description(`Edit user file located at ${colors.green(Config.getUserConfigPath(""))}`) .on("--help", Utils.extraHelp) .action(function (name) { - if (!fs.existsSync(Helper.getUsersPath())) { - log.error(`${Helper.getUsersPath()} does not exist.`); + if (!fs.existsSync(Config.getUsersPath())) { + log.error(`${Config.getUsersPath()} does not exist.`); return; } @@ -33,12 +33,12 @@ program const child_spawn = child.spawn( process.env.EDITOR || "vi", - [Helper.getUserConfigPath(name)], + [Config.getUserConfigPath(name)], {stdio: "inherit"} ); child_spawn.on("error", function () { log.error( - `Unable to open ${colors.green(Helper.getUserConfigPath(name))}. ${colors.bold( + `Unable to open ${colors.green(Config.getUserConfigPath(name))}. ${colors.bold( "$EDITOR" )} is not set, and ${colors.bold("vi")} was not found.` ); diff --git a/src/command-line/users/index.js b/src/command-line/users/index.js index b4784963..76ed999f 100644 --- a/src/command-line/users/index.js +++ b/src/command-line/users/index.js @@ -1,6 +1,6 @@ "use strict"; -if (!require("../../helper").config.ldap.enable) { +if (!require("../../config").values.ldap.enable) { require("./add"); require("./reset"); } diff --git a/src/command-line/users/remove.js b/src/command-line/users/remove.js index 4b47c407..840b69a8 100644 --- a/src/command-line/users/remove.js +++ b/src/command-line/users/remove.js @@ -4,7 +4,7 @@ const log = require("../../log"); const colors = require("chalk"); const program = require("commander"); const fs = require("fs"); -const Helper = require("../../helper"); +const Config = require("../../config"); const Utils = require("../utils"); program @@ -12,8 +12,8 @@ program .description("Remove an existing user") .on("--help", Utils.extraHelp) .action(function (name) { - if (!fs.existsSync(Helper.getUsersPath())) { - log.error(`${Helper.getUsersPath()} does not exist.`); + if (!fs.existsSync(Config.getUsersPath())) { + log.error(`${Config.getUsersPath()} does not exist.`); return; } diff --git a/src/command-line/users/reset.js b/src/command-line/users/reset.js index bcf9ea76..89a7f2f5 100644 --- a/src/command-line/users/reset.js +++ b/src/command-line/users/reset.js @@ -5,6 +5,7 @@ const colors = require("chalk"); const program = require("commander"); const fs = require("fs"); const Helper = require("../../helper"); +const Config = require("../../config"); const Utils = require("../utils"); program @@ -13,8 +14,8 @@ program .on("--help", Utils.extraHelp) .option("--password [password]", "new password, will be prompted if not specified") .action(function (name, cmdObj) { - if (!fs.existsSync(Helper.getUsersPath())) { - log.error(`${Helper.getUsersPath()} does not exist.`); + if (!fs.existsSync(Config.getUsersPath())) { + log.error(`${Config.getUsersPath()} does not exist.`); return; } @@ -52,7 +53,7 @@ program }); function change(name, password) { - const pathReal = Helper.getUserConfigPath(name); + const pathReal = Config.getUserConfigPath(name); const pathTemp = pathReal + ".tmp"; const user = JSON.parse(fs.readFileSync(pathReal, "utf-8")); diff --git a/src/command-line/utils.js b/src/command-line/utils.js index 859d2991..c6cec2e3 100644 --- a/src/command-line/utils.js +++ b/src/command-line/utils.js @@ -5,6 +5,7 @@ const log = require("../log"); const colors = require("chalk"); const fs = require("fs"); const Helper = require("../helper"); +const Config = require("../config"); const path = require("path"); let home; @@ -91,7 +92,7 @@ class Utils { static executeYarnCommand(command, ...parameters) { const yarn = require.resolve("yarn/bin/yarn.js"); - const packagesPath = Helper.getPackagesPath(); + const packagesPath = Config.getPackagesPath(); const cachePath = path.join(packagesPath, "package_manager_cache"); const staticParameters = [ diff --git a/src/config.js b/src/config.js new file mode 100644 index 00000000..e7860f8f --- /dev/null +++ b/src/config.js @@ -0,0 +1,182 @@ +"use strict"; + +const path = require("path"); +const fs = require("fs"); +const os = require("os"); +const _ = require("lodash"); +const colors = require("chalk"); +const log = require("./log"); +const Helper = require("./helper"); + +class Config { + values = require(path.resolve(path.join(__dirname, "..", "defaults", "config.js"))); + #homePath; + + getHomePath() { + return this.#homePath; + } + + getConfigPath() { + return path.join(this.#homePath, "config.js"); + } + + getUserLogsPath() { + return path.join(this.#homePath, "logs"); + } + + getStoragePath() { + return path.join(this.#homePath, "storage"); + } + + getFileUploadPath() { + return path.join(this.#homePath, "uploads"); + } + + getUsersPath() { + return path.join(this.#homePath, "users"); + } + + getUserConfigPath(name) { + return path.join(this.getUsersPath(), `${name}.json`); + } + + getClientCertificatesPath() { + return path.join(this.#homePath, "certificates"); + } + + getPackagesPath() { + return path.join(this.#homePath, "packages"); + } + + getPackageModulePath(packageName) { + return path.join(this.getPackagesPath(), "node_modules", packageName); + } + + getDefaultNick() { + if (!this.values.defaults.nick) { + return "thelounge"; + } + + return this.values.defaults.nick.replace(/%/g, () => Math.floor(Math.random() * 10)); + } + + merge(newConfig) { + this._merge_config_objects(this.values, newConfig); + } + + _merge_config_objects(oldConfig, newConfig) { + // semi exposed function so that we can test it + // it mutates the oldConfig, but returns it as a convenience for testing + + for (const key in newConfig) { + if (!Object.prototype.hasOwnProperty.call(oldConfig, key)) { + log.warn(`Unknown key "${colors.bold(key)}", please verify your config.`); + } + } + + return _.mergeWith(oldConfig, newConfig, (objValue, srcValue, key) => { + // Do not override config variables if the type is incorrect (e.g. object changed into a string) + if ( + typeof objValue !== "undefined" && + objValue !== null && + typeof objValue !== typeof srcValue + ) { + log.warn(`Incorrect type for "${colors.bold(key)}", please verify your config.`); + + return objValue; + } + + // For arrays, simply override the value with user provided one. + if (_.isArray(objValue)) { + return srcValue; + } + }); + } + + setHome(newPath) { + this.#homePath = Helper.expandHome(newPath); + + // Reload config from new home location + const configPath = this.getConfigPath(); + + if (fs.existsSync(configPath)) { + const userConfig = require(configPath); + + if (_.isEmpty(userConfig)) { + log.warn( + `The file located at ${colors.green( + configPath + )} does not appear to expose anything.` + ); + log.warn( + `Make sure it is non-empty and the configuration is exported using ${colors.bold( + "module.exports = { ... }" + )}.` + ); + log.warn("Using default configuration..."); + } + + this.merge(userConfig); + } + + if (this.values.fileUpload.baseUrl) { + try { + new URL("test/file.png", this.values.fileUpload.baseUrl); + } catch (e) { + this.values.fileUpload.baseUrl = null; + + log.warn(`The ${colors.bold("fileUpload.baseUrl")} you specified is invalid: ${e}`); + } + } + + const manifestPath = path.resolve( + path.join(__dirname, "..", "public", "thelounge.webmanifest") + ); + + // Check if manifest exists, if not, the app most likely was not built + if (!fs.existsSync(manifestPath)) { + log.error( + `The client application was not built. Run ${colors.bold( + "NODE_ENV=production yarn build" + )} to resolve this.` + ); + process.exit(1); + } + + // Load theme color from the web manifest + const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); + this.values.themeColor = manifest.theme_color; + + // log dir probably shouldn't be world accessible. + // Create it with the desired permission bits if it doesn't exist yet. + let logsStat = undefined; + + const userLogsPath = this.getUserLogsPath(); + + try { + logsStat = fs.statSync(userLogsPath); + } catch { + // ignored on purpose, node v14.17.0 will give us {throwIfNoEntry: false} + } + + if (!logsStat) { + try { + fs.mkdirSync(userLogsPath, {recursive: true, mode: 0o750}); + } catch (e) { + log.error("Unable to create logs directory", e); + } + } else if (logsStat && logsStat.mode & 0o001) { + log.warn( + "contents of", + userLogsPath, + "can be accessed by any user, the log files may be exposed" + ); + + if (os.platform() !== "win32") { + log.warn(`run \`chmod o-x ${userLogsPath}\` to correct it`); + } + } + } +} + +module.exports = new Config(); diff --git a/src/helper.js b/src/helper.js index 58316b97..4777a10c 100644 --- a/src/helper.js +++ b/src/helper.js @@ -2,45 +2,20 @@ const pkg = require("../package.json"); const _ = require("lodash"); -const log = require("./log"); const path = require("path"); const os = require("os"); const fs = require("fs"); const net = require("net"); const bcrypt = require("bcryptjs"); -const colors = require("chalk"); const crypto = require("crypto"); -let homePath; -let configPath; -let usersPath; -let storagePath; -let packagesPath; -let fileUploadPath; -let userLogsPath; -let clientCertificatesPath; - const Helper = { - config: null, expandHome, - getHomePath, - getPackagesPath, - getPackageModulePath, - getStoragePath, - getConfigPath, - getFileUploadPath, - getUsersPath, - getUserConfigPath, - getUserLogsPath, - getClientCertificatesPath, - setHome, getVersion, getVersionCacheBust, getVersionNumber, getGitCommit, ip2hex, - mergeConfig, - getDefaultNick, parseHostmask, compareHostmask, compareWithWildcard, @@ -54,8 +29,6 @@ const Helper = { module.exports = Helper; -Helper.config = require(path.resolve(path.join(__dirname, "..", "defaults", "config.js"))); - function getVersion() { const gitCommit = getGitCommit(); const version = `v${pkg.version}`; @@ -100,134 +73,6 @@ function getVersionCacheBust() { return hash.substring(0, 10); } -function setHome(newPath) { - homePath = expandHome(newPath); - configPath = path.join(homePath, "config.js"); - usersPath = path.join(homePath, "users"); - storagePath = path.join(homePath, "storage"); - fileUploadPath = path.join(homePath, "uploads"); - packagesPath = path.join(homePath, "packages"); - userLogsPath = path.join(homePath, "logs"); - clientCertificatesPath = path.join(homePath, "certificates"); - - // Reload config from new home location - if (fs.existsSync(configPath)) { - const userConfig = require(configPath); - - if (_.isEmpty(userConfig)) { - log.warn( - `The file located at ${colors.green( - configPath - )} does not appear to expose anything.` - ); - log.warn( - `Make sure it is non-empty and the configuration is exported using ${colors.bold( - "module.exports = { ... }" - )}.` - ); - log.warn("Using default configuration..."); - } - - mergeConfig(this.config, userConfig); - } - - if (this.config.fileUpload.baseUrl) { - try { - new URL("test/file.png", this.config.fileUpload.baseUrl); - } catch (e) { - this.config.fileUpload.baseUrl = null; - - log.warn(`The ${colors.bold("fileUpload.baseUrl")} you specified is invalid: ${e}`); - } - } - - const manifestPath = path.resolve( - path.join(__dirname, "..", "public", "thelounge.webmanifest") - ); - - // Check if manifest exists, if not, the app most likely was not built - if (!fs.existsSync(manifestPath)) { - log.error( - `The client application was not built. Run ${colors.bold( - "NODE_ENV=production yarn build" - )} to resolve this.` - ); - process.exit(1); - } - - // Load theme color from the web manifest - const manifest = JSON.parse(fs.readFileSync(manifestPath, "utf8")); - this.config.themeColor = manifest.theme_color; - - // log dir probably shouldn't be world accessible. - // Create it with the desired permission bits if it doesn't exist yet. - let logsStat = undefined; - - try { - logsStat = fs.statSync(userLogsPath); - } catch { - // ignored on purpose, node v14.17.0 will give us {throwIfNoEntry: false} - } - - if (!logsStat) { - try { - fs.mkdirSync(userLogsPath, {recursive: true, mode: 0o750}); - } catch (e) { - log.error("Unable to create logs directory", e); - } - } else if (logsStat && logsStat.mode & 0o001) { - log.warn( - "contents of", - userLogsPath, - "can be accessed by any user, the log files may be exposed" - ); - - if (os.platform() !== "win32") { - log.warn(`run \`chmod o-x ${userLogsPath}\` to correct it`); - } - } -} - -function getHomePath() { - return homePath; -} - -function getConfigPath() { - return configPath; -} - -function getFileUploadPath() { - return fileUploadPath; -} - -function getUsersPath() { - return usersPath; -} - -function getUserConfigPath(name) { - return path.join(usersPath, name + ".json"); -} - -function getUserLogsPath() { - return userLogsPath; -} - -function getClientCertificatesPath() { - return clientCertificatesPath; -} - -function getStoragePath() { - return storagePath; -} - -function getPackagesPath() { - return packagesPath; -} - -function getPackageModulePath(packageName) { - return path.join(Helper.getPackagesPath(), "node_modules", packageName); -} - function ip2hex(address) { // no ipv6 support if (!net.isIPv4(address)) { @@ -271,40 +116,6 @@ function passwordCompare(password, expected) { return bcrypt.compare(password, expected); } -function getDefaultNick() { - if (!this.config.defaults.nick) { - return "thelounge"; - } - - return this.config.defaults.nick.replace(/%/g, () => Math.floor(Math.random() * 10)); -} - -function mergeConfig(oldConfig, newConfig) { - for (const key in newConfig) { - if (!Object.prototype.hasOwnProperty.call(oldConfig, key)) { - log.warn(`Unknown key "${colors.bold(key)}", please verify your config.`); - } - } - - return _.mergeWith(oldConfig, newConfig, (objValue, srcValue, key) => { - // Do not override config variables if the type is incorrect (e.g. object changed into a string) - if ( - typeof objValue !== "undefined" && - objValue !== null && - typeof objValue !== typeof srcValue - ) { - log.warn(`Incorrect type for "${colors.bold(key)}", please verify your config.`); - - return objValue; - } - - // For arrays, simply override the value with user provided one. - if (_.isArray(objValue)) { - return srcValue; - } - }); -} - function parseHostmask(hostmask) { let nick = ""; let ident = "*"; diff --git a/src/identification.js b/src/identification.js index 5ddc06cf..59ebc590 100644 --- a/src/identification.js +++ b/src/identification.js @@ -5,20 +5,21 @@ const fs = require("fs"); const net = require("net"); const colors = require("chalk"); const Helper = require("./helper"); +const Config = require("./config"); class Identification { constructor(startedCallback) { this.connectionId = 0; this.connections = new Map(); - if (typeof Helper.config.oidentd === "string") { - this.oidentdFile = Helper.expandHome(Helper.config.oidentd); + if (typeof Config.values.oidentd === "string") { + this.oidentdFile = Helper.expandHome(Config.values.oidentd); log.info(`Oidentd file: ${colors.green(this.oidentdFile)}`); this.refresh(); } - if (Helper.config.identd.enable) { + if (Config.values.identd.enable) { if (this.oidentdFile) { log.warn( "Using both identd and oidentd at the same time, this is most likely not intended." @@ -33,8 +34,8 @@ class Identification { server.listen( { - port: Helper.config.identd.port || 113, - host: Helper.config.bind, + port: Config.values.identd.port || 113, + host: Config.values.bind, }, () => { const address = server.address(); diff --git a/src/models/chan.js b/src/models/chan.js index 5191d898..451cdc6a 100644 --- a/src/models/chan.js +++ b/src/models/chan.js @@ -2,7 +2,7 @@ const _ = require("lodash"); const log = require("../log"); -const Helper = require("../helper"); +const Config = require("../config"); const User = require("./user"); const Msg = require("./msg"); const storage = require("../plugins/storage"); @@ -81,7 +81,7 @@ Chan.prototype.pushMessage = function (client, msg, increasesUnread) { // Never store messages in public mode as the session // is completely destroyed when the page gets closed - if (Helper.config.public) { + if (Config.values.public) { return; } @@ -92,19 +92,19 @@ Chan.prototype.pushMessage = function (client, msg, increasesUnread) { this.writeUserLog(client, msg); - if (Helper.config.maxHistory >= 0 && this.messages.length > Helper.config.maxHistory) { - const deleted = this.messages.splice(0, this.messages.length - Helper.config.maxHistory); + if (Config.values.maxHistory >= 0 && this.messages.length > Config.values.maxHistory) { + const deleted = this.messages.splice(0, this.messages.length - Config.values.maxHistory); // If maxHistory is 0, image would be dereferenced before client had a chance to retrieve it, // so for now, just don't implement dereferencing for this edge case. - if (Helper.config.maxHistory > 0) { + if (Config.values.maxHistory > 0) { this.dereferencePreviews(deleted); } } }; Chan.prototype.dereferencePreviews = function (messages) { - if (!Helper.config.prefetch || !Helper.config.prefetchStorage) { + if (!Config.values.prefetch || !Config.values.prefetchStorage) { return; } diff --git a/src/models/network.js b/src/models/network.js index b882b181..1ceee867 100644 --- a/src/models/network.js +++ b/src/models/network.js @@ -7,6 +7,7 @@ const Chan = require("./chan"); const Msg = require("./msg"); const Prefix = require("./prefix"); const Helper = require("../helper"); +const Config = require("../config"); const STSPolicies = require("../plugins/sts"); const ClientCertificate = require("../plugins/clientCertificate"); @@ -92,7 +93,7 @@ Network.prototype.validate = function (client) { // Remove new lines and limit length const cleanString = (str) => str.replace(/[\x00\r\n]/g, "").substring(0, 300); - this.setNick(cleanNick(String(this.nick || Helper.getDefaultNick()))); + this.setNick(cleanNick(String(this.nick || Config.getDefaultNick()))); if (!this.username) { // If username is empty, make one from the provided nick @@ -133,28 +134,28 @@ Network.prototype.validate = function (client) { this.sasl = ""; } - if (Helper.config.lockNetwork) { + if (Config.values.lockNetwork) { // This check is needed to prevent invalid user configurations if ( - !Helper.config.public && + !Config.values.public && this.host && this.host.length > 0 && - this.host !== Helper.config.defaults.host + this.host !== Config.values.defaults.host ) { error(this, `The hostname you specified (${this.host}) is not allowed.`); return false; } - if (Helper.config.public) { - this.name = Helper.config.defaults.name; + if (Config.values.public) { + this.name = Config.values.defaults.name; // Sync lobby channel name - this.channels[0].name = Helper.config.defaults.name; + this.channels[0].name = Config.values.defaults.name; } - this.host = Helper.config.defaults.host; - this.port = Helper.config.defaults.port; - this.tls = Helper.config.defaults.tls; - this.rejectUnauthorized = Helper.config.defaults.rejectUnauthorized; + this.host = Config.values.defaults.host; + this.port = Config.values.defaults.port; + this.tls = Config.values.defaults.tls; + this.rejectUnauthorized = Config.values.defaults.rejectUnauthorized; } if (this.host.length === 0) { @@ -181,7 +182,7 @@ Network.prototype.validate = function (client) { Network.prototype.createIrcFramework = function (client) { this.irc = new IrcFramework.Client({ version: false, // We handle it ourselves - outgoing_addr: Helper.config.bind, + outgoing_addr: Config.values.bind, enable_chghost: true, enable_echomessage: true, enable_setname: true, @@ -205,7 +206,7 @@ Network.prototype.setIrcFrameworkOptions = function (client) { this.irc.options.port = this.port; this.irc.options.password = this.password; this.irc.options.nick = this.nick; - this.irc.options.username = Helper.config.useHexIp + this.irc.options.username = Config.values.useHexIp ? Helper.ip2hex(client.config.browser.ip) : this.username; this.irc.options.gecos = this.realname; @@ -243,14 +244,14 @@ Network.prototype.setIrcFrameworkOptions = function (client) { Network.prototype.createWebIrc = function (client) { if ( - !Helper.config.webirc || - !Object.prototype.hasOwnProperty.call(Helper.config.webirc, this.host) + !Config.values.webirc || + !Object.prototype.hasOwnProperty.call(Config.values.webirc, this.host) ) { return null; } const webircObject = { - password: Helper.config.webirc[this.host], + password: Config.values.webirc[this.host], username: "thelounge", address: client.config.browser.ip, hostname: client.config.browser.hostname, @@ -263,9 +264,9 @@ Network.prototype.createWebIrc = function (client) { }; } - if (typeof Helper.config.webirc[this.host] === "function") { + if (typeof Config.values.webirc[this.host] === "function") { webircObject.password = null; - return Helper.config.webirc[this.host](webircObject, this); + return Config.values.webirc[this.host](webircObject, this); } return webircObject; @@ -462,7 +463,7 @@ Network.prototype.quit = function (quitMessage) { // https://ircv3.net/specs/extensions/sts#rescheduling-expiry-on-disconnect STSPolicies.refreshExpiration(this.host); - this.irc.quit(quitMessage || this.leaveMessage || Helper.config.leaveMessage); + this.irc.quit(quitMessage || this.leaveMessage || Config.values.leaveMessage); }; Network.prototype.exportForEdit = function () { @@ -486,7 +487,7 @@ Network.prototype.exportForEdit = function () { "proxyPassword", ]; - if (!Helper.config.lockNetwork) { + if (!Config.values.lockNetwork) { fieldsToReturn.push("host"); fieldsToReturn.push("port"); fieldsToReturn.push("tls"); diff --git a/src/plugins/auth/ldap.js b/src/plugins/auth/ldap.js index 1c93419f..952d9d14 100644 --- a/src/plugins/auth/ldap.js +++ b/src/plugins/auth/ldap.js @@ -1,12 +1,12 @@ "use strict"; const log = require("../../log"); -const Helper = require("../../helper"); +const Config = require("../../config"); const ldap = require("ldapjs"); const colors = require("chalk"); function ldapAuthCommon(user, bindDN, password, callback) { - const config = Helper.config; + const config = Config.values; const ldapclient = ldap.createClient({ url: config.ldap.url, @@ -35,7 +35,7 @@ function simpleLdapAuth(user, password, callback) { return callback(false); } - const config = Helper.config; + const config = Config.values; const userDN = user.replace(/([,\\/#+<>;"= ])/g, "\\$1"); const bindDN = `${config.ldap.primaryKey}=${userDN},${config.ldap.baseDN}`; @@ -53,7 +53,7 @@ function advancedLdapAuth(user, password, callback) { return callback(false); } - const config = Helper.config; + const config = Config.values; const userDN = user.replace(/([,\\/#+<>;"= ])/g, "\\$1"); const ldapclient = ldap.createClient({ @@ -132,7 +132,7 @@ function ldapAuth(manager, client, user, password, callback) { let auth; - if ("baseDN" in Helper.config.ldap) { + if ("baseDN" in Config.values.ldap) { auth = simpleLdapAuth; } else { auth = advancedLdapAuth; @@ -147,7 +147,7 @@ function ldapAuth(manager, client, user, password, callback) { */ function advancedLdapLoadUsers(users, callbackLoadUser) { - const config = Helper.config; + const config = Config.values; const ldapclient = ldap.createClient({ url: config.ldap.url, @@ -212,7 +212,7 @@ function advancedLdapLoadUsers(users, callbackLoadUser) { } function ldapLoadUsers(users, callbackLoadUser) { - if ("baseDN" in Helper.config.ldap) { + if ("baseDN" in Config.values.ldap) { // simple LDAP case can't test for user existence without access to the // user's unhashed password, so indicate need to fallback to default // loadUser behaviour by returning false @@ -223,7 +223,7 @@ function ldapLoadUsers(users, callbackLoadUser) { } function isLdapEnabled() { - return !Helper.config.public && Helper.config.ldap.enable; + return !Config.values.public && Config.values.ldap.enable; } module.exports = { diff --git a/src/plugins/clientCertificate.js b/src/plugins/clientCertificate.js index ba5617c3..eb76d97e 100644 --- a/src/plugins/clientCertificate.js +++ b/src/plugins/clientCertificate.js @@ -5,7 +5,7 @@ const fs = require("fs"); const crypto = require("crypto"); const {md, pki} = require("node-forge"); const log = require("../log"); -const Helper = require("../helper"); +const Config = require("../config"); module.exports = { get, @@ -13,11 +13,11 @@ module.exports = { }; function get(uuid) { - if (Helper.config.public) { + if (Config.values.public) { return null; } - const folderPath = Helper.getClientCertificatesPath(); + const folderPath = Config.getClientCertificatesPath(); const paths = getPaths(folderPath, uuid); if (!fs.existsSync(paths.privateKeyPath) || !fs.existsSync(paths.certificatePath)) { @@ -37,11 +37,11 @@ function get(uuid) { } function remove(uuid) { - if (Helper.config.public) { + if (Config.values.public) { return null; } - const paths = getPaths(Helper.getClientCertificatesPath(), uuid); + const paths = getPaths(Config.getClientCertificatesPath(), uuid); try { if (fs.existsSync(paths.privateKeyPath)) { diff --git a/src/plugins/inputs/part.js b/src/plugins/inputs/part.js index 988dfba5..00c78893 100644 --- a/src/plugins/inputs/part.js +++ b/src/plugins/inputs/part.js @@ -2,7 +2,7 @@ const Msg = require("../../models/msg"); const Chan = require("../../models/chan"); -const Helper = require("../../helper"); +const Config = require("../../config"); exports.commands = ["close", "leave", "part"]; exports.allowDisconnected = true; @@ -42,7 +42,7 @@ exports.input = function (network, chan, cmd, args) { ) { this.part(network, target); } else { - const partMessage = args.join(" ") || network.leaveMessage || Helper.config.leaveMessage; + const partMessage = args.join(" ") || network.leaveMessage || Config.values.leaveMessage; network.irc.part(target.name, partMessage); } diff --git a/src/plugins/irc-events/connection.js b/src/plugins/irc-events/connection.js index da4ba42f..608c6063 100644 --- a/src/plugins/irc-events/connection.js +++ b/src/plugins/irc-events/connection.js @@ -5,6 +5,7 @@ const log = require("../../log"); const Msg = require("../../models/msg"); const Chan = require("../../models/chan"); const Helper = require("../../helper"); +const Config = require("../../config"); module.exports = function (irc, network) { const client = this; @@ -93,7 +94,7 @@ module.exports = function (irc, network) { irc.on("raw socket connected", function (socket) { let ident = client.name || network.username; - if (Helper.config.useHexIp) { + if (Config.values.useHexIp) { ident = Helper.ip2hex(client.config.browser.ip); } @@ -138,7 +139,7 @@ module.exports = function (irc, network) { sendStatus(); }); - if (Helper.config.debug.ircFramework) { + if (Config.values.debug.ircFramework) { irc.on("debug", function (message) { log.debug( `[${client.name} (${client.id}) on ${network.name} (${network.uuid}]`, @@ -147,7 +148,7 @@ module.exports = function (irc, network) { }); } - if (Helper.config.debug.raw) { + if (Config.values.debug.raw) { irc.on("raw", function (message) { network.channels[0].pushMessage( client, diff --git a/src/plugins/irc-events/error.js b/src/plugins/irc-events/error.js index 29f95ab6..8bb49af6 100644 --- a/src/plugins/irc-events/error.js +++ b/src/plugins/irc-events/error.js @@ -1,7 +1,7 @@ "use strict"; const Msg = require("../../models/msg"); -const Helper = require("../../helper"); +const Config = require("../../config"); module.exports = function (irc, network) { const client = this; @@ -36,7 +36,7 @@ module.exports = function (irc, network) { irc.on("nick in use", function (data) { let message = data.nick + ": " + (data.reason || "Nickname is already in use."); - if (irc.connection.registered === false && !Helper.config.public) { + if (irc.connection.registered === false && !Config.values.public) { message += " An attempt to use it will be made when this nick quits."; // Clients usually get nick in use on connect when reconnecting to a network @@ -81,7 +81,7 @@ module.exports = function (irc, network) { lobby.pushMessage(client, msg, true); if (irc.connection.registered === false) { - irc.changeNick(Helper.getDefaultNick()); + irc.changeNick(Config.getDefaultNick()); } client.emit("nick", { diff --git a/src/plugins/irc-events/link.js b/src/plugins/irc-events/link.js index 0d7a5061..6bfa366b 100644 --- a/src/plugins/irc-events/link.js +++ b/src/plugins/irc-events/link.js @@ -4,7 +4,7 @@ const cheerio = require("cheerio"); const got = require("got"); const URL = require("url").URL; const mime = require("mime-types"); -const Helper = require("../../helper"); +const Config = require("../../config"); const {findLinksWithSchema} = require("../../../client/js/helpers/ircmessageparser/findLinks"); const storage = require("../storage"); const currentFetchPromises = new Map(); @@ -13,7 +13,7 @@ const mediaTypeRegex = /^(audio|video)\/.+/; const log = require("../../log"); module.exports = function (client, chan, msg, cleanText) { - if (!Helper.config.prefetch) { + if (!Config.values.prefetch) { return; } @@ -90,7 +90,7 @@ function parseHtml(preview, res, client) { preview.body = preview.body.substr(0, 300); } - if (!Helper.config.prefetchStorage && Helper.config.disableMediaPreview) { + if (!Config.values.prefetchStorage && Config.values.disableMediaPreview) { resolve(res); return; } @@ -113,7 +113,7 @@ function parseHtml(preview, res, client) { if ( resThumb !== null && imageTypeRegex.test(resThumb.type) && - resThumb.size <= Helper.config.prefetchMaxImageSize * 1024 + resThumb.size <= Config.values.prefetchMaxImageSize * 1024 ) { preview.thumbActualUrl = thumb; } @@ -130,7 +130,7 @@ function parseHtml(preview, res, client) { function parseHtmlMedia($, preview, client) { return new Promise((resolve, reject) => { - if (Helper.config.disableMediaPreview) { + if (Config.values.disableMediaPreview) { reject(); return; } @@ -226,14 +226,14 @@ function parse(msg, chan, preview, res, client) { case "image/jxl": case "image/webp": case "image/avif": - if (!Helper.config.prefetchStorage && Helper.config.disableMediaPreview) { + if (!Config.values.prefetchStorage && Config.values.disableMediaPreview) { return removePreview(msg, preview); } - if (res.size > Helper.config.prefetchMaxImageSize * 1024) { + if (res.size > Config.values.prefetchMaxImageSize * 1024) { preview.type = "error"; preview.error = "image-too-big"; - preview.maxSize = Helper.config.prefetchMaxImageSize * 1024; + preview.maxSize = Config.values.prefetchMaxImageSize * 1024; } else { preview.type = "image"; preview.thumbActualUrl = preview.link; @@ -259,7 +259,7 @@ function parse(msg, chan, preview, res, client) { break; } - if (Helper.config.disableMediaPreview) { + if (Config.values.disableMediaPreview) { return removePreview(msg, preview); } @@ -276,7 +276,7 @@ function parse(msg, chan, preview, res, client) { break; } - if (Helper.config.disableMediaPreview) { + if (Config.values.disableMediaPreview) { return removePreview(msg, preview); } @@ -301,7 +301,7 @@ function handlePreview(client, chan, msg, preview, res) { const thumb = preview.thumbActualUrl || ""; delete preview.thumbActualUrl; - if (!thumb.length || !Helper.config.prefetchStorage) { + if (!thumb.length || !Config.values.prefetchStorage) { preview.thumb = thumb; return emitPreview(client, chan, msg, preview); } @@ -382,7 +382,7 @@ function fetch(uri, headers) { return promise; } - const prefetchTimeout = Helper.config.prefetchTimeout; + const prefetchTimeout = Config.values.prefetchTimeout; if (!prefetchTimeout) { log.warn( @@ -394,7 +394,7 @@ function fetch(uri, headers) { let buffer = Buffer.from(""); let contentLength = 0; let contentType; - let limit = Helper.config.prefetchMaxImageSize * 1024; + let limit = Config.values.prefetchMaxImageSize * 1024; try { const gotStream = got.stream(uri, { @@ -415,7 +415,7 @@ function fetch(uri, headers) { // response is an image // if Content-Length header reports a size exceeding the prefetch limit, abort fetch // and if file is not to be stored we don't need to download further either - if (contentLength > limit || !Helper.config.prefetchStorage) { + if (contentLength > limit || !Config.values.prefetchStorage) { gotStream.destroy(); } } else if (mediaTypeRegex.test(contentType)) { @@ -426,8 +426,8 @@ function fetch(uri, headers) { // twitter.com sends opengraph meta tags within ~20kb of data for individual tweets, the default is set to 50. // for sites like Youtube the og tags are in the first 300K and hence this is configurable by the admin limit = - "prefetchMaxSearchSize" in Helper.config - ? Helper.config.prefetchMaxSearchSize * 1024 + "prefetchMaxSearchSize" in Config.values + ? Config.values.prefetchMaxSearchSize * 1024 : // set to the previous size if config option is unset 50 * 1024; } diff --git a/src/plugins/messageStorage/sqlite.js b/src/plugins/messageStorage/sqlite.js index 6ce93211..243d1ef8 100644 --- a/src/plugins/messageStorage/sqlite.js +++ b/src/plugins/messageStorage/sqlite.js @@ -3,7 +3,7 @@ const log = require("../../log"); const path = require("path"); const fs = require("fs"); -const Helper = require("../../helper"); +const Config = require("../../config"); const Msg = require("../../models/msg"); let sqlite3; @@ -11,7 +11,7 @@ let sqlite3; try { sqlite3 = require("sqlite3"); } catch (e) { - Helper.config.messageStorage = Helper.config.messageStorage.filter((item) => item !== "sqlite"); + Config.values.messageStorage = Config.values.messageStorage.filter((item) => item !== "sqlite"); log.error( "Unable to load sqlite3 module. See https://github.com/mapbox/node-sqlite3/wiki/Binaries" @@ -35,7 +35,7 @@ class MessageStorage { } enable() { - const logsPath = Helper.getUserLogsPath(); + const logsPath = Config.getUserLogsPath(); const sqlitePath = path.join(logsPath, `${this.client.name}.sqlite3`); try { @@ -165,12 +165,12 @@ class MessageStorage { * @param Chan channel - Channel object for which to load messages for */ getMessages(network, channel) { - if (!this.isEnabled || Helper.config.maxHistory === 0) { + if (!this.isEnabled || Config.values.maxHistory === 0) { return Promise.resolve([]); } // If unlimited history is specified, load 100k messages - const limit = Helper.config.maxHistory < 0 ? 100000 : Helper.config.maxHistory; + const limit = Config.values.maxHistory < 0 ? 100000 : Config.values.maxHistory; return new Promise((resolve, reject) => { this.database.serialize(() => diff --git a/src/plugins/messageStorage/text.js b/src/plugins/messageStorage/text.js index 2e13aa18..602aeeca 100644 --- a/src/plugins/messageStorage/text.js +++ b/src/plugins/messageStorage/text.js @@ -4,7 +4,7 @@ const log = require("../../log"); const fs = require("fs"); const path = require("path"); const filenamify = require("filenamify"); -const Helper = require("../../helper"); +const Config = require("../../config"); const Msg = require("../../models/msg"); class TextFileMessageStorage { @@ -31,7 +31,7 @@ class TextFileMessageStorage { } const logPath = path.join( - Helper.getUserLogsPath(), + Config.getUserLogsPath(), this.client.name, TextFileMessageStorage.getNetworkFolderName(network) ); @@ -117,7 +117,7 @@ class TextFileMessageStorage { } const logPath = path.join( - Helper.getUserLogsPath(), + Config.getUserLogsPath(), this.client.name, TextFileMessageStorage.getNetworkFolderName(network), TextFileMessageStorage.getChannelFileName(channel) diff --git a/src/plugins/packages/index.js b/src/plugins/packages/index.js index a3d99022..13d5a1be 100644 --- a/src/plugins/packages/index.js +++ b/src/plugins/packages/index.js @@ -6,6 +6,7 @@ const colors = require("chalk"); const path = require("path"); const semver = require("semver"); const Helper = require("../../helper"); +const Config = require("../../config"); const themes = require("./themes"); const packageMap = new Map(); const inputs = require("../inputs"); @@ -45,7 +46,7 @@ const packageApis = function (packageInfo) { client.inputLine({target: targetId, text: command}), }, Config: { - getConfig: () => Helper.config, + getConfig: () => Config.values, getPersistentStorageDir: getPersistentStorageDir.bind(this, packageInfo.packageName), }, Logger: { @@ -89,7 +90,7 @@ function getEnabledPackages(packageJson) { } function getPersistentStorageDir(packageName) { - const dir = path.join(Helper.getPackagesPath(), packageName); + const dir = path.join(Config.getPackagesPath(), packageName); fs.mkdirSync(dir, {recursive: true}); // we don't care if it already exists or not return dir; } @@ -99,7 +100,7 @@ function loadPackage(packageName) { let packageFile; try { - const packagePath = Helper.getPackageModulePath(packageName); + const packagePath = Config.getPackageModulePath(packageName); packageInfo = JSON.parse(fs.readFileSync(path.join(packagePath, "package.json"), "utf-8")); @@ -155,7 +156,7 @@ function loadPackage(packageName) { } function loadPackages() { - const packageJson = path.join(Helper.getPackagesPath(), "package.json"); + const packageJson = path.join(Config.getPackagesPath(), "package.json"); const packages = getEnabledPackages(packageJson); packages.forEach(loadPackage); @@ -193,7 +194,7 @@ async function outdated(cacheTimeout = TIME_TO_LIVE) { } // Get paths to the location of packages directory - const packagesPath = Helper.getPackagesPath(); + const packagesPath = Config.getPackagesPath(); const packagesConfig = path.join(packagesPath, "package.json"); const packagesList = JSON.parse(fs.readFileSync(packagesConfig, "utf-8")).dependencies; const argsList = [ diff --git a/src/plugins/packages/themes.js b/src/plugins/packages/themes.js index 24814523..ba422bc3 100644 --- a/src/plugins/packages/themes.js +++ b/src/plugins/packages/themes.js @@ -1,7 +1,7 @@ "use strict"; const fs = require("fs"); -const Helper = require("../../helper"); +const Config = require("../../config"); const path = require("path"); const _ = require("lodash"); const themes = new Map(); @@ -61,7 +61,7 @@ function makePackageThemeObject(moduleName, module) { } const themeColor = /^#[0-9A-F]{6}$/i.test(module.themeColor) ? module.themeColor : null; - const modulePath = Helper.getPackageModulePath(moduleName); + const modulePath = Config.getPackageModulePath(moduleName); return { displayName: module.name || moduleName, filename: path.join(modulePath, module.css), diff --git a/src/plugins/storage.js b/src/plugins/storage.js index 3c2d021b..6e9c8dd7 100644 --- a/src/plugins/storage.js +++ b/src/plugins/storage.js @@ -4,7 +4,7 @@ const log = require("../log"); const fs = require("fs"); const path = require("path"); const crypto = require("crypto"); -const helper = require("../helper"); +const Config = require("../config"); class Storage { constructor() { @@ -16,7 +16,7 @@ class Storage { // Deletes directory contents if the directory is not empty. // If the directory does not exist, it is created. - const dir = helper.getStoragePath(); + const dir = Config.getStoragePath(); let items; try { @@ -44,7 +44,7 @@ class Storage { this.references.delete(url); // Drop "storage/" from url and join it with full storage path - const filePath = path.join(helper.getStoragePath(), url.substring(8)); + const filePath = path.join(Config.getStoragePath(), url.substring(8)); fs.unlink(filePath, (err) => { if (err) { @@ -57,7 +57,7 @@ class Storage { const hash = crypto.createHash("sha256").update(data).digest("hex"); const a = hash.substring(0, 2); const b = hash.substring(2, 4); - const folder = path.join(helper.getStoragePath(), a, b); + const folder = path.join(Config.getStoragePath(), a, b); const filePath = path.join(folder, `${hash.substring(4)}.${extension}`); const url = `storage/${a}/${b}/${hash.substring(4)}.${extension}`; diff --git a/src/plugins/sts.js b/src/plugins/sts.js index 25164ee7..697af9ae 100644 --- a/src/plugins/sts.js +++ b/src/plugins/sts.js @@ -4,11 +4,11 @@ const _ = require("lodash"); const fs = require("fs"); const path = require("path"); const log = require("../log"); -const Helper = require("../helper"); +const Config = require("../config"); class STSPolicies { constructor() { - this.stsFile = path.join(Helper.getHomePath(), "sts-policies.json"); + this.stsFile = path.join(Config.getHomePath(), "sts-policies.json"); this.policies = new Map(); this.refresh = _.debounce(this.saveFile, 10000, {maxWait: 60000}); diff --git a/src/plugins/uploader.js b/src/plugins/uploader.js index ca921e21..79f8f195 100644 --- a/src/plugins/uploader.js +++ b/src/plugins/uploader.js @@ -1,6 +1,6 @@ "use strict"; -const Helper = require("../helper"); +const Config = require("../config"); const busboy = require("@fastify/busboy"); const {v4: uuidv4} = require("uuid"); const path = require("path"); @@ -86,7 +86,7 @@ class Uploader { } const folder = name.substring(0, 2); - const uploadPath = Helper.getFileUploadPath(); + const uploadPath = Config.getFileUploadPath(); const filePath = path.join(uploadPath, folder, name); let detectedMimeType = await Uploader.getFileType(filePath); @@ -207,7 +207,7 @@ class Uploader { // that already exists on disk do { randomName = crypto.randomBytes(8).toString("hex"); - destDir = path.join(Helper.getFileUploadPath(), randomName.substring(0, 2)); + destDir = path.join(Config.getFileUploadPath(), randomName.substring(0, 2)); destPath = path.join(destDir, randomName); } while (fs.existsSync(destPath)); @@ -228,8 +228,8 @@ class Uploader { busboyInstance.on("file", (fieldname, fileStream, filename) => { uploadUrl = `${randomName}/${encodeURIComponent(filename)}`; - if (Helper.config.fileUpload.baseUrl) { - uploadUrl = new URL(uploadUrl, Helper.config.fileUpload.baseUrl).toString(); + if (Config.values.fileUpload.baseUrl) { + uploadUrl = new URL(uploadUrl, Config.values.fileUpload.baseUrl).toString(); } else { uploadUrl = `uploads/${uploadUrl}`; } @@ -266,7 +266,7 @@ class Uploader { } static getMaxFileSize() { - const configOption = Helper.config.fileUpload.maxFileSize; + const configOption = Config.values.fileUpload.maxFileSize; // Busboy uses Infinity to allow unlimited file size if (configOption < 1) { diff --git a/src/plugins/webpush.js b/src/plugins/webpush.js index 09cfb81d..6f3fa3ef 100644 --- a/src/plugins/webpush.js +++ b/src/plugins/webpush.js @@ -5,11 +5,11 @@ const log = require("../log"); const fs = require("fs"); const path = require("path"); const WebPushAPI = require("web-push"); -const Helper = require("../helper"); +const Config = require("../config"); class WebPush { constructor() { - const vapidPath = path.join(Helper.getHomePath(), "vapid.json"); + const vapidPath = path.join(Config.getHomePath(), "vapid.json"); let vapidStat = undefined; diff --git a/src/server.js b/src/server.js index 640b8742..49c417a3 100644 --- a/src/server.js +++ b/src/server.js @@ -12,6 +12,7 @@ const io = require("socket.io"); const dns = require("dns"); const Uploader = require("./plugins/uploader"); const Helper = require("./helper"); +const Config = require("./config"); const colors = require("chalk"); const net = require("net"); const Identification = require("./identification"); @@ -35,7 +36,7 @@ module.exports = function (options = {}) { (Node.js ${colors.green(process.versions.node)} on ${colors.green(process.platform)} ${ process.arch })`); - log.info(`Configuration file: ${colors.green(Helper.getConfigPath())}`); + log.info(`Configuration file: ${colors.green(Config.getConfigPath())}`); const staticOptions = { redirect: false, @@ -57,9 +58,9 @@ module.exports = function (options = {}) { .get("/js/bundle.js.map", forceNoCacheRequest) .get("/css/style.css.map", forceNoCacheRequest) .use(express.static(path.join(__dirname, "..", "public"), staticOptions)) - .use("/storage/", express.static(Helper.getStoragePath(), staticOptions)); + .use("/storage/", express.static(Config.getStoragePath(), staticOptions)); - if (Helper.config.fileUpload.enable) { + if (Config.values.fileUpload.enable) { Uploader.router(app); } @@ -87,25 +88,25 @@ module.exports = function (options = {}) { return res.status(404).send("Not found"); } - const packagePath = Helper.getPackageModulePath(packageName); + const packagePath = Config.getPackageModulePath(packageName); return res.sendFile(path.join(packagePath, fileName)); }); let server = null; - if (Helper.config.public && (Helper.config.ldap || {}).enable) { + if (Config.values.public && (Config.values.ldap || {}).enable) { log.warn( "Server is public and set to use LDAP. Set to private mode if trying to use LDAP authentication." ); } - if (!Helper.config.https.enable) { + if (!Config.values.https.enable) { server = require("http"); server = server.createServer(app); } else { - const keyPath = Helper.expandHome(Helper.config.https.key); - const certPath = Helper.expandHome(Helper.config.https.certificate); - const caPath = Helper.expandHome(Helper.config.https.ca); + const keyPath = Helper.expandHome(Config.values.https.key); + const certPath = Helper.expandHome(Config.values.https.certificate); + const caPath = Helper.expandHome(Config.values.https.ca); if (!keyPath.length || !fs.existsSync(keyPath)) { log.error("Path to SSL key is invalid. Stopping server..."); @@ -135,12 +136,12 @@ module.exports = function (options = {}) { let listenParams; - if (typeof Helper.config.host === "string" && Helper.config.host.startsWith("unix:")) { - listenParams = Helper.config.host.replace(/^unix:/, ""); + if (typeof Config.values.host === "string" && Config.values.host.startsWith("unix:")) { + listenParams = Config.values.host.replace(/^unix:/, ""); } else { listenParams = { - port: Helper.config.port, - host: Helper.config.host, + port: Config.values.port, + host: Config.values.host, }; } @@ -150,7 +151,7 @@ module.exports = function (options = {}) { if (typeof listenParams === "string") { log.info("Available on socket " + colors.green(listenParams)); } else { - const protocol = Helper.config.https.enable ? "https" : "http"; + const protocol = Config.values.https.enable ? "https" : "http"; const address = server.address(); if (address.family === "IPv6") { @@ -160,7 +161,7 @@ module.exports = function (options = {}) { log.info( "Available at " + colors.green(`${protocol}://${address.address}:${address.port}/`) + - ` in ${colors.bold(Helper.config.public ? "public" : "private")} mode` + ` in ${colors.bold(Config.values.public ? "public" : "private")} mode` ); } @@ -168,14 +169,14 @@ module.exports = function (options = {}) { wsEngine: require("ws").Server, cookie: false, serveClient: false, - transports: Helper.config.transports, + transports: Config.values.transports, pingTimeout: 60000, }); sockets.on("connect", (socket) => { socket.on("error", (err) => log.error(`io socket error: ${err}`)); - if (Helper.config.public) { + if (Config.values.public) { performAuthentication.call(socket, {}); } else { socket.on("auth:perform", performAuthentication); @@ -186,17 +187,17 @@ module.exports = function (options = {}) { manager = new ClientManager(); packages.loadPackages(); - const defaultTheme = themes.getByName(Helper.config.theme); + const defaultTheme = themes.getByName(Config.values.theme); if (defaultTheme === undefined) { log.warn( `The specified default theme "${colors.red( - Helper.config.theme + Config.values.theme )}" does not exist, verify your config.` ); - Helper.config.theme = "default"; + Config.values.theme = "default"; } else if (defaultTheme.themeColor) { - Helper.config.themeColor = defaultTheme.themeColor; + Config.values.themeColor = defaultTheme.themeColor; } new Identification((identHandler, err) => { @@ -221,7 +222,7 @@ module.exports = function (options = {}) { // Close all client and IRC connections manager.clients.forEach((client) => client.quit()); - if (Helper.config.prefetchStorage) { + if (Config.values.prefetchStorage) { log.info("Clearing prefetch storage folder, this might take a while..."); require("./plugins/storage").emptyDir(); @@ -241,7 +242,7 @@ module.exports = function (options = {}) { process.on("SIGTERM", exitGracefully); // Clear storage folder after server starts successfully - if (Helper.config.prefetchStorage) { + if (Config.values.prefetchStorage) { require("./plugins/storage").emptyDir(); } @@ -265,7 +266,7 @@ function getClientLanguage(socket) { function getClientIp(socket) { let ip = socket.handshake.address || "127.0.0.1"; - if (Helper.config.reverseProxy) { + if (Config.values.reverseProxy) { const forwarded = (socket.handshake.headers["x-forwarded-for"] || "") .split(/\s*,\s*/) .filter(Boolean); @@ -281,7 +282,7 @@ function getClientIp(socket) { function getClientSecure(socket) { let secure = socket.handshake.secure; - if (Helper.config.reverseProxy && socket.handshake.headers["x-forwarded-proto"] === "https") { + if (Config.values.reverseProxy && socket.handshake.headers["x-forwarded-proto"] === "https") { secure = true; } @@ -310,7 +311,7 @@ function addSecurityHeaders(req, res, next) { // If prefetch is enabled, but storage is not, we have to allow mixed content // - https://user-images.githubusercontent.com is where we currently push our changelog screenshots // - data: is required for the HTML5 video player - if (Helper.config.prefetchStorage || !Helper.config.prefetch) { + if (Config.values.prefetchStorage || !Config.values.prefetch) { policies.push("img-src 'self' data: https://user-images.githubusercontent.com"); policies.unshift("block-all-mixed-content"); } else { @@ -367,7 +368,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { openChannel = client.lastActiveChannel; } - if (Helper.config.fileUpload.enable) { + if (Config.values.fileUpload.enable) { new Uploader(socket); } @@ -436,7 +437,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { } }); - if (!Helper.config.public && !Helper.config.ldap.enable) { + if (!Config.values.public && !Config.values.ldap.enable) { socket.on("change-password", (data) => { if (_.isPlainObject(data)) { const old = data.old_password; @@ -510,7 +511,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { // In public mode only one client can be connected, // so there's no need to handle msg:preview:toggle - if (!Helper.config.public) { + if (!Config.values.public) { socket.on("msg:preview:toggle", (data) => { if (_.isPlainObject(data)) { return; @@ -571,7 +572,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { client.mentions = []; }); - if (!Helper.config.public) { + if (!Config.values.public) { socket.on("push:register", (subscription) => { if (!Object.prototype.hasOwnProperty.call(client.config.sessions, token)) { return; @@ -614,7 +615,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { socket.on("sessions:get", sendSessionList); - if (!Helper.config.public) { + if (!Config.values.public) { socket.on("setting:set", (newSetting) => { if (!_.isPlainObject(newSetting)) { return; @@ -739,7 +740,7 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { socket.emit("commands", inputs.getCommands()); }; - if (Helper.config.public) { + if (Config.values.public) { sendInitEvent(null); } else if (token === null) { client.generateToken((newToken) => { @@ -757,16 +758,16 @@ function initializeClient(socket, client, token, lastMessage, openChannel) { } function getClientConfiguration() { - const config = _.pick(Helper.config, ["public", "lockNetwork", "useHexIp", "prefetch"]); + const config = _.pick(Config.values, ["public", "lockNetwork", "useHexIp", "prefetch"]); - config.fileUpload = Helper.config.fileUpload.enable; - config.ldapEnabled = Helper.config.ldap.enable; + config.fileUpload = Config.values.fileUpload.enable; + config.ldapEnabled = Config.values.ldap.enable; if (!config.lockNetwork) { - config.defaults = _.clone(Helper.config.defaults); + config.defaults = _.clone(Config.values.defaults); } else { // Only send defaults that are visible on the client - config.defaults = _.pick(Helper.config.defaults, [ + config.defaults = _.pick(Config.values.defaults, [ "name", "nick", "username", @@ -781,8 +782,8 @@ function getClientConfiguration() { config.version = pkg.version; config.gitCommit = Helper.getGitCommit(); config.themes = themes.getAll(); - config.defaultTheme = Helper.config.theme; - config.defaults.nick = Helper.getDefaultNick(); + config.defaultTheme = Config.values.theme; + config.defaults.nick = Config.getDefaultNick(); config.defaults.sasl = ""; config.defaults.saslAccount = ""; config.defaults.saslPassword = ""; @@ -795,7 +796,7 @@ function getClientConfiguration() { } function getServerConfiguration() { - const config = _.clone(Helper.config); + const config = _.clone(Config.values); config.stylesheets = packages.getStylesheets(); @@ -833,7 +834,7 @@ function performAuthentication(data) { }; // If webirc is enabled perform reverse dns lookup - if (Helper.config.webirc === null) { + if (Config.values.webirc === null) { return finalInit(); } @@ -844,7 +845,7 @@ function performAuthentication(data) { }); }; - if (Helper.config.public) { + if (Config.values.public) { client = new Client(manager); manager.clients.push(client); diff --git a/test/fixtures/env.js b/test/fixtures/env.js index 57adf7ad..dcdb1a25 100644 --- a/test/fixtures/env.js +++ b/test/fixtures/env.js @@ -3,7 +3,7 @@ const fs = require("fs"); const home = require("path").join(__dirname, ".thelounge"); -require("../../src/helper").setHome(home); +require("../../src/config").setHome(home); const STSPolicies = require("../../src/plugins/sts"); // Must be imported *after* setHome diff --git a/test/models/network.js b/test/models/network.js index 1b5a1ed1..d933439c 100644 --- a/test/models/network.js +++ b/test/models/network.js @@ -5,7 +5,7 @@ const Chan = require("../../src/models/chan"); const Msg = require("../../src/models/msg"); const User = require("../../src/models/user"); const Network = require("../../src/models/network"); -const Helper = require("../../src/helper"); +const Config = require("../../src/config"); const STSPolicies = require("../../src/plugins/sts"); const ClientCertificate = require("../../src/plugins/clientCertificate"); @@ -126,7 +126,7 @@ describe("Network", function () { describe("#validate()", function () { it("should set correct defaults", function () { - Helper.config.defaults.nick = ""; + Config.values.defaults.nick = ""; const network = new Network({ host: "localhost", @@ -147,10 +147,10 @@ describe("Network", function () { }); it("should enforce lockNetwork", function () { - Helper.config.lockNetwork = true; + Config.values.lockNetwork = true; // Make sure we lock in private mode - Helper.config.public = false; + Config.values.public = false; const network = new Network({ host: "", @@ -165,7 +165,7 @@ describe("Network", function () { expect(network.rejectUnauthorized).to.be.true; // Make sure we lock in public mode (also resets public=true for other tests) - Helper.config.public = true; + Config.values.public = true; const network2 = new Network({ host: "some.fake.tld", @@ -173,7 +173,7 @@ describe("Network", function () { expect(network2.validate()).to.be.true; expect(network2.host).to.equal("irc.example.com"); - Helper.config.lockNetwork = false; + Config.values.lockNetwork = false; }); it("should apply STS policies iff they match", function () { @@ -204,7 +204,7 @@ describe("Network", function () { }); it("should not remove client certs if TLS is disabled", function () { - Helper.config.public = false; + Config.values.public = false; const client = {idMsg: 1, emit() {}, messageStorage: []}; @@ -221,11 +221,11 @@ describe("Network", function () { expect(ClientCertificate.get(network.uuid)).to.deep.equal(client_cert); // Should be unchanged ClientCertificate.remove(network.uuid); - Helper.config.public = true; + Config.values.public = true; }); it("should not remove client certs if there is a STS policy", function () { - Helper.config.public = false; + Config.values.public = false; const client = {idMsg: 1, emit() {}, messageStorage: []}; STSPolicies.update("irc.example.com", 7000, 3600); @@ -243,13 +243,13 @@ describe("Network", function () { expect(ClientCertificate.get(network.uuid)).to.deep.equal(client_cert); // Should be unchanged ClientCertificate.remove(network.uuid); - Helper.config.public = true; + Config.values.public = true; }); }); describe("#createIrcFramework(client)", function () { it("should generate and use a client certificate when using SASL external", function () { - Helper.config.public = false; + Config.values.public = false; const client = {idMsg: 1, emit() {}}; STSPolicies.update("irc.example.com", 7000, 3600); @@ -265,7 +265,7 @@ describe("Network", function () { expect(network.irc.options.client_certificate).to.not.be.null; ClientCertificate.remove(network.uuid); - Helper.config.public = true; + Config.values.public = true; }); }); diff --git a/test/plugins/auth/ldap.js b/test/plugins/auth/ldap.js index 88f76365..da101e66 100644 --- a/test/plugins/auth/ldap.js +++ b/test/plugins/auth/ldap.js @@ -2,7 +2,7 @@ const log = require("../../../src/log"); const ldapAuth = require("../../../src/plugins/auth/ldap"); -const Helper = require("../../../src/helper"); +const Config = require("../../../src/config"); const ldap = require("ldapjs"); const expect = require("chai").expect; const stub = require("sinon").stub; @@ -23,7 +23,7 @@ function normalizeDN(dn) { function startLdapServer(callback) { const server = ldap.createServer(); - const searchConf = Helper.config.ldap.searchDN; + const searchConf = Config.values.ldap.searchDN; const userDN = primaryKey + "=" + user + "," + baseDN; // Two users are authorized: john doe and the root user in case of @@ -143,34 +143,34 @@ describe("LDAP authentication plugin", function () { }); beforeEach(function () { - Helper.config.public = false; - Helper.config.ldap.enable = true; - Helper.config.ldap.url = "ldap://localhost:" + String(serverPort); - Helper.config.ldap.primaryKey = primaryKey; + Config.values.public = false; + Config.values.ldap.enable = true; + Config.values.ldap.url = "ldap://localhost:" + String(serverPort); + Config.values.ldap.primaryKey = primaryKey; }); afterEach(function () { - Helper.config.public = true; - Helper.config.ldap.enable = false; + Config.values.public = true; + Config.values.ldap.enable = false; }); describe("LDAP authentication availability", function () { it("checks that the configuration is correctly tied to isEnabled()", function () { - Helper.config.ldap.enable = true; + Config.values.ldap.enable = true; expect(ldapAuth.isEnabled()).to.equal(true); - Helper.config.ldap.enable = false; + Config.values.ldap.enable = false; expect(ldapAuth.isEnabled()).to.equal(false); }); }); describe("Simple LDAP authentication (predefined DN pattern)", function () { - Helper.config.ldap.baseDN = baseDN; + Config.values.ldap.baseDN = baseDN; testLdapAuth(); }); describe("Advanced LDAP authentication (DN found by a prior search query)", function () { - delete Helper.config.ldap.baseDN; + delete Config.values.ldap.baseDN; testLdapAuth(); }); }); diff --git a/test/plugins/clientCertificate.js b/test/plugins/clientCertificate.js index 6330b62e..fad096a2 100644 --- a/test/plugins/clientCertificate.js +++ b/test/plugins/clientCertificate.js @@ -4,18 +4,18 @@ const fs = require("fs"); const path = require("path"); const {expect} = require("chai"); const ClientCertificate = require("../../src/plugins/clientCertificate"); -const Helper = require("../../src/helper"); +const Config = require("../../src/config"); describe("ClientCertificate", function () { it("should not generate a client certificate in public mode", function () { - Helper.config.public = true; + Config.values.public = true; const certificate = ClientCertificate.get("this-is-test-uuid"); expect(certificate).to.be.null; }); it("should generate a client certificate", function () { - Helper.config.public = false; + Config.values.public = false; const certificate = ClientCertificate.get("this-is-test-uuid"); expect(certificate.certificate).to.match(/^-----BEGIN CERTIFICATE-----/); @@ -25,18 +25,18 @@ describe("ClientCertificate", function () { expect(certificate2.certificate).to.equal(certificate.certificate); expect(certificate2.private_key).to.equal(certificate.private_key); - Helper.config.public = true; + Config.values.public = true; }); it("should remove the client certificate files", function () { - Helper.config.public = false; + Config.values.public = false; const privateKeyPath = path.join( - Helper.getClientCertificatesPath(), + Config.getClientCertificatesPath(), `this-is-test-uuid.pem` ); const certificatePath = path.join( - Helper.getClientCertificatesPath(), + Config.getClientCertificatesPath(), `this-is-test-uuid.crt` ); @@ -48,6 +48,6 @@ describe("ClientCertificate", function () { expect(fs.existsSync(privateKeyPath)).to.be.false; expect(fs.existsSync(certificatePath)).to.be.false; - Helper.config.public = true; + Config.values.public = true; }); }); diff --git a/test/plugins/link.js b/test/plugins/link.js index 9098d5c5..a121cdde 100644 --- a/test/plugins/link.js +++ b/test/plugins/link.js @@ -3,7 +3,7 @@ const path = require("path"); const expect = require("chai").expect; const util = require("../util"); -const Helper = require("../../src/helper"); +const Config = require("../../src/config"); const link = require("../../src/plugins/irc-events/link.js"); describe("Link plugin", function () { @@ -36,7 +36,7 @@ Vivamus bibendum vulputate tincidunt. Sed vitae ligula felis.`; this.irc = util.createClient(); this.network = util.createNetwork(); - Helper.config.prefetchStorage = false; + Config.values.prefetchStorage = false; }); afterEach(function (done) { @@ -224,11 +224,11 @@ Vivamus bibendum vulputate tincidunt. Sed vitae ligula felis.`; describe("test disableMediaPreview", function () { beforeEach(function (done) { - Helper.config.disableMediaPreview = true; + Config.values.disableMediaPreview = true; done(); }); afterEach(function (done) { - Helper.config.disableMediaPreview = false; + Config.values.disableMediaPreview = false; done(); }); it("should ignore og:image if disableMediaPreview", function (done) { diff --git a/test/plugins/sqlite.js b/test/plugins/sqlite.js index 4dadef14..35016522 100644 --- a/test/plugins/sqlite.js +++ b/test/plugins/sqlite.js @@ -5,7 +5,7 @@ const path = require("path"); const expect = require("chai").expect; const util = require("../util"); const Msg = require("../../src/models/msg"); -const Helper = require("../../src/helper"); +const Config = require("../../src/config"); const MessageStorage = require("../../src/plugins/messageStorage/sqlite.js"); describe("SQLite Message Storage", function () { @@ -13,7 +13,7 @@ describe("SQLite Message Storage", function () { this.timeout(util.isRunningOnCI() ? 25000 : 5000); this.slow(300); - const expectedPath = path.join(Helper.getHomePath(), "logs", "testUser.sqlite3"); + const expectedPath = path.join(Config.getHomePath(), "logs", "testUser.sqlite3"); let store; before(function (done) { @@ -34,7 +34,7 @@ describe("SQLite Message Storage", function () { // After tests run, remove the logs folder // so we return to the clean state fs.unlinkSync(expectedPath); - fs.rmdir(path.join(Helper.getHomePath(), "logs"), done); + fs.rmdir(path.join(Config.getHomePath(), "logs"), done); }); it("should resolve an empty array when disabled", function () { @@ -127,10 +127,10 @@ describe("SQLite Message Storage", function () { }); it("should retrieve latest LIMIT messages in order", function () { - const originalMaxHistory = Helper.config.maxHistory; + const originalMaxHistory = Config.values.maxHistory; try { - Helper.config.maxHistory = 2; + Config.values.maxHistory = 2; for (let i = 0; i < 200; ++i) { store.index( @@ -150,15 +150,15 @@ describe("SQLite Message Storage", function () { expect(messages.map((i) => i.text)).to.deep.equal(["msg 198", "msg 199"]); }); } finally { - Helper.config.maxHistory = originalMaxHistory; + Config.values.maxHistory = originalMaxHistory; } }); it("should search messages", function () { - const originalMaxHistory = Helper.config.maxHistory; + const originalMaxHistory = Config.values.maxHistory; try { - Helper.config.maxHistory = 2; + Config.values.maxHistory = 2; return store .search({ @@ -177,7 +177,7 @@ describe("SQLite Message Storage", function () { expect(messages.results.map((i) => i.text)).to.deep.equal(expectedMessages); }); } finally { - Helper.config.maxHistory = originalMaxHistory; + Config.values.maxHistory = originalMaxHistory; } }); @@ -193,10 +193,10 @@ describe("SQLite Message Storage", function () { }); } - const originalMaxHistory = Helper.config.maxHistory; + const originalMaxHistory = Config.values.maxHistory; try { - Helper.config.maxHistory = 3; + Config.values.maxHistory = 3; store.index( {uuid: "this-is-a-network-guid2"}, @@ -239,7 +239,7 @@ describe("SQLite Message Storage", function () { .then(() => assertResults("@", ["bar @ baz"])) ); } finally { - Helper.config.maxHistory = originalMaxHistory; + Config.values.maxHistory = originalMaxHistory; } }); diff --git a/test/plugins/storage.js b/test/plugins/storage.js index c8c4a14d..802937f9 100644 --- a/test/plugins/storage.js +++ b/test/plugins/storage.js @@ -5,7 +5,7 @@ const path = require("path"); const crypto = require("crypto"); const expect = require("chai").expect; const util = require("../util"); -const Helper = require("../../src/helper"); +const Config = require("../../src/config"); const storage = require("../../src/plugins/storage"); const link = require("../../src/plugins/irc-events/link.js"); @@ -55,7 +55,7 @@ describe("Image storage", function () { after(function (done) { // After storage tests run, remove the remaining empty // storage folder so we return to the clean state - const dir = Helper.getStoragePath(); + const dir = Config.getStoragePath(); fs.rmdir(dir, done); }); @@ -63,11 +63,11 @@ describe("Image storage", function () { this.irc = util.createClient(); this.network = util.createNetwork(); - Helper.config.prefetchStorage = true; + Config.values.prefetchStorage = true; }); afterEach(function () { - Helper.config.prefetchStorage = false; + Config.values.prefetchStorage = false; }); it("should store the thumbnail", function (done) { @@ -135,7 +135,7 @@ describe("Image storage", function () { }); it("should clear storage folder", function () { - const dir = Helper.getStoragePath(); + const dir = Config.getStoragePath(); expect(fs.readdirSync(dir)).to.not.be.empty; storage.emptyDir(); diff --git a/test/server.js b/test/server.js index e1647bba..28b2304f 100644 --- a/test/server.js +++ b/test/server.js @@ -1,7 +1,7 @@ "use strict"; const log = require("../src/log"); -const Helper = require("../src/helper"); +const Config = require("../src/config"); const expect = require("chai").expect; const stub = require("sinon").stub; const got = require("got"); @@ -28,7 +28,7 @@ describe("Server", function () { changelog.checkForUpdates.restore(); }); - const webURL = `http://${Helper.config.host}:${Helper.config.port}/`; + const webURL = `http://${Config.values.host}:${Config.values.port}/`; describe("Express", () => { it("should run a web server on " + webURL, async () => { @@ -84,7 +84,7 @@ describe("Server", function () { nick: "test-user", join: "#thelounge, #spam", name: "Test Network", - host: Helper.config.host, + host: Config.values.host, port: 6667, }); }); diff --git a/test/tests/mergeConfig.js b/test/tests/mergeConfig.js index f50d2ffc..7a785402 100644 --- a/test/tests/mergeConfig.js +++ b/test/tests/mergeConfig.js @@ -3,7 +3,7 @@ const log = require("../../src/log"); const expect = require("chai").expect; const stub = require("sinon").stub; -const mergeConfig = require("../../src/helper").mergeConfig; +const Config = require("../../src/config"); const TestUtil = require("../util"); describe("mergeConfig", function () { @@ -13,7 +13,7 @@ describe("mergeConfig", function () { }; expect( - mergeConfig(config, { + Config._merge_config_objects(config, { ip: "overridden", }) ).to.deep.equal({ @@ -27,7 +27,7 @@ describe("mergeConfig", function () { it("should merge new properties", function () { expect( - mergeConfig( + Config._merge_config_objects( { ip: "default", newProp: "this should appear too", @@ -44,7 +44,7 @@ describe("mergeConfig", function () { it("should extend objects", function () { expect( - mergeConfig( + Config._merge_config_objects( { tlsOptions: {}, }, @@ -68,7 +68,7 @@ describe("mergeConfig", function () { stub(log, "warn").callsFake(TestUtil.sanitizeLog((str) => (warning += str))); expect( - mergeConfig( + Config._merge_config_objects( { optionOne: 123, }, @@ -88,7 +88,7 @@ describe("mergeConfig", function () { it("should not warn for unknown second level keys", function () { expect( - mergeConfig( + Config._merge_config_objects( { optionOne: { subOne: 123, @@ -111,7 +111,7 @@ describe("mergeConfig", function () { it("should allow changing nulls", function () { expect( - mergeConfig( + Config._merge_config_objects( { oidentd: null, }, @@ -126,7 +126,7 @@ describe("mergeConfig", function () { it("should allow changing nulls with objects", function () { expect( - mergeConfig( + Config._merge_config_objects( { webirc: null, }, @@ -149,7 +149,7 @@ describe("mergeConfig", function () { const callbackFunction = () => ({}); expect( - mergeConfig( + Config._merge_config_objects( { webirc: null, }, @@ -168,7 +168,7 @@ describe("mergeConfig", function () { it("should keep new properties inside of objects", function () { expect( - mergeConfig( + Config._merge_config_objects( { nestedOnce: { ip: "default", @@ -206,7 +206,7 @@ describe("mergeConfig", function () { it("should not merge arrays", function () { expect( - mergeConfig( + Config._merge_config_objects( { test: ["sqlite", "text"], }, @@ -219,7 +219,7 @@ describe("mergeConfig", function () { }); expect( - mergeConfig( + Config._merge_config_objects( { test: ["sqlite", "text"], }, @@ -234,7 +234,7 @@ describe("mergeConfig", function () { it("should change order in arrays", function () { expect( - mergeConfig( + Config._merge_config_objects( { test: ["sqlite", "text"], }, @@ -251,7 +251,7 @@ describe("mergeConfig", function () { stub(log, "warn"); expect( - mergeConfig( + Config._merge_config_objects( { shouldBeObject: { thing: "yes", @@ -268,7 +268,7 @@ describe("mergeConfig", function () { }); expect( - mergeConfig( + Config._merge_config_objects( { shouldBeString: "string", },