diff --git a/.gitignore b/.gitignore index 63aacd7..a5b09c3 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ lib/*.map lib/api-functions.js lib/auth.js -lib/config.js lib/cwmp.js lib/db.js lib/nbi.js diff --git a/lib/config.coffee b/lib/config.coffee deleted file mode 100644 index 37aa60e..0000000 --- a/lib/config.coffee +++ /dev/null @@ -1,209 +0,0 @@ -### -# Copyright 2013-2017 Zaid Abdulla -# -# This file is part of GenieACS. -# -# GenieACS is free software: you can redistribute it and/or modify -# it under the terms of the GNU Affero General Public License as -# published by the Free Software Foundation, either version 3 of the -# License, or (at your option) any later version. -# -# GenieACS is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public License -# along with GenieACS. If not, see . -### - -path = require 'path' -common = require './common' - -options = { - CONFIG_DIR : {type : 'path', default : 'config'}, - MONGODB_CONNECTION_URL : {type : 'string', default : 'mongodb://127.0.0.1/genieacs'}, - REDIS_PORT : {type : 'int', default : 6379}, - REDIS_HOST : {type : 'string', default : ''}, - REDIS_DB : {type : 'int', default : 0}, - - 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_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_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_HOSTNAME : {type : 'string', default : 'acs.example.com'}, - FS_LOG_FILE : {type: 'path', default : ''}, - FS_ACCESS_LOG_FILE : {type : 'path', default : ''}, - - UDP_CONNECTION_REQUEST_PORT : {type : 'int', default : 0}, - - DOWNLOAD_TIMEOUT: {type : 'int', default : 3600}, - EXT_TIMEOUT: {type: 'int', default: 3000}, - MAX_CACHE_TTL : {type : 'int', default : 86400}, - DEBUG : {type : 'bool', default : false}, - RETRY_DELAY : {type : 'int', default : 300}, - SESSION_TIMEOUT : {type : 'int', default : 30}, - CONNECTION_REQUEST_TIMEOUT : {type : 'int', default: 2000}, - GPN_NEXT_LEVEL : {type : 'int', default : 0}, - GPV_BATCH_SIZE : {type : 'int', default : 32}, - MAX_DEPTH : {type: 'int', default : 16}, - COOKIES_PATH : {type : 'string'}, - LOG_FORMAT : {type : 'string', default : 'simple'}, - ACCESS_LOG_FORMAT : {type : 'string', default : ''}, - MAX_CONCURRENT_REQUESTS : {type : 'int', default: 20}, - DATETIME_MILLISECONDS : {type: 'bool', default: true}, - BOOLEAN_LITERAL : {type: 'bool', default: true}, - CONNECTION_REQUEST_ALLOW_BASIC_AUTH: {type: 'bool', default: false}, - MAX_COMMIT_ITERATIONS : {type : 'int', default: 32}, - - # XML configuration - XML_RECOVER : {type : 'bool', default : false}, - XML_IGNORE_ENC : {type : 'bool', default : false}, - XML_FORMAT : {type : 'bool', default : false}, - XML_NO_DECL : {type : 'bool', default : false}, - XML_NO_EMPTY : {type : 'bool', default : false}, - XML_IGNORE_NAMESPACE : {type : 'bool', default : false}, - - # Should probably never be changed - DEVICE_ONLINE_THRESHOLD : {type : 'int', default : 4000} -} - -allConfig = {} - - -setConfig = (name, value, commandLineArgument) -> - return true if allConfig[name]? - - # For compatibility with v1.0 - if name in ['PRESETS_CACHE_DURATION', 'presets-cache-duration'] - setConfig('MAX_CACHE_TTL', value) - - if name in ['GET_PARAMETER_NAMES_DEPTH_THRESHOLD', 'get-parameter-names-depth-threshold'] - setConfig('GPN_NEXT_LEVEL', value) - - if name in ['TASK_PARAMETERS_BATCH_SIZE', 'task-parameters-batch-size'] - setConfig('GPV_BATCH_SIZE', value) - - if name in ['IGNORE_XML_NAMESPACES', 'ignore-xml-namespaces'] - setConfig('XML_IGNORE_NAMESPACE', value) - - if name in ['XML_PARSE_IGNORE_ENC', 'xml-parse-ignore-enc'] - setConfig('XML_IGNORE_ENC', value) - - if name in ['XML_PARSE_RECOVER', 'xml-parse-recover'] - setConfig('XML_RECOVER', value) - - if name in ['FS_IP', 'fs-ip'] - setConfig('FS_HOSTNAME', value) - - cast = (val, type) -> - switch type - when 'int' - Number(val) - when 'bool' - String(val).trim().toLowerCase() in ['true', 'on', 'yes', '1'] - when 'string' - String(val) - when 'path' - if val then path.resolve(val) else '' - else - null - - _value = null - - for optionName, optionDetails of options - n = optionName - if commandLineArgument - n = n.toLowerCase().replace(/_/g, '-') - - if name == n - _value = cast(value, optionDetails.type) - n = optionName - else if name.startsWith("#{n}-") - _value = cast(value, optionDetails.type) - n = "#{optionName}-#{name[optionName.length+1..]}" - - if _value? - allConfig[n] = _value - # Save as environmnet variable to pass on to any child processes - process.env["GENIEACS_#{n}"] = _value - return true - - return false - - -# Command line arguments -argv = process.argv[2..] -while argv.length - arg = argv.shift() - if arg[0] == '-' - v = argv.shift() - setConfig(arg[2..], v, true) - - -# Environment variable -for k, v of process.env - continue if k.lastIndexOf('GENIEACS_', 0) != 0 - k = k[9..] # remove "GENIEACS_" prefix - setConfig(k, v) - - -# Use default config dir if none defined -setConfig('CONFIG_DIR', options['CONFIG_DIR'].default) - -# Configuration file -for k, v of require(path.resolve(allConfig.CONFIG_DIR, 'config')) - if not setConfig(k, v) - # Pass as environment variable to be accessable by extensions - process.env["GENIEACS_#{k}"] = v - - -# Defaults -for k, v of options - setConfig(k, v.default) if v.default? - - -get = (option, deviceId) -> - if deviceId? - name = "#{option}-#{deviceId}" - v = allConfig[name] - return v if v? - i = name.lastIndexOf('-') - v = allConfig[name[0...i]] - return v if v? - i = name.lastIndexOf('-', i-1) - v = allConfig[name[0...i]] - return v if v? or i == -1 - - return allConfig[option] - - -getDefault = (optionName) -> - option = options[optionName] - return null if not option - val = option.default - if val and option.type == 'path' - val = path.resolve(val) - return val - - -# load authentication scripts -try - exports.auth = require(path.resolve(allConfig.CONFIG_DIR, 'auth')) - -exports.get = get -exports.getDefault = getDefault diff --git a/lib/config.js b/lib/config.js new file mode 100644 index 0000000..6c59021 --- /dev/null +++ b/lib/config.js @@ -0,0 +1,238 @@ +/** + * Copyright 2013-2018 Zaid Abdulla + * + * This file is part of GenieACS. + * + * GenieACS is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * GenieACS is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with GenieACS. If not, see . + */ +"use strict"; + +const path = require("path"); + +const options = { + CONFIG_DIR: {type: "path", "default": "config"}, + MONGODB_CONNECTION_URL: {type: "string", "default": "mongodb://127.0.0.1/genieacs"}, + REDIS_PORT: {type: "int", "default": 6379}, + REDIS_HOST: {type: "string", "default": ""}, + REDIS_DB: {type: "int", "default": 0}, + + 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_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_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_HOSTNAME: {type: "string", "default": "acs.example.com"}, + FS_LOG_FILE: {type: "path", "default": ""}, + FS_ACCESS_LOG_FILE: {type: "path", "default": ""}, + + UDP_CONNECTION_REQUEST_PORT: {type: "int", "default": 0}, + + DOWNLOAD_TIMEOUT: {type: "int", "default": 3600}, + EXT_TIMEOUT: {type: "int", "default": 3000}, + MAX_CACHE_TTL: {type: "int", "default": 86400}, + DEBUG: {type: "bool", "default": false}, + RETRY_DELAY: {type: "int", "default": 300}, + SESSION_TIMEOUT: {type: "int", "default": 30}, + CONNECTION_REQUEST_TIMEOUT: {type: "int", "default": 2000}, + GPN_NEXT_LEVEL: {type: "int", "default": 0}, + GPV_BATCH_SIZE: {type: "int", "default": 32}, + MAX_DEPTH: {type: "int", "default": 16}, + COOKIES_PATH: {type: "string"}, + LOG_FORMAT: {type: "string", "default": "simple"}, + ACCESS_LOG_FORMAT: {type: "string", "default": ""}, + MAX_CONCURRENT_REQUESTS: {type: "int", "default": 20}, + DATETIME_MILLISECONDS: {type: "bool", "default": true}, + BOOLEAN_LITERAL: {type: "bool", "default": true}, + CONNECTION_REQUEST_ALLOW_BASIC_AUTH: {type: "bool", "default": false}, + MAX_COMMIT_ITERATIONS: {type: "int", "default": 32}, + + // XML configuration + XML_RECOVER: {type: "bool", "default": false}, + XML_IGNORE_ENC: {type: "bool", "default": false}, + XML_FORMAT: {type: "bool", "default": false}, + XML_NO_DECL: {type: "bool", "default": false}, + XML_NO_EMPTY: {type: "bool", "default": false}, + XML_IGNORE_NAMESPACE: {type: "bool", "default": false}, + + // Should probably never be changed + DEVICE_ONLINE_THRESHOLD: {type: "int", "default": 4000} +}; + +const allConfig = {}; + +function setConfig(name, value, commandLineArgument) { + if (allConfig[name] != null) + return true; + + // For compatibility with v1.0 + if (name === "PRESETS_CACHE_DURATION" || name === "presets-cache-duration") + setConfig("MAX_CACHE_TTL", value); + + if (name === "GET_PARAMETER_NAMES_DEPTH_THRESHOLD" || name === "get-parameter-names-depth-threshold") + setConfig("GPN_NEXT_LEVEL", value); + + if (name === "TASK_PARAMETERS_BATCH_SIZE" || name === "task-parameters-batch-size") + setConfig("GPV_BATCH_SIZE", value); + + if (name === "IGNORE_XML_NAMESPACES" || name === "ignore-xml-namespaces") + setConfig("XML_IGNORE_NAMESPACE", value); + + if (name === "XML_PARSE_IGNORE_ENC" || name === "xml-parse-ignore-enc") + setConfig("XML_IGNORE_ENC", value); + + if (name === "XML_PARSE_RECOVER" || name === "xml-parse-recover") + setConfig("XML_RECOVER", value); + + if (name === "FS_IP" || name === "fs-ip") + setConfig("FS_HOSTNAME", value); + + function cast(val, type) { + switch (type) { + case "int": + return Number(val); + case "bool": + return ["true", "on", "yes", "1"].includes(String(val).trim().toLowerCase()); + case "string": + return String(val); + case "path": + if (!val) + return ""; + return path.resolve(val); + default: + return null; + } + } + + let _value = null; + for (let [optionName, optionDetails] of Object.entries(options)) { + let n = optionName; + if (commandLineArgument) + n = n.toLowerCase().replace(/_/g, "-"); + + if (name === n) { + _value = cast(value, optionDetails.type); + n = optionName; + } else if (name.startsWith(`${n}-`)) { + _value = cast(value, optionDetails.type); + n = `${optionName}-${name.slice(optionName.length + 1)}`; + } + + if (_value != null) { + allConfig[n] = _value; + // Save as environmnet variable to pass on to any child process + process.env[`GENIEACS_${n}`] = _value; + return true; + } + } + + return false; +} + +// Command line arguments +const argv = process.argv.slice(2); +while (argv.length) { + const arg = argv.shift(); + if (arg[0] === "-") { + const v = argv.shift(); + setConfig(arg.slice(2), v, true); + } +} + +// Environment variable +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 = require(path.resolve(allConfig.CONFIG_DIR, "config")); +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}`; + +// Defaults +for (const [k, v] of Object.entries(options)) + if (v["default"] != null) + setConfig(k, v["default"]); + +function get(optionName, deviceId) { + if (!deviceId) + return allConfig[optionName]; + + optionName = `${optionName}-${deviceId}`; + let v = allConfig[optionName]; + if (v != null) + return v; + + let i = optionName.lastIndexOf("-"); + v = allConfig[optionName.slice(0, i)]; + if (v != null) + return v; + + i = optionName.lastIndexOf("-", i - 1); + v = allConfig[optionName.slice(0, i)]; + if (v != null) + return v; + + i = optionName.lastIndexOf("-", i - 1); + v = allConfig[optionName.slice(0, i)]; + if (v != null) + return v; + + i = optionName.lastIndexOf("-", i - 1); + if (i > 0) { + v = allConfig[optionName.slice(0, i)]; + if (v != null) + return v; + } + + return null; +} + +function getDefault(optionName) { + const option = options[optionName]; + if (!option) + return null; + + let val = option["default"]; + if (val && option.type === "path") + val = path.resolve(val); + + return val; +} + +// Load authentication scripts +try { + exports.auth = require(path.resolve(allConfig.CONFIG_DIR, "auth")); +} catch (error) {} + +exports.get = get; +exports.getDefault = getDefault;