'use strict'; exports = module.exports = { initCache, // these values come from the cache apiServerOrigin, webServerOrigin, consoleServerOrigin, dashboardDomain, setDashboardLocation, setMailLocation, mailFqdn, mailDomain, dashboardOrigin, dashboardFqdn, get, set, getJson, setJson, getBlob, setBlob, // booleans. if you add an entry here, be sure to fix list() DYNAMIC_DNS_KEY: 'dynamic_dns', // json. if you add an entry here, be sure to fix list() BACKUP_CONFIG_KEY: 'backup_config', BACKUP_POLICY_KEY: 'backup_policy', SERVICES_CONFIG_KEY: 'services_config', EXTERNAL_LDAP_KEY: 'external_ldap_config', DIRECTORY_SERVER_KEY: 'directory_server_config', REGISTRY_CONFIG_KEY: 'registry_config', IPV4_CONFIG_KEY: 'ipv4_config', SUPPORT_CONFIG_KEY: 'support_config', PROFILE_CONFIG_KEY: 'profile_config', GHOSTS_CONFIG_KEY: 'ghosts_config', REVERSE_PROXY_CONFIG_KEY: 'reverseproxy_config', IPV6_CONFIG_KEY: 'ipv6_config', // strings AUTOUPDATE_PATTERN_KEY: 'autoupdate_pattern', TIME_ZONE_KEY: 'time_zone', OIDC_COOKIE_SECRET_KEY: 'cookie_secret', CLOUDRON_NAME_KEY: 'cloudron_name', LANGUAGE_KEY: 'language', CLOUDRON_ID_KEY: 'cloudron_id', APPSTORE_API_TOKEN_KEY: 'appstore_api_token', APPSTORE_WEB_TOKEN_KEY: 'appstore_web_token', FIREWALL_BLOCKLIST_KEY: 'firewall_blocklist', TRUSTED_IPS_KEY: 'trusted_ips_key', API_SERVER_ORIGIN_KEY: 'api_server_origin', WEB_SERVER_ORIGIN_KEY: 'web_server_origin', CONSOLE_SERVER_ORIGIN_KEY: 'console_server_origin', DASHBOARD_DOMAIN_KEY: 'admin_domain', DASHBOARD_FQDN_KEY: 'admin_fqdn', MAIL_DOMAIN_KEY: 'mail_domain', MAIL_FQDN_KEY: 'mail_fqdn', FOOTER_KEY: 'footer', // blobs CLOUDRON_AVATAR_KEY: 'cloudron_avatar', // testing _setApiServerOrigin: setApiServerOrigin, _clear: clear, _set: set }; const assert = require('assert'), database = require('./database.js'), debug = require('debug')('box:settings'), safe = require('safetydance'); const SETTINGS_FIELDS = [ 'name', 'value' ].join(','); const SETTINGS_BLOB_FIELDS = [ 'name', 'valueBlob' ].join(','); const gDefaults = (function () { const result = { }; result[exports.DASHBOARD_DOMAIN_KEY] = ''; result[exports.DASHBOARD_FQDN_KEY] = ''; result[exports.MAIL_DOMAIN_KEY] = ''; result[exports.MAIL_FQDN_KEY] = ''; result[exports.API_SERVER_ORIGIN_KEY] = 'https://api.cloudron.io'; result[exports.WEB_SERVER_ORIGIN_KEY] = 'https://cloudron.io'; result[exports.CONSOLE_SERVER_ORIGIN_KEY] = 'https://console.cloudron.io'; return result; })(); let gCache = {}; async function get(key) { assert.strictEqual(typeof key, 'string'); const result = await database.query(`SELECT ${SETTINGS_FIELDS} FROM settings WHERE name = ?`, [ key ]); if (result.length === 0) return null; // can't return the default value here because we might need to massage/json parse the result return result[0].value; } async function set(key, value) { assert.strictEqual(typeof key, 'string'); assert(value === null || typeof value === 'string'); await database.query('INSERT INTO settings (name, value) VALUES (?, ?) ON DUPLICATE KEY UPDATE value=VALUES(value)', [ key, value ]); // don't rely on affectedRows here since it gives 2 } async function getJson(key) { assert.strictEqual(typeof key, 'string'); return safe.JSON.parse(await get(key)); } async function setJson(key, value) { assert.strictEqual(typeof key, 'string'); assert.strictEqual(typeof value, 'object'); // can be null await set(key, value ? JSON.stringify(value) : null); } async function getBlob(key) { assert.strictEqual(typeof key, 'string'); const result = await database.query(`SELECT ${SETTINGS_BLOB_FIELDS} FROM settings WHERE name = ?`, [ key ]); if (result.length === 0) return null; return result[0].valueBlob; } async function setBlob(key, value) { assert.strictEqual(typeof key, 'string'); assert(value === null || Buffer.isBuffer(value)); await database.query('INSERT INTO settings (name, valueBlob) VALUES (?, ?) ON DUPLICATE KEY UPDATE valueBlob=VALUES(valueBlob)', [ key, value ]); // don't rely on affectedRows here since it gives 2 } async function clear() { await database.query('DELETE FROM settings'); } async function list() { const settings = await database.query(`SELECT ${SETTINGS_FIELDS} FROM settings WHERE value IS NOT NULL ORDER BY name`); const result = Object.assign({}, gDefaults); settings.forEach(function (setting) { result[setting.name] = setting.value; }); // convert booleans result[exports.DEMO_KEY] = !!result[exports.DEMO_KEY]; return result; } async function initCache() { debug('initCache: pre-load settings'); const allSettings = await list(); gCache = { apiServerOrigin: allSettings[exports.API_SERVER_ORIGIN_KEY], webServerOrigin: allSettings[exports.WEB_SERVER_ORIGIN_KEY], consoleServerOrigin: allSettings[exports.CONSOLE_SERVER_ORIGIN_KEY], dashboardDomain: allSettings[exports.DASHBOARD_DOMAIN_KEY], dashboardFqdn: allSettings[exports.DASHBOARD_FQDN_KEY], mailDomain: allSettings[exports.MAIL_DOMAIN_KEY], mailFqdn: allSettings[exports.MAIL_FQDN_KEY], }; } // this is together so we can do this in a transaction later async function setDashboardLocation(dashboardDomain, dashboardFqdn) { assert.strictEqual(typeof dashboardDomain, 'string'); assert.strictEqual(typeof dashboardFqdn, 'string'); await set(exports.DASHBOARD_DOMAIN_KEY, dashboardDomain); await set(exports.DASHBOARD_FQDN_KEY, dashboardFqdn); gCache.dashboardDomain = dashboardDomain; gCache.dashboardFqdn = dashboardFqdn; } async function setMailLocation(mailDomain, mailFqdn) { assert.strictEqual(typeof mailDomain, 'string'); assert.strictEqual(typeof mailFqdn, 'string'); await set(exports.MAIL_DOMAIN_KEY, mailDomain); await set(exports.MAIL_FQDN_KEY, mailFqdn); gCache.mailDomain = mailDomain; gCache.mailFqdn = mailFqdn; } async function setApiServerOrigin(origin) { assert.strictEqual(typeof origin, 'string'); await set(exports.API_SERVER_ORIGIN_KEY, origin); gCache.apiServerOrigin = origin; } function apiServerOrigin() { return gCache.apiServerOrigin; } function webServerOrigin() { return gCache.webServerOrigin; } function consoleServerOrigin() { return gCache.consoleServerOrigin; } function dashboardDomain() { return gCache.dashboardDomain; } function dashboardFqdn() { return gCache.dashboardFqdn; } function mailDomain() { return gCache.mailDomain; } function mailFqdn() { return gCache.mailFqdn; } function dashboardOrigin() { return 'https://' + dashboardFqdn(); }