Files
cloudron-box/src/settings.js
T
Girish Ramakrishnan 6ace8d1ac5 volumes: fix various mount related issues
Various notes on mounting:

* The permissions come from the mounted file system and not the mount point.
This means that if we change the perms before mounting, it is overridden by
whatever is in the actual file system.

* uid/gid only works for permission-less file systems

SFTP container notes:

* Assumes that nothing changed if the host path hasn't changed. This means that
if a user changes the disk uuid, reload doesn't work.

* Not sure how/why, but even after unmounting the container can still access the old
mount files (!). With ext4 on disk change or nfs after root path change, the file manager
continues to be able to access the old mounts (despite umount succeeding).

All this led to following changes:

* Remove editing of volumes. Just allow editing username/password.
* edit UI then just also provides a way to re-mount.
* Change mode of mountpoint to be 777 post mounting for ease of use. Otherwise, we have to
make the user do this by ssh. this can always become options later.
2021-06-21 16:11:48 -07:00

936 lines
30 KiB
JavaScript

'use strict';
exports = module.exports = {
getAutoupdatePattern,
setAutoupdatePattern,
getTimeZone,
setTimeZone,
getCloudronName,
setCloudronName,
getCloudronAvatar,
setCloudronAvatar,
getDynamicDnsConfig,
setDynamicDnsConfig,
getUnstableAppsConfig,
setUnstableAppsConfig,
getBackupConfig,
setBackupConfig,
setBackupCredentials,
getServicesConfig,
setServicesConfig,
getExternalLdapConfig,
setExternalLdapConfig,
getRegistryConfig,
setRegistryConfig,
getLicenseKey,
setLicenseKey,
getLanguage,
setLanguage,
getCloudronId,
setCloudronId,
getCloudronToken,
setCloudronToken,
getSysinfoConfig,
setSysinfoConfig,
getFooter,
setFooter,
getDirectoryConfig,
setDirectoryConfig,
getAppstoreListingConfig,
setAppstoreListingConfig,
getFirewallBlocklist,
setFirewallBlocklist,
getSupportConfig,
provider,
getAll,
initCache,
// these values come from the cache
apiServerOrigin,
webServerOrigin,
dashboardDomain,
setDashboardLocation,
setMailLocation,
mailFqdn,
mailDomain,
dashboardOrigin,
dashboardFqdn,
isDemo,
// booleans. if you add an entry here, be sure to fix getAll
DYNAMIC_DNS_KEY: 'dynamic_dns',
UNSTABLE_APPS_KEY: 'unstable_apps',
DEMO_KEY: 'demo',
// json. if you add an entry here, be sure to fix getAll
BACKUP_CONFIG_KEY: 'backup_config',
SERVICES_CONFIG_KEY: 'services_config',
EXTERNAL_LDAP_KEY: 'external_ldap_config',
REGISTRY_CONFIG_KEY: 'registry_config',
SYSINFO_CONFIG_KEY: 'sysinfo_config',
APPSTORE_LISTING_CONFIG_KEY: 'appstore_listing_config',
SUPPORT_CONFIG_KEY: 'support_config',
DIRECTORY_CONFIG_KEY: 'directory_config',
// strings
AUTOUPDATE_PATTERN_KEY: 'autoupdate_pattern',
TIME_ZONE_KEY: 'time_zone',
CLOUDRON_NAME_KEY: 'cloudron_name',
LICENSE_KEY: 'license_key',
LANGUAGE_KEY: 'language',
CLOUDRON_ID_KEY: 'cloudron_id',
CLOUDRON_TOKEN_KEY: 'cloudron_token', // apstore token
FIREWALL_BLOCKLIST_KEY: 'firewall_blocklist',
API_SERVER_ORIGIN_KEY: 'api_server_origin',
WEB_SERVER_ORIGIN_KEY: 'web_server_origin',
DASHBOARD_DOMAIN_KEY: 'admin_domain',
DASHBOARD_FQDN_KEY: 'admin_fqdn',
MAIL_DOMAIN_KEY: 'mail_domain',
MAIL_FQDN_KEY: 'mail_fqdn',
PROVIDER_KEY: 'provider',
FOOTER_KEY: 'footer',
// blobs
CLOUDRON_AVATAR_KEY: 'cloudron_avatar',
// testing
_setApiServerOrigin: setApiServerOrigin
};
const assert = require('assert'),
backups = require('./backups.js'),
BoxError = require('./boxerror.js'),
constants = require('./constants.js'),
cron = require('./cron.js'),
CronJob = require('cron').CronJob,
debug = require('debug')('box:settings'),
docker = require('./docker.js'),
externalLdap = require('./externalldap.js'),
moment = require('moment-timezone'),
mounts = require('./mounts.js'),
paths = require('./paths.js'),
safe = require('safetydance'),
settingsdb = require('./settingsdb.js'),
sysinfo = require('./sysinfo.js'),
translation = require('./translation.js'),
_ = require('underscore');
let gDefaults = (function () {
var result = { };
result[exports.AUTOUPDATE_PATTERN_KEY] = cron.DEFAULT_AUTOUPDATE_PATTERN;
result[exports.TIME_ZONE_KEY] = 'America/Los_Angeles';
result[exports.CLOUDRON_NAME_KEY] = 'Cloudron';
result[exports.DYNAMIC_DNS_KEY] = false;
result[exports.UNSTABLE_APPS_KEY] = true;
result[exports.LICENSE_KEY] = '';
result[exports.LANGUAGE_KEY] = 'en';
result[exports.CLOUDRON_ID_KEY] = '';
result[exports.CLOUDRON_TOKEN_KEY] = '';
result[exports.BACKUP_CONFIG_KEY] = {
provider: 'filesystem',
backupFolder: '/var/backups',
format: 'tgz',
encryption: null,
retentionPolicy: { keepWithinSecs: 2 * 24 * 60 * 60 }, // 2 days
schedulePattern: '00 00 23 * * *' // every day at 11pm
};
result[exports.SERVICES_CONFIG_KEY] = {};
result[exports.EXTERNAL_LDAP_KEY] = {
provider: 'noop',
autoCreate: false
};
result[exports.REGISTRY_CONFIG_KEY] = {
provider: 'noop'
};
result[exports.SYSINFO_CONFIG_KEY] = {
provider: 'generic'
};
result[exports.DIRECTORY_CONFIG_KEY] = {
lockUserProfiles: false,
mandatory2FA: false
};
result[exports.DASHBOARD_DOMAIN_KEY] = '';
result[exports.DASHBOARD_FQDN_KEY] = '';
result[exports.MAIL_DOMAIN_KEY] = '';
result[exports.MAIL_FQDN_KEY] = '';
result[exports.FIREWALL_BLOCKLIST_KEY] = '';
result[exports.API_SERVER_ORIGIN_KEY] = 'https://api.cloudron.io';
result[exports.WEB_SERVER_ORIGIN_KEY] = 'https://cloudron.io';
result[exports.DEMO_KEY] = false;
result[exports.APPSTORE_LISTING_CONFIG_KEY] = {
blacklist: [],
whitelist: null // null imples nothing is whitelisted. this is an array
};
result[exports.SUPPORT_CONFIG_KEY] = {
email: 'support@cloudron.io',
remoteSupport: true,
ticketFormBody:
'Use this form to open support tickets. You can also write directly to [support@cloudron.io](mailto:support@cloudron.io).\n\n'
+ '* [Knowledge Base & App Docs](https://docs.cloudron.io/apps/?support_view)\n'
+ '* [Custom App Packaging & API](https://docs.cloudron.io/custom-apps/tutorial/?support_view)\n'
+ '* [Forum](https://forum.cloudron.io/)\n\n',
submitTickets: true
};
result[exports.FOOTER_KEY] = '';
return result;
})();
let gCache = {};
function notifyChange(key, value) {
assert.strictEqual(typeof key, 'string');
// value is a variant
cron.handleSettingsChanged(key, value);
}
function setAutoupdatePattern(pattern, callback) {
assert.strictEqual(typeof pattern, 'string');
assert.strictEqual(typeof callback, 'function');
if (pattern !== constants.AUTOUPDATE_PATTERN_NEVER) { // check if pattern is valid
var job = safe.safeCall(function () { return new CronJob(pattern); });
if (!job) return callback(new BoxError(BoxError.BAD_FIELD, 'Invalid pattern', { field: 'pattern' }));
}
settingsdb.set(exports.AUTOUPDATE_PATTERN_KEY, pattern, function (error) {
if (error) return callback(error);
notifyChange(exports.AUTOUPDATE_PATTERN_KEY, pattern);
return callback(null);
});
}
function getAutoupdatePattern(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.AUTOUPDATE_PATTERN_KEY, function (error, pattern) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.AUTOUPDATE_PATTERN_KEY]);
if (error) return callback(error);
callback(null, pattern);
});
}
function setTimeZone(tz, callback) {
assert.strictEqual(typeof tz, 'string');
assert.strictEqual(typeof callback, 'function');
if (moment.tz.names().indexOf(tz) === -1) return callback(new BoxError(BoxError.BAD_FIELD, 'Bad timeZone', { field: 'timezone' }));
settingsdb.set(exports.TIME_ZONE_KEY, tz, function (error) {
if (error) return callback(error);
notifyChange(exports.TIME_ZONE_KEY, tz);
return callback(null);
});
}
function getTimeZone(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.TIME_ZONE_KEY, function (error, tz) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.TIME_ZONE_KEY]);
if (error) return callback(error);
callback(null, tz);
});
}
function getCloudronName(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.CLOUDRON_NAME_KEY, function (error, name) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.CLOUDRON_NAME_KEY]);
if (error) return callback(error);
callback(null, name);
});
}
function setCloudronName(name, callback) {
assert.strictEqual(typeof name, 'string');
assert.strictEqual(typeof callback, 'function');
if (!name) return callback(new BoxError(BoxError.BAD_FIELD, 'name is empty', { field: 'name' }));
// some arbitrary restrictions (for sake of ui layout)
// if this is changed, adjust dashboard/branding.html
if (name.length > 64) return callback(new BoxError(BoxError.BAD_FIELD, 'name cannot exceed 64 characters', { field: 'name' }));
settingsdb.set(exports.CLOUDRON_NAME_KEY, name, function (error) {
if (error) return callback(error);
notifyChange(exports.CLOUDRON_NAME_KEY, name);
return callback(null);
});
}
function getCloudronAvatar(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.getBlob(exports.CLOUDRON_AVATAR_KEY, function (error, avatar) {
if (error && error.reason !== BoxError.NOT_FOUND) return callback(error);
if (avatar) return callback(null, avatar);
// try default fallback
avatar = safe.fs.readFileSync(paths.CLOUDRON_DEFAULT_AVATAR_FILE);
if (avatar) return callback(null, avatar);
callback(new BoxError(BoxError.FS_ERROR, safe.error));
});
}
function setCloudronAvatar(avatar, callback) {
assert(Buffer.isBuffer(avatar));
assert.strictEqual(typeof callback, 'function');
settingsdb.setBlob(exports.CLOUDRON_AVATAR_KEY, avatar, function (error) {
if (error) return callback(error);
return callback(null);
});
}
function getDynamicDnsConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.DYNAMIC_DNS_KEY, function (error, enabled) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.DYNAMIC_DNS_KEY]);
if (error) return callback(error);
callback(null, !!enabled); // settingsdb holds string values only
});
}
function setDynamicDnsConfig(enabled, callback) {
assert.strictEqual(typeof enabled, 'boolean');
assert.strictEqual(typeof callback, 'function');
// settingsdb takes string values only
settingsdb.set(exports.DYNAMIC_DNS_KEY, enabled ? 'enabled' : '', function (error) {
if (error) return callback(error);
notifyChange(exports.DYNAMIC_DNS_KEY, enabled);
return callback(null);
});
}
function getUnstableAppsConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.UNSTABLE_APPS_KEY, function (error, enabled) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.UNSTABLE_APPS_KEY]);
if (error) return callback(error);
callback(null, !!enabled); // settingsdb holds string values only
});
}
function setUnstableAppsConfig(enabled, callback) {
assert.strictEqual(typeof enabled, 'boolean');
assert.strictEqual(typeof callback, 'function');
// settingsdb takes string values only
settingsdb.set(exports.UNSTABLE_APPS_KEY, enabled ? 'enabled' : '', function (error) {
if (error) return callback(error);
notifyChange(exports.UNSTABLE_APPS_KEY, enabled);
return callback(null);
});
}
function getBackupConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.BACKUP_CONFIG_KEY, async function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.BACKUP_CONFIG_KEY]);
if (error) return callback(error);
const backupConfig = JSON.parse(value); // provider, token, password, region, prefix, bucket
if (backupConfig.provider === 'sshfs' || backupConfig.provider === 'cifs' || backupConfig.provider === 'nfs' || backupConfig.provider === 'ext4' || backupConfig.provider === 'mountpoint') {
backupConfig.mountStatus = await mounts.getStatus(backupConfig.provider, backupConfig.mountPoint); // { state, message }
}
callback(null, backupConfig);
});
}
function mountOptionsChanged(currentConfig, backupConfig) {
return currentConfig.provider !== backupConfig.provider
|| currentConfig.mountPoint !== backupConfig.mountPoint
|| !_.isEqual(currentConfig.mountOptions, backupConfig.mountOptions);
}
function setBackupConfig(backupConfig, callback) {
assert.strictEqual(typeof backupConfig, 'object');
assert.strictEqual(typeof callback, 'function');
getBackupConfig(async function (error, oldConfig) {
if (error) return callback(error);
backups.injectPrivateFields(backupConfig, oldConfig);
let oldMount = null, newMount = null;
if (backups.isMountProvider(oldConfig.provider)) {
oldMount = {
name: 'backup',
hostPath: oldConfig.mountPoint,
mountType: oldConfig.provider,
mountOptions: oldConfig.mountOptions
};
}
if (backups.isMountProvider(backupConfig.provider) && (!backups.isMountProvider(oldConfig.provider) || mountOptionsChanged(oldConfig, backupConfig))) {
error = mounts.validateMountOptions(backupConfig.provider, backupConfig.mountOptions);
if (error) return callback(error);
newMount = {
name: 'backup',
hostPath: backupConfig.mountPoint,
mountType: backupConfig.provider,
mountOptions: backupConfig.mountOptions
};
[error] = await safe(mounts.tryAddMount(newMount, oldMount, { times: 20, interval: 500 })); // 10 seconds
if (error) return callback(error);
}
backups.testConfig(backupConfig, async function (error) {
if (error) return callback(error);
if ('password' in backupConfig) { // user set password
backupConfig.encryption = backups.generateEncryptionKeysSync(backupConfig.password);
delete backupConfig.password;
}
// if any of these changes, we have to clear the cache
if ([ 'format', 'provider', 'prefix', 'bucket', 'region', 'endpoint', 'backupFolder', 'mountPoint', 'encryption' ].some(p => backupConfig[p] !== oldConfig[p])) {
debug('setBackupConfig: clearing backup cache');
backups.cleanupCacheFilesSync();
}
settingsdb.set(exports.BACKUP_CONFIG_KEY, JSON.stringify(backupConfig), async function (error) {
if (error) return callback(error);
if (oldMount && (!backups.isMountProvider(backupConfig.provider) || (newMount && newMount.hostPath !== oldMount.hostPath))) {
debug('setBackupConfig: removing old mount configuration');
await safe(mounts.removeMount(oldMount));
}
notifyChange(exports.BACKUP_CONFIG_KEY, backupConfig);
backups.configureCollectd(backupConfig, callback);
});
});
});
}
function setBackupCredentials(credentials, callback) {
assert.strictEqual(typeof credentials, 'object');
assert.strictEqual(typeof callback, 'function');
getBackupConfig(function (error, currentConfig) {
if (error) return callback(error);
// preserve these fields
const extra = _.pick(currentConfig, 'retentionPolicy', 'schedulePattern', 'copyConcurrency', 'syncConcurrency', 'memoryLimit', 'downloadConcurrency', 'deleteConcurrency', 'uploadPartSize');
const backupConfig = _.extend({}, credentials, extra);
backups.cleanupCacheFilesSync();
settingsdb.set(exports.BACKUP_CONFIG_KEY, JSON.stringify(backupConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.BACKUP_CONFIG_KEY, backupConfig);
backups.configureCollectd(backupConfig, callback);
});
});
}
function getServicesConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.SERVICES_CONFIG_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.SERVICES_CONFIG_KEY]);
if (error) return callback(error);
callback(null, JSON.parse(value));
});
}
function setServicesConfig(platformConfig, callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.SERVICES_CONFIG_KEY, JSON.stringify(platformConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.SERVICES_CONFIG_KEY, platformConfig);
callback(null);
});
}
function getExternalLdapConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.EXTERNAL_LDAP_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.EXTERNAL_LDAP_KEY]);
if (error) return callback(error);
let config = JSON.parse(value);
// ensure new keys
if (!config.autoCreate) config.autoCreate = false;
callback(null, config);
});
}
function setExternalLdapConfig(externalLdapConfig, callback) {
assert.strictEqual(typeof externalLdapConfig, 'object');
assert.strictEqual(typeof callback, 'function');
if (isDemo()) return callback(new BoxError(BoxError.BAD_FIELD, 'Not allowed in demo mode'));
getExternalLdapConfig(function (error, currentConfig) {
if (error) return callback(error);
externalLdap.injectPrivateFields(externalLdapConfig, currentConfig);
externalLdap.testConfig(externalLdapConfig, function (error) {
if (error) return callback(error);
settingsdb.set(exports.EXTERNAL_LDAP_KEY, JSON.stringify(externalLdapConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.EXTERNAL_LDAP_KEY, externalLdapConfig);
callback(null);
});
});
});
}
function getRegistryConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.REGISTRY_CONFIG_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.REGISTRY_CONFIG_KEY]);
if (error) return callback(error);
callback(null, JSON.parse(value));
});
}
function setRegistryConfig(registryConfig, callback) {
assert.strictEqual(typeof registryConfig, 'object');
assert.strictEqual(typeof callback, 'function');
getRegistryConfig(function (error, curentConfig) {
if (error) return callback(error);
docker.injectPrivateFields(registryConfig, curentConfig);
docker.testRegistryConfig(registryConfig, function (error) {
if (error) return callback(error);
settingsdb.set(exports.REGISTRY_CONFIG_KEY, JSON.stringify(registryConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.REGISTRY_CONFIG_KEY, registryConfig);
callback(null);
});
});
});
}
function getSysinfoConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.SYSINFO_CONFIG_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.SYSINFO_CONFIG_KEY]);
if (error) return callback(error);
callback(null, JSON.parse(value));
});
}
function setSysinfoConfig(sysinfoConfig, callback) {
assert.strictEqual(typeof sysinfoConfig, 'object');
assert.strictEqual(typeof callback, 'function');
if (isDemo()) return callback(new BoxError(BoxError.BAD_FIELD, 'Not allowed in demo mode'));
sysinfo.testConfig(sysinfoConfig, function (error) {
if (error) return callback(error);
settingsdb.set(exports.SYSINFO_CONFIG_KEY, JSON.stringify(sysinfoConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.SYSINFO_CONFIG_KEY, sysinfoConfig);
callback(null);
});
});
}
function getDirectoryConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.DIRECTORY_CONFIG_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.DIRECTORY_CONFIG_KEY]);
if (error) return callback(error);
callback(null, JSON.parse(value));
});
}
function setDirectoryConfig(directoryConfig, callback) {
assert.strictEqual(typeof directoryConfig, 'object');
assert.strictEqual(typeof callback, 'function');
if (isDemo()) return callback(new BoxError(BoxError.BAD_FIELD, 'Not allowed in demo mode'));
settingsdb.set(exports.DIRECTORY_CONFIG_KEY, JSON.stringify(directoryConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.DIRECTORY_CONFIG_KEY, directoryConfig);
callback(null);
});
}
function getAppstoreListingConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.APPSTORE_LISTING_CONFIG_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.APPSTORE_LISTING_CONFIG_KEY]);
if (error) return callback(error);
callback(null, JSON.parse(value));
});
}
function setAppstoreListingConfig(listingConfig, callback) {
assert.strictEqual(typeof listingConfig, 'object');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.APPSTORE_LISTING_CONFIG_KEY, JSON.stringify(listingConfig), function (error) {
if (error) return callback(error);
notifyChange(exports.APPSTORE_LISTING_CONFIG_KEY, listingConfig);
callback(null);
});
}
function getFirewallBlocklist(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.getBlob(exports.FIREWALL_BLOCKLIST_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.FIREWALL_BLOCKLIST_KEY]);
if (error) return callback(error);
callback(null, value.toString('utf8'));
});
}
function setFirewallBlocklist(blocklist, callback) {
assert.strictEqual(typeof blocklist, 'string');
assert.strictEqual(typeof callback, 'function');
// store in blob since the value field is TEXT and has 16kb size limit
settingsdb.setBlob(exports.FIREWALL_BLOCKLIST_KEY, Buffer.from(blocklist), function (error) {
if (error) return callback(error);
callback(null);
});
}
function getSupportConfig(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.SUPPORT_CONFIG_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.SUPPORT_CONFIG_KEY]);
if (error) return callback(error);
callback(null, JSON.parse(value));
});
}
function getLicenseKey(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.LICENSE_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.LICENSE_KEY]);
if (error) return callback(error);
callback(null, value);
});
}
function setLicenseKey(licenseKey, callback) {
assert.strictEqual(typeof licenseKey, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.LICENSE_KEY, licenseKey, function (error) {
if (error) return callback(error);
notifyChange(exports.LICENSE_KEY, licenseKey);
callback(null);
});
}
function getLanguage(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.LANGUAGE_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.LANGUAGE_KEY]);
if (error) return callback(error);
callback(null, value);
});
}
function setLanguage(language, callback) {
assert.strictEqual(typeof language, 'string');
assert.strictEqual(typeof callback, 'function');
translation.getLanguages(function (error, languages) {
if (error) return callback(error);
if (languages.indexOf(language) === -1) return callback(new BoxError(BoxError.NOT_FOUND));
settingsdb.set(exports.LANGUAGE_KEY, language, function (error) {
if (error) return callback(error);
notifyChange(exports.LANGUAGE_KEY, language);
callback(null);
});
});
}
function getCloudronId(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.CLOUDRON_ID_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.CLOUDRON_ID_KEY]);
if (error) return callback(error);
callback(null, value);
});
}
function setCloudronId(cid, callback) {
assert.strictEqual(typeof cid, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.CLOUDRON_ID_KEY, cid, function (error) {
if (error) return callback(error);
notifyChange(exports.CLOUDRON_ID_KEY, cid);
callback(null);
});
}
function getCloudronToken(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.CLOUDRON_TOKEN_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.CLOUDRON_TOKEN_KEY]);
if (error) return callback(error);
callback(null, value);
});
}
function setCloudronToken(token, callback) {
assert.strictEqual(typeof token, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.CLOUDRON_TOKEN_KEY, token, function (error) {
if (error) return callback(error);
notifyChange(exports.CLOUDRON_TOKEN_KEY, token);
callback(null);
});
}
function getAll(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.getAll(function (error, settings) {
if (error) return callback(error);
var result = _.extend({ }, gDefaults);
settings.forEach(function (setting) { result[setting.name] = setting.value; });
// convert booleans
result[exports.DYNAMIC_DNS_KEY] = !!result[exports.DYNAMIC_DNS_KEY];
result[exports.UNSTABLE_APPS_KEY] = !!result[exports.UNSTABLE_APPS_KEY];
result[exports.DEMO_KEY] = !!result[exports.DEMO_KEY];
// convert JSON objects
[exports.BACKUP_CONFIG_KEY, exports.DIRECTORY_CONFIG_KEY, exports.SERVICES_CONFIG_KEY, exports.EXTERNAL_LDAP_KEY, exports.REGISTRY_CONFIG_KEY, exports.SYSINFO_CONFIG_KEY ].forEach(function (key) {
result[key] = typeof result[key] === 'object' ? result[key] : safe.JSON.parse(result[key]);
});
callback(null, result);
});
}
function initCache(callback) {
debug('initCache: pre-load settings');
getAll(function (error, allSettings) {
if (error) return callback(error);
const provider = safe.fs.readFileSync(paths.PROVIDER_FILE, 'utf8');
gCache = {
apiServerOrigin: allSettings[exports.API_SERVER_ORIGIN_KEY],
webServerOrigin: allSettings[exports.WEB_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],
isDemo: allSettings[exports.DEMO_KEY],
provider: provider ? provider.trim() : 'generic'
};
callback();
});
}
// this is together so we can do this in a transaction later
function setDashboardLocation(dashboardDomain, dashboardFqdn, callback) {
assert.strictEqual(typeof dashboardDomain, 'string');
assert.strictEqual(typeof dashboardFqdn, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.DASHBOARD_DOMAIN_KEY, dashboardDomain, function (error) {
if (error) return callback(error);
settingsdb.set(exports.DASHBOARD_FQDN_KEY, dashboardFqdn, function (error) {
if (error) return callback(error);
gCache.dashboardDomain = dashboardDomain;
gCache.dashboardFqdn = dashboardFqdn;
callback(null);
});
});
}
function setMailLocation(mailDomain, mailFqdn, callback) {
assert.strictEqual(typeof mailDomain, 'string');
assert.strictEqual(typeof mailFqdn, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.MAIL_DOMAIN_KEY, mailDomain, function (error) {
if (error) return callback(error);
settingsdb.set(exports.MAIL_FQDN_KEY, mailFqdn, function (error) {
if (error) return callback(error);
gCache.mailDomain = mailDomain;
gCache.mailFqdn = mailFqdn;
callback(null);
});
});
}
function setApiServerOrigin(origin, callback) {
assert.strictEqual(typeof origin, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.API_SERVER_ORIGIN_KEY, origin, function (error) {
if (error) return callback(error);
gCache.apiServerOrigin = origin;
notifyChange(exports.API_SERVER_ORIGIN_KEY, origin);
callback(null);
});
}
function getFooter(callback) {
assert.strictEqual(typeof callback, 'function');
settingsdb.get(exports.FOOTER_KEY, function (error, value) {
if (error && error.reason === BoxError.NOT_FOUND) return callback(null, gDefaults[exports.FOOTER_KEY]);
if (error) return callback(error);
callback(null, value);
});
}
function setFooter(footer, callback) {
assert.strictEqual(typeof footer, 'string');
assert.strictEqual(typeof callback, 'function');
settingsdb.set(exports.FOOTER_KEY, footer, function (error) {
if (error) return callback(error);
notifyChange(exports.FOOTER_KEY, footer);
callback(null);
});
}
function provider() { return gCache.provider; }
function apiServerOrigin() { return gCache.apiServerOrigin; }
function webServerOrigin() { return gCache.webServerOrigin; }
function dashboardDomain() { return gCache.dashboardDomain; }
function dashboardFqdn() { return gCache.dashboardFqdn; }
function isDemo() { return gCache.isDemo; }
function mailDomain() { return gCache.mailDomain; }
function mailFqdn() { return gCache.mailFqdn; }
function dashboardOrigin() { return 'https://' + dashboardFqdn(); }