+33
-5
@@ -42,6 +42,7 @@ exports = module.exports = {
|
||||
setEnvironment,
|
||||
setMailbox,
|
||||
setInbox,
|
||||
setTurn,
|
||||
setLocation,
|
||||
setStorage,
|
||||
repair,
|
||||
@@ -106,6 +107,7 @@ exports = module.exports = {
|
||||
ISTATE_PENDING_CONFIGURE: 'pending_configure', // infra update
|
||||
ISTATE_PENDING_RECREATE_CONTAINER: 'pending_recreate_container', // env change or addon change
|
||||
ISTATE_PENDING_LOCATION_CHANGE: 'pending_location_change',
|
||||
ISTATE_PENDING_SERVICES_CHANGE: 'pending_services_change',
|
||||
ISTATE_PENDING_DATA_DIR_MIGRATION: 'pending_data_dir_migration',
|
||||
ISTATE_PENDING_RESIZE: 'pending_resize',
|
||||
ISTATE_PENDING_DEBUG: 'pending_debug',
|
||||
@@ -198,7 +200,7 @@ const APPS_FIELDS_PREFIXED = [ 'apps.id', 'apps.appStoreId', 'apps.installationS
|
||||
'apps.sso', 'apps.debugModeJson', 'apps.enableBackup', 'apps.proxyAuth', 'apps.containerIp', 'apps.crontab',
|
||||
'apps.creationTime', 'apps.updateTime', 'apps.enableAutomaticUpdate', 'apps.upstreamUri',
|
||||
'apps.enableMailbox', 'apps.mailboxDisplayName', 'apps.mailboxName', 'apps.mailboxDomain', 'apps.enableInbox', 'apps.inboxName', 'apps.inboxDomain',
|
||||
'apps.storageVolumeId', 'apps.storageVolumePrefix', 'apps.ts', 'apps.healthTime', '(apps.icon IS NOT NULL) AS hasIcon', '(apps.appStoreIcon IS NOT NULL) AS hasAppStoreIcon' ].join(',');
|
||||
'apps.enableTurn', 'apps.storageVolumeId', 'apps.storageVolumePrefix', 'apps.ts', 'apps.healthTime', '(apps.icon IS NOT NULL) AS hasIcon', '(apps.appStoreIcon IS NOT NULL) AS hasAppStoreIcon' ].join(',');
|
||||
|
||||
// const PORT_BINDINGS_FIELDS = [ 'hostPort', 'type', 'environmentVariable', 'appId' ].join(',');
|
||||
const LOCATION_FIELDS = [ 'appId', 'subdomain', 'domain', 'type', 'certificateJson' ];
|
||||
@@ -593,7 +595,7 @@ function removeInternalFields(app) {
|
||||
'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuShares', 'operators',
|
||||
'sso', 'debugMode', 'reverseProxyConfig', 'enableBackup', 'creationTime', 'updateTime', 'ts', 'tags',
|
||||
'label', 'secondaryDomains', 'redirectDomains', 'aliasDomains', 'env', 'enableAutomaticUpdate',
|
||||
'storageVolumeId', 'storageVolumePrefix', 'mounts',
|
||||
'storageVolumeId', 'storageVolumePrefix', 'mounts', 'enableTurn',
|
||||
'enableMailbox', 'mailboxDisplayName', 'mailboxName', 'mailboxDomain', 'enableInbox', 'inboxName', 'inboxDomain');
|
||||
|
||||
removeCertificateKeys(result);
|
||||
@@ -840,6 +842,7 @@ async function add(id, appStoreId, manifest, subdomain, domain, portBindings, da
|
||||
servicesConfigJson = data.servicesConfig ? JSON.stringify(data.servicesConfig) : null,
|
||||
enableMailbox = data.enableMailbox || false,
|
||||
upstreamUri = data.upstreamUri || '',
|
||||
enableTurn = 'enableTurn' in data ? data.enableTurn : true,
|
||||
icon = data.icon || null;
|
||||
|
||||
const queries = [];
|
||||
@@ -847,11 +850,11 @@ async function add(id, appStoreId, manifest, subdomain, domain, portBindings, da
|
||||
queries.push({
|
||||
query: 'INSERT INTO apps (id, appStoreId, manifestJson, installationState, runState, accessRestrictionJson, memoryLimit, cpuShares, '
|
||||
+ 'sso, debugModeJson, mailboxName, mailboxDomain, label, tagsJson, reverseProxyConfigJson, servicesConfigJson, icon, '
|
||||
+ 'enableMailbox, mailboxDisplayName, upstreamUri) '
|
||||
+ ' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
+ 'enableMailbox, mailboxDisplayName, upstreamUri, enableTurn) '
|
||||
+ ' VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)',
|
||||
args: [ id, appStoreId, manifestJson, installationState, runState, accessRestrictionJson, memoryLimit, cpuShares,
|
||||
sso, debugModeJson, mailboxName, mailboxDomain, label, tagsJson, reverseProxyConfigJson, servicesConfigJson, icon,
|
||||
enableMailbox, mailboxDisplayName, upstreamUri ]
|
||||
enableMailbox, mailboxDisplayName, upstreamUri, enableTurn ]
|
||||
});
|
||||
|
||||
queries.push({
|
||||
@@ -1324,6 +1327,7 @@ async function install(data, auditSource) {
|
||||
tags = data.tags || [],
|
||||
overwriteDns = 'overwriteDns' in data ? data.overwriteDns : false,
|
||||
skipDnsSetup = 'skipDnsSetup' in data ? data.skipDnsSetup : false,
|
||||
enableTurn = 'enableTurn' in data ? data.enableTurn : true,
|
||||
appStoreId = data.appStoreId,
|
||||
upstreamUri = data.upstreamUri || '',
|
||||
manifest = data.manifest;
|
||||
@@ -1411,6 +1415,7 @@ async function install(data, auditSource) {
|
||||
icon,
|
||||
enableMailbox,
|
||||
upstreamUri,
|
||||
enableTurn,
|
||||
runState: exports.RSTATE_RUNNING,
|
||||
installationState: exports.ISTATE_PENDING_INSTALL
|
||||
};
|
||||
@@ -1733,6 +1738,29 @@ async function setInbox(app, data, auditSource) {
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
async function setTurn(app, enableTurn, auditSource) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof enableTurn, 'boolean');
|
||||
assert.strictEqual(typeof auditSource, 'object');
|
||||
|
||||
const appId = app.id;
|
||||
let error = checkAppState(app, exports.ISTATE_PENDING_SERVICES_CHANGE);
|
||||
if (error) throw error;
|
||||
|
||||
if (!app.manifest.addons?.turn) throw new BoxError(BoxError.BAD_FIELD, 'App does not use turn addon');
|
||||
if (!app.manifest.addons.turn.optional) throw new BoxError(BoxError.BAD_FIELD, 'turn service is not optional');
|
||||
|
||||
const task = {
|
||||
args: {},
|
||||
values: { enableTurn }
|
||||
};
|
||||
const taskId = await addTask(appId, exports.ISTATE_PENDING_SERVICES_CHANGE, task, auditSource);
|
||||
|
||||
await eventlog.add(eventlog.ACTION_APP_CONFIGURE, auditSource, { appId, app, enableTurn, taskId });
|
||||
|
||||
return { taskId };
|
||||
}
|
||||
|
||||
async function setAutomaticBackup(app, enable, auditSource) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof enable, 'boolean');
|
||||
|
||||
@@ -508,6 +508,31 @@ async function changeLocation(app, args, progressCallback) {
|
||||
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
|
||||
}
|
||||
|
||||
async function changeServices(app, args, progressCallback) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof args, 'object');
|
||||
assert.strictEqual(typeof progressCallback, 'function');
|
||||
|
||||
await progressCallback({ percent: 10, message: 'Cleaning up old install' });
|
||||
await deleteContainers(app, { managedOnly: true });
|
||||
|
||||
const unusedAddons = {};
|
||||
if (app.manifest.addons.turn && !args.enableTurn) unusedAddons.turn = app.manifest.addons.turn;
|
||||
await progressCallback({ percent: 20, message: 'Removing unused addons' });
|
||||
await services.teardownAddons(app, unusedAddons);
|
||||
|
||||
await progressCallback({ percent: 40, message: 'Setting up addons' });
|
||||
await services.setupAddons(app, app.manifest.addons);
|
||||
|
||||
await progressCallback({ percent: 60, message: 'Creating container' });
|
||||
await createContainer(app);
|
||||
|
||||
await startApp(app);
|
||||
|
||||
await progressCallback({ percent: 100, message: 'Done' });
|
||||
await updateApp(app, { installationState: apps.ISTATE_INSTALLED, error: null, health: null });
|
||||
}
|
||||
|
||||
async function migrateDataDir(app, args, progressCallback) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof args, 'object');
|
||||
@@ -773,6 +798,9 @@ async function run(appId, args, progressCallback) {
|
||||
case apps.ISTATE_PENDING_LOCATION_CHANGE:
|
||||
cmd = changeLocation(app, args, progressCallback);
|
||||
break;
|
||||
case apps.ISTATE_PENDING_SERVICES_CHANGE:
|
||||
cmd = changeServices(app, args, progressCallback);
|
||||
break;
|
||||
case apps.ISTATE_PENDING_DATA_DIR_MIGRATION:
|
||||
cmd = migrateDataDir(app, args, progressCallback);
|
||||
break;
|
||||
|
||||
@@ -24,6 +24,7 @@ exports = module.exports = {
|
||||
setLabel,
|
||||
setTags,
|
||||
setIcon,
|
||||
setTurn,
|
||||
setMemoryLimit,
|
||||
setCpuShares,
|
||||
setAutomaticBackup,
|
||||
@@ -176,6 +177,8 @@ async function install(req, res, next) {
|
||||
if ('skipDnsSetup' in data && typeof data.skipDnsSetup !== 'boolean') return next(new HttpError(400, 'skipDnsSetup must be boolean'));
|
||||
if ('enableMailbox' in data && typeof data.enableMailbox !== 'boolean') return next(new HttpError(400, 'enableMailbox must be boolean'));
|
||||
|
||||
if ('enableTurn' in data && typeof data.enableTurn !== 'boolean') return next(new HttpError(400, 'enableTurn must be boolean'));
|
||||
|
||||
let [error, result] = await safe(apps.downloadManifest(data.appStoreId, data.manifest));
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
@@ -407,6 +410,18 @@ async function setInbox(req, res, next) {
|
||||
next(new HttpSuccess(202, { taskId: result.taskId }));
|
||||
}
|
||||
|
||||
async function setTurn(req, res, next) {
|
||||
assert.strictEqual(typeof req.body, 'object');
|
||||
assert.strictEqual(typeof req.app, 'object');
|
||||
|
||||
if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean'));
|
||||
|
||||
const [error, result] = await safe(apps.setTurn(req.app, req.body.enable, AuditSource.fromRequest(req)));
|
||||
if (error) return next(BoxError.toHttpError(error));
|
||||
|
||||
next(new HttpSuccess(202, { taskId: result.taskId }));
|
||||
}
|
||||
|
||||
async function setLocation(req, res, next) {
|
||||
assert.strictEqual(typeof req.body, 'object');
|
||||
assert.strictEqual(typeof req.app, 'object');
|
||||
|
||||
@@ -231,6 +231,7 @@ async function initializeExpressSync() {
|
||||
router.post('/api/v1/apps/:id/configure/debug_mode', json, token, routes.apps.load, authorizeOperator, routes.apps.setDebugMode);
|
||||
router.post('/api/v1/apps/:id/configure/mailbox', json, token, routes.apps.load, authorizeAdmin, routes.apps.setMailbox);
|
||||
router.post('/api/v1/apps/:id/configure/inbox', json, token, routes.apps.load, authorizeAdmin, routes.apps.setInbox);
|
||||
router.post('/api/v1/apps/:id/configure/turn', json, token, routes.apps.load, authorizeAdmin, routes.apps.setTurn);
|
||||
router.post('/api/v1/apps/:id/configure/env', json, token, routes.apps.load, authorizeOperator, routes.apps.setEnvironment);
|
||||
router.post('/api/v1/apps/:id/configure/storage', json, token, routes.apps.load, authorizeAdmin, routes.apps.setStorage);
|
||||
router.post('/api/v1/apps/:id/configure/location', json, token, routes.apps.load, authorizeAdmin, routes.apps.setLocation);
|
||||
|
||||
@@ -887,6 +887,9 @@ async function setupTurn(app, options) {
|
||||
assert.strictEqual(typeof app, 'object');
|
||||
assert.strictEqual(typeof options, 'object');
|
||||
|
||||
const disabled = app.manifest.addons.turn.optional && !app.enableTurn;
|
||||
if (disabled) return await addonConfigs.set(app.id, 'turn', []);
|
||||
|
||||
const turnSecret = await blobs.getString(blobs.ADDON_TURN_SECRET);
|
||||
if (!turnSecret) throw new BoxError(BoxError.ADDONS_ERROR, 'Turn secret is missing');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user