6ace8d1ac5
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.
936 lines
30 KiB
JavaScript
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(); }
|