| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- const debug = require('debug')('growi:service:ConfigManager');
- const pathUtils = require('growi-commons').pathUtils;
- const ConfigLoader = require('../service/config-loader');
- const KEYS_FOR_SAML_USE_ONLY_ENV_OPTION = [
- 'security:passport-saml:isEnabled',
- 'security:passport-saml:entryPoint',
- 'security:passport-saml:issuer',
- 'security:passport-saml:attrMapId',
- 'security:passport-saml:attrMapUsername',
- 'security:passport-saml:attrMapMail',
- 'security:passport-saml:attrMapFirstName',
- 'security:passport-saml:attrMapLastName',
- 'security:passport-saml:cert',
- ];
- class ConfigManager {
- constructor(configModel) {
- this.configModel = configModel;
- this.configLoader = new ConfigLoader(this.configModel);
- this.configObject = null;
- this.getConfig = this.getConfig.bind(this);
- }
- /**
- * load configs from the database and the environment variables
- */
- async loadConfigs() {
- this.configObject = await this.configLoader.load();
- debug('ConfigManager#loadConfigs', this.configObject);
- }
- /**
- * get a config specified by namespace & key
- *
- * Basically, this searches a specified config from configs loaded from the database at first
- * and then from configs loaded from the environment variables.
- *
- * In some case, this search method changes.
- *
- * the followings are the meanings of each special return value.
- * - null: a specified config is not set.
- * - undefined: a specified config does not exist.
- */
- getConfig(namespace, key) {
- if (this.searchOnlyFromEnvVarConfigs('crowi', 'security:passport-saml:useOnlyEnvVarsForSomeOptions')) {
- return this.searchInSAMLUseOnlyEnvMode(namespace, key);
- }
- return this.defaultSearch(namespace, key);
- }
- /**
- * get a config specified by namespace & key from configs loaded from the database
- *
- * **Do not use this unless absolutely necessary. Use getConfig instead.**
- */
- getConfigFromDB(namespace, key) {
- return this.searchOnlyFromDBConfigs(namespace, key);
- }
- /**
- * get a config specified by namespace & key from configs loaded from the environment variables
- *
- * **Do not use this unless absolutely necessary. Use getConfig instead.**
- */
- getConfigFromEnvVars(namespace, key) {
- return this.searchOnlyFromEnvVarConfigs(namespace, key);
- }
- /**
- * get the site url
- *
- * If the config for the site url is not set, this returns a message "[The site URL is not set. Please set it!]".
- *
- * With version 3.2.3 and below, there is no config for the site URL, so the system always uses auto-generated site URL.
- * With version 3.2.4 to 3.3.4, the system uses the auto-generated site URL only if the config is not set.
- * With version 3.3.5 and above, the system use only a value from the config.
- */
- /* eslint-disable no-else-return */
- getSiteUrl() {
- const siteUrl = this.getConfig('crowi', 'app:siteUrl');
- if (siteUrl != null) {
- return pathUtils.removeTrailingSlash(siteUrl);
- }
- else {
- return '[The site URL is not set. Please set it!]';
- }
- }
- /* eslint-enable no-else-return */
- getIsUploadable() {
- const method = process.env.FILE_UPLOAD || 'aws';
- if (method === 'aws' && (
- !this.getConfig('crowi', 'aws:accessKeyId')
- || !this.getConfig('crowi', 'aws:secretAccessKey')
- || !this.getConfig('crowi', 'aws:region')
- || !this.getConfig('crowi', 'aws:bucket'))) {
- return false;
- }
- return method !== 'none';
- }
- getTagWhiteList() {
- const { tags } = require('@commons/service/xss/recommended-whitelist');
- const isEnabledXssPrevention = this.getConfig('markdown', 'markdown:xss:isEnabledPrevention');
- const xssOpiton = this.getConfig('markdown', 'markdown:xss:option');
- if (isEnabledXssPrevention) {
- switch (xssOpiton) {
- case 1: // ignore all: use default option
- return [];
- case 2: // recommended
- return tags;
- case 3: // custom white list
- return this.getConfig('markdown', 'markdown:xss:tagWhiteList');
- default:
- return [];
- }
- }
- else {
- return [];
- }
- }
- getAttrWhiteList() {
- const { attrs } = require('@commons/service/xss/recommended-whitelist');
- const isEnabledXssPrevention = this.getConfig('markdown', 'markdown:xss:isEnabledPrevention');
- const xssOpiton = this.getConfig('markdown', 'markdown:xss:option');
- if (isEnabledXssPrevention) {
- switch (xssOpiton) {
- case 1: // ignore all: use default option
- return [];
- case 2: // recommended
- return attrs;
- case 3: // custom white list
- return this.getConfig('markdown', 'markdown:xss:attrWhiteList');
- default:
- return [];
- }
- }
- else {
- return [];
- }
- }
- getIsPublicWikiOnly() {
- // CONF.RF save PUBLIC_WIKI_ONLY in mongodb?
- const publicWikiOnly = process.env.PUBLIC_WIKI_ONLY;
- if (publicWikiOnly === 'true' || publicWikiOnly === 1) {
- return true;
- }
- return false;
- }
- getIsGuestAllowedToRead() {
- const SECURITY_RESTRICT_GUEST_MODE_DENY = 'Deny';
- const SECURITY_RESTRICT_GUEST_MODE_READONLY = 'Readonly';
- const SECURITY_REGISTRATION_MODE_OPEN = 'Open';
- const SECURITY_REGISTRATION_MODE_RESTRICTED = 'Resricted';
- const SECURITY_REGISTRATION_MODE_CLOSED = 'Closed';
- // return true if puclic wiki mode
- if (this.getIsPublicWikiOnly()) {
- return true;
- }
- // return false if undefined
- const isRestrictGuestMode = this.getConfig('crowi', 'security:restrictGuestMode');
- if (isRestrictGuestMode) {
- return false;
- }
- return SECURITY_RESTRICT_GUEST_MODE_READONLY === isRestrictGuestMode;
- }
- /**
- * update configs in the same namespace
- *
- * Specified values are encoded by convertInsertValue.
- * In it, an empty string is converted to null that indicates a config is not set.
- *
- * For example:
- * ```
- * updateConfigsInTheSameNamespace(
- * 'some namespace',
- * {
- * 'some key 1': 'value 1',
- * 'some key 2': 'value 2',
- * ...
- * }
- * );
- * ```
- */
- async updateConfigsInTheSameNamespace(namespace, configs) {
- const queries = [];
- for (const key of Object.keys(configs)) {
- queries.push({
- updateOne: {
- filter: { ns: namespace, key },
- update: { ns: namespace, key, value: this.convertInsertValue(configs[key]) },
- upsert: true,
- },
- });
- }
- await this.configModel.bulkWrite(queries);
- await this.loadConfigs();
- }
- /**
- * Execute only once for installing application
- */
- async initDB(globalLang) {
- const initialConfig = this.configModel.getConfigsObjectForInstalling();
- initialConfig['app:globalLang'] = globalLang;
- await this.updateConfigsInTheSameNamespace('crowi', initialConfig);
- }
- async isDBInitialized() {
- const appInstalled = await this.getConfigFromDB('crowi', 'app:installed');
- return appInstalled;
- }
- /*
- * All of the methods below are private APIs.
- */
- /**
- * search a specified config from configs loaded from the database at first
- * and then from configs loaded from the environment variables
- */
- defaultSearch(namespace, key) {
- if (!this.configExistsInDB(namespace, key) && !this.configExistsInEnvVars(namespace, key)) {
- return undefined;
- }
- if (this.configExistsInDB(namespace, key) && !this.configExistsInEnvVars(namespace, key)) {
- return this.configObject.fromDB[namespace][key];
- }
- if (!this.configExistsInDB(namespace, key) && this.configExistsInEnvVars(namespace, key)) {
- return this.configObject.fromEnvVars[namespace][key];
- }
- if (this.configExistsInDB(namespace, key) && this.configExistsInEnvVars(namespace, key)) {
- /* eslint-disable no-else-return */
- if (this.configObject.fromDB[namespace][key] !== null) {
- return this.configObject.fromDB[namespace][key];
- }
- else {
- return this.configObject.fromEnvVars[namespace][key];
- }
- /* eslint-enable no-else-return */
- }
- }
- /**
- * For the configs specified by KEYS_FOR_SAML_USE_ONLY_ENV_OPTION,
- * this searches only from configs loaded from the environment variables.
- * For the other configs, this searches as the same way to defaultSearch.
- */
- /* eslint-disable no-else-return */
- searchInSAMLUseOnlyEnvMode(namespace, key) {
- if (namespace === 'crowi' && KEYS_FOR_SAML_USE_ONLY_ENV_OPTION.includes(key)) {
- return this.searchOnlyFromEnvVarConfigs(namespace, key);
- }
- else {
- return this.defaultSearch(namespace, key);
- }
- }
- /* eslint-enable no-else-return */
- /**
- * search a specified config from configs loaded from the database
- */
- searchOnlyFromDBConfigs(namespace, key) {
- if (!this.configExistsInDB(namespace, key)) {
- return undefined;
- }
- return this.configObject.fromDB[namespace][key];
- }
- /**
- * search a specified config from configs loaded from the environment variables
- */
- searchOnlyFromEnvVarConfigs(namespace, key) {
- if (!this.configExistsInEnvVars(namespace, key)) {
- return undefined;
- }
- return this.configObject.fromEnvVars[namespace][key];
- }
- /**
- * check whether a specified config exists in configs loaded from the database
- */
- configExistsInDB(namespace, key) {
- if (this.configObject.fromDB[namespace] === undefined) {
- return false;
- }
- return this.configObject.fromDB[namespace][key] !== undefined;
- }
- /**
- * check whether a specified config exists in configs loaded from the environment variables
- */
- configExistsInEnvVars(namespace, key) {
- if (this.configObject.fromEnvVars[namespace] === undefined) {
- return false;
- }
- return this.configObject.fromEnvVars[namespace][key] !== undefined;
- }
- convertInsertValue(value) {
- return JSON.stringify(value === '' ? null : value);
- }
- }
- module.exports = ConfigManager;
|