Start using req.resources = { app, volume, ...} pattern

Reason was that req.app was clashing with expressjs v5 which
stores the main expressjs app object there
This commit is contained in:
Johannes Zellner
2025-06-10 11:02:41 +02:00
parent a556237963
commit 2e4bc5e218
12 changed files with 223 additions and 207 deletions
+2 -2
View File
@@ -90,11 +90,11 @@ function authorize(requiredRole) {
async function authorizeOperator(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
assert.strictEqual(typeof req.user, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.token, 'object');
if (!tokens.hasScope(req.token, req.method, req.path)) return next(new HttpError(403, 'access token does not have this scope'));
if (apps.isOperator(req.app, req.user)) return next();
if (apps.isOperator(req.resources.app, req.user)) return next();
return next(new HttpError(403, 'user is not an operator'));
}
+7 -7
View File
@@ -25,7 +25,7 @@ async function load(req, res, next) {
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'Applink not found'));
req.resource = result;
req.resources.applink = result;
next();
}
@@ -63,9 +63,9 @@ async function get(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
// we have a separate route for this
delete req.resource.icon;
delete req.resources.applink.icon;
next(new HttpSuccess(200, req.resource));
next(new HttpSuccess(200, req.resources.applink));
}
async function update(req, res, next) {
@@ -78,7 +78,7 @@ async function update(req, res, next) {
if ('tags' in req.body && !Array.isArray(req.body.tags)) return next(new HttpError(400, 'tags must be an array with strings'));
if ('icon' in req.body && typeof req.body.icon !== 'string') return next(new HttpError(400, 'icon must be a string'));
const [error] = await safe(applinks.update(req.resource, req.body));
const [error] = await safe(applinks.update(req.resources.applink, req.body));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -87,14 +87,14 @@ async function update(req, res, next) {
async function del(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
const [error] = await safe(applinks.del(req.resource));
const [error] = await safe(applinks.del(req.resources.applink));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
}
async function getIcon(req, res, next) {
async function getIcon(req, res) {
assert.strictEqual(typeof req.params.id, 'string');
res.send(req.resource.icon);
res.send(req.resources.applink.icon);
}
+112 -112
View File
@@ -92,16 +92,16 @@ async function load(req, res, next) {
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'App not found'));
req.app = result;
req.resources.app = result;
next();
}
function getApp(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const accessLevel = apps.accessLevel(req.app, req.user);
const result = apps.pickFields(req.app, accessLevel);
const accessLevel = apps.accessLevel(req.resources.app, req.user);
const result = apps.pickFields(req.resources.app, accessLevel);
result.accessLevel = accessLevel;
next(new HttpSuccess(200, result));
@@ -124,9 +124,9 @@ async function listByUser(req, res, next) {
}
async function getAppIcon(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, icon] = await safe(apps.getIcon(req.app, { original: req.query.original }));
const [error, icon] = await safe(apps.getIcon(req.resources.app, { original: req.query.original }));
if (error) return next(BoxError.toHttpError(error));
res.send(icon);
@@ -208,11 +208,11 @@ async function install(req, res, next) {
async function setAccessRestriction(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.accessRestriction !== 'object') return next(new HttpError(400, 'accessRestriction must be an object'));
const [error] = await safe(apps.setAccessRestriction(req.app, req.body.accessRestriction, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setAccessRestriction(req.resources.app, req.body.accessRestriction, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -220,11 +220,11 @@ async function setAccessRestriction(req, res, next) {
async function setOperators(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.operators !== 'object') return next(new HttpError(400, 'operators must be an object'));
const [error] = await safe(apps.setOperators(req.app, req.body.operators, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setOperators(req.resources.app, req.body.operators, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -232,11 +232,11 @@ async function setOperators(req, res, next) {
async function setCrontab(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (req.body.crontab !== null && typeof req.body.crontab !== 'string') return next(new HttpError(400, 'crontab must be a string'));
const [error] = await safe(apps.setCrontab(req.app, req.body.crontab, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setCrontab(req.resources.app, req.body.crontab, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -244,11 +244,11 @@ async function setCrontab(req, res, next) {
async function setLabel(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.label !== 'string') return next(new HttpError(400, 'label must be a string'));
const [error] = await safe(apps.setLabel(req.app, req.body.label, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setLabel(req.resources.app, req.body.label, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -256,12 +256,12 @@ async function setLabel(req, res, next) {
async function setTags(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (!Array.isArray(req.body.tags)) return next(new HttpError(400, 'tags must be an array'));
if (req.body.tags.some((t) => typeof t !== 'string')) return next(new HttpError(400, 'tags array must contain strings'));
const [error] = await safe(apps.setTags(req.app, req.body.tags, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setTags(req.resources.app, req.body.tags, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -269,11 +269,11 @@ async function setTags(req, res, next) {
async function setNotes(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.notes !== 'string') return next(new HttpError(400, 'notes must be a string'));
const [error] = await safe(apps.setNotes(req.app, req.body.notes, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setNotes(req.resources.app, req.body.notes, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -281,11 +281,11 @@ async function setNotes(req, res, next) {
async function setChecklistItem(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.done !== 'boolean') return next(new HttpError(400, 'done must be a boolean'));
const [error] = await safe(apps.setChecklistItem(req.app, req.params.key, req.body.done, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setChecklistItem(req.resources.app, req.params.key, req.body.done, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
@@ -293,11 +293,11 @@ async function setChecklistItem(req, res, next) {
async function setIcon(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (req.body.icon !== null && typeof req.body.icon !== 'string') return next(new HttpError(400, 'icon is null or a base-64 image string'));
const [error] = await safe(apps.setIcon(req.app, req.body.icon || null /* empty string means null */, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setIcon(req.resources.app, req.body.icon || null /* empty string means null */, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -305,11 +305,11 @@ async function setIcon(req, res, next) {
async function setMemoryLimit(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.memoryLimit !== 'number') return next(new HttpError(400, 'memoryLimit is not a number'));
const [error, result] = await safe(apps.setMemoryLimit(req.app, req.body.memoryLimit, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setMemoryLimit(req.resources.app, req.body.memoryLimit, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -317,11 +317,11 @@ async function setMemoryLimit(req, res, next) {
async function setCpuQuota(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.cpuQuota !== 'number') return next(new HttpError(400, 'cpuQuota is not a number'));
const [error, result] = await safe(apps.setCpuQuota(req.app, req.body.cpuQuota, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setCpuQuota(req.resources.app, req.body.cpuQuota, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -329,11 +329,11 @@ async function setCpuQuota(req, res, next) {
async function setAutomaticBackup(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean'));
const [error] = await safe(apps.setAutomaticBackup(req.app, req.body.enable, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setAutomaticBackup(req.resources.app, req.body.enable, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -341,11 +341,11 @@ async function setAutomaticBackup(req, res, next) {
async function setAutomaticUpdate(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean'));
const [error] = await safe(apps.setAutomaticUpdate(req.app, req.body.enable, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setAutomaticUpdate(req.resources.app, req.body.enable, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -353,7 +353,7 @@ async function setAutomaticUpdate(req, res, next) {
async function setReverseProxyConfig(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (req.body.robotsTxt !== null && typeof req.body.robotsTxt !== 'string') return next(new HttpError(400, 'robotsTxt is not a string'));
@@ -361,7 +361,7 @@ async function setReverseProxyConfig(req, res, next) {
if (typeof req.body.hstsPreload !== 'boolean') return next(new HttpError(400, 'hstsPreload must be a boolean'));
const [error] = await safe(apps.setReverseProxyConfig(req.app, req.body, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setReverseProxyConfig(req.resources.app, req.body, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -369,7 +369,7 @@ async function setReverseProxyConfig(req, res, next) {
async function setCertificate(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.subdomain !== 'string') return next(new HttpError(400, 'subdomain must be string')); // subdomain may be an empty string
if (!req.body.domain) return next(new HttpError(400, 'domain is required'));
@@ -380,7 +380,7 @@ async function setCertificate(req, res, next) {
if (req.body.cert && !req.body.key) return next(new HttpError(400, 'key must be provided'));
if (!req.body.cert && req.body.key) return next(new HttpError(400, 'cert must be provided'));
const [error] = await safe(apps.setCertificate(req.app, req.body, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setCertificate(req.resources.app, req.body, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -388,12 +388,12 @@ async function setCertificate(req, res, next) {
async function setEnvironment(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (!req.body.env || typeof req.body.env !== 'object') return next(new HttpError(400, 'env must be an object'));
if (Object.keys(req.body.env).some((key) => typeof req.body.env[key] !== 'string')) return next(new HttpError(400, 'env must contain values as strings'));
const [error, result] = await safe(apps.setEnvironment(req.app, req.body.env, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setEnvironment(req.resources.app, req.body.env, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -401,11 +401,11 @@ async function setEnvironment(req, res, next) {
async function setDebugMode(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (req.body.debugMode !== null && typeof req.body.debugMode !== 'object') return next(new HttpError(400, 'debugMode must be an object'));
const [error, result] = await safe(apps.setDebugMode(req.app, req.body.debugMode, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setDebugMode(req.resources.app, req.body.debugMode, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -413,7 +413,7 @@ async function setDebugMode(req, res, next) {
async function setMailbox(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean'));
if (req.body.enable) {
@@ -422,7 +422,7 @@ async function setMailbox(req, res, next) {
if ('mailboxDisplayName' in req.body && typeof req.body.mailboxDisplayName !== 'string') return next(new HttpError(400, 'mailboxDisplayName must be a string'));
}
const [error, result] = await safe(apps.setMailbox(req.app, req.body, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setMailbox(req.resources.app, req.body, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -430,7 +430,7 @@ async function setMailbox(req, res, next) {
async function setInbox(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean'));
if (req.body.enable) {
@@ -438,7 +438,7 @@ async function setInbox(req, res, next) {
if (typeof req.body.inboxDomain !== 'string') return next(new HttpError(400, 'inboxDomain must be a string'));
}
const [error, result] = await safe(apps.setInbox(req.app, req.body, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setInbox(req.resources.app, req.body, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -446,11 +446,11 @@ async function setInbox(req, res, next) {
async function setTurn(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.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)));
const [error, result] = await safe(apps.setTurn(req.resources.app, req.body.enable, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -458,11 +458,11 @@ async function setTurn(req, res, next) {
async function setRedis(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.enable !== 'boolean') return next(new HttpError(400, 'enable must be a boolean'));
const [error, result] = await safe(apps.setRedis(req.app, req.body.enable, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setRedis(req.resources.app, req.body.enable, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -470,7 +470,7 @@ async function setRedis(req, res, next) {
async function setLocation(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.subdomain !== 'string') return next(new HttpError(400, 'subdomain must be string')); // subdomain may be an empty string
if (typeof req.body.domain !== 'string') return next(new HttpError(400, 'domain must be string'));
@@ -495,7 +495,7 @@ async function setLocation(req, res, next) {
if ('overwriteDns' in req.body && typeof req.body.overwriteDns !== 'boolean') return next(new HttpError(400, 'overwriteDns must be boolean'));
if ('skipDnsSetup' in req.body && typeof req.body.skipDnsSetup !== 'boolean') return next(new HttpError(400, 'skipDnsSetup must be boolean'));
const [error, result] = await safe(apps.setLocation(req.app, req.body, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setLocation(req.resources.app, req.body, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -503,7 +503,7 @@ async function setLocation(req, res, next) {
async function setStorage(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const { storageVolumeId, storageVolumePrefix } = req.body;
@@ -512,7 +512,7 @@ async function setStorage(req, res, next) {
if (typeof storageVolumePrefix !== 'string') return next(new HttpError(400, 'storageVolumePrefix must be a string'));
}
const [error, result] = await safe(apps.setStorage(req.app, storageVolumeId, storageVolumePrefix, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setStorage(req.resources.app, storageVolumeId, storageVolumePrefix, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -520,7 +520,7 @@ async function setStorage(req, res, next) {
async function repair(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const data = req.body;
@@ -534,7 +534,7 @@ async function repair(req, res, next) {
if (!data.dockerImage || typeof data.dockerImage !== 'string') return next(new HttpError(400, 'dockerImage must be a string'));
}
const [error, result] = await safe(apps.repair(req.app, data, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.repair(req.resources.app, data, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -542,13 +542,13 @@ async function repair(req, res, next) {
async function restore(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const data = req.body;
if (!data.backupId || typeof data.backupId !== 'string') return next(new HttpError(400, 'backupId must be non-empty string'));
const [error, result] = await safe(apps.restore(req.app, data.backupId, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.restore(req.resources.app, data.backupId, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -567,7 +567,7 @@ async function restore(req, res, next) {
// 3. backupConfig.password and backupConfig.encryptedFilenames
async function importApp(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const data = req.body;
@@ -589,7 +589,7 @@ async function importApp(req, res, next) {
}
}
const [error, result] = await safe(apps.importApp(req.app, data, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.importApp(req.resources.app, data, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -597,9 +597,9 @@ async function importApp(req, res, next) {
async function exportApp(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.exportApp(req.app, {}, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.exportApp(req.resources.app, {}, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -607,7 +607,7 @@ async function exportApp(req, res, next) {
async function clone(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const data = req.body;
@@ -624,63 +624,63 @@ async function clone(req, res, next) {
if ('overwriteDns' in req.body && typeof req.body.overwriteDns !== 'boolean') return next(new HttpError(400, 'overwriteDns must be boolean'));
if ('skipDnsSetup' in req.body && typeof req.body.skipDnsSetup !== 'boolean') return next(new HttpError(400, 'skipDnsSetup must be boolean'));
const [error, result] = await safe(apps.clone(req.app, data, req.user, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.clone(req.resources.app, data, req.user, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(201, { id: result.id, taskId: result.taskId }));
}
async function backup(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.backup(req.app, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.backup(req.resources.app, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
}
async function uninstall(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.uninstall(req.app, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.uninstall(req.resources.app, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
}
async function archive(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.backupId !== 'string') return next(new HttpError(400, 'backupId must be a string'));
const [error, result] = await safe(apps.archive(req.app, req.body.backupId, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.archive(req.resources.app, req.body.backupId, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId, id: result.id }));
}
async function start(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.start(req.app, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.start(req.resources.app, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
}
async function stop(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.stop(req.app, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.stop(req.resources.app, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
}
async function restart(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.restart(req.app, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.restart(req.resources.app, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -688,7 +688,7 @@ async function restart(req, res, next) {
async function update(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const data = req.body;
@@ -709,7 +709,7 @@ async function update(req, res, next) {
data.appStoreId = appStoreId;
data.manifest = manifest;
[error, result] = await safe(apps.updateApp(req.app, data, AuditSource.fromRequest(req)));
[error, result] = await safe(apps.updateApp(req.resources.app, data, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -717,7 +717,7 @@ async function update(req, res, next) {
// this route is for streaming logs
async function getLogStream(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const lines = 'lines' in req.query ? parseInt(req.query.lines, 10) : 10; // we ignore last-event-id
if (isNaN(lines)) return next(new HttpError(400, 'lines must be a valid number'));
@@ -730,7 +730,7 @@ async function getLogStream(req, res, next) {
format: 'json'
};
const [error, logStream] = await safe(apps.getLogs(req.app, options));
const [error, logStream] = await safe(apps.getLogs(req.resources.app, options));
if (error) return next(BoxError.toHttpError(error));
res.writeHead(200, {
@@ -752,7 +752,7 @@ async function getLogStream(req, res, next) {
}
async function getLogs(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const lines = 'lines' in req.query ? parseInt(req.query.lines, 10) : 10;
if (isNaN(lines)) return next(new HttpError(400, 'lines must be a number'));
@@ -763,12 +763,12 @@ async function getLogs(req, res, next) {
format: req.query.format || 'json'
};
const [error, logStream] = await safe(apps.getLogs(req.app, options));
const [error, logStream] = await safe(apps.getLogs(req.resources.app, options));
if (error) return next(BoxError.toHttpError(error));
res.writeHead(200, {
'Content-Type': 'application/x-logs',
'Content-Disposition': `attachment; filename="${req.app.id}.log"`,
'Content-Disposition': `attachment; filename="${req.resources.app.id}.log"`,
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no' // disable nginx buffering
});
@@ -799,7 +799,7 @@ function demuxStream(stream, stdin) {
}
async function createExec(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.body, 'object');
if ('cmd' in req.body) {
@@ -812,16 +812,16 @@ async function createExec(req, res, next) {
if ('lang' in req.body && typeof req.body.lang !== 'string') return next(new HttpError(400, 'lang must be a string'));
if (safe.query(req.app, 'manifest.addons.docker') && req.user.role !== users.ROLE_OWNER) return next(new HttpError(403, '"owner" role is requied to exec app with docker addon'));
if (safe.query(req.resources.app, 'manifest.addons.docker') && req.user.role !== users.ROLE_OWNER) return next(new HttpError(403, '"owner" role is requied to exec app with docker addon'));
const [error, id] = await safe(apps.createExec(req.app, { cmd, tty, lang: req.body.lang }));
const [error, id] = await safe(apps.createExec(req.resources.app, { cmd, tty, lang: req.body.lang }));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, { id }));
}
async function startExec(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.params.execId, 'string');
const columns = req.query.columns ? parseInt(req.query.columns, 10) : null;
@@ -832,12 +832,12 @@ async function startExec(req, res, next) {
const tty = req.query.tty === 'true';
if (safe.query(req.app, 'manifest.addons.docker') && req.user.role !== users.ROLE_OWNER) return next(new HttpError(403, '"owner" role is requied to exec app with docker addon'));
if (safe.query(req.resources.app, 'manifest.addons.docker') && req.user.role !== users.ROLE_OWNER) return next(new HttpError(403, '"owner" role is requied to exec app with docker addon'));
// in a badly configured reverse proxy, we might be here without an upgrade
if (req.headers['upgrade'] !== 'tcp') return next(new HttpError(404, 'exec requires TCP upgrade'));
const [error, duplexStream] = await safe(apps.startExec(req.app, req.params.execId, { rows, columns, tty }));
const [error, duplexStream] = await safe(apps.startExec(req.resources.app, req.params.execId, { rows, columns, tty }));
if (error) return next(BoxError.toHttpError(error));
req.clearTimeout();
@@ -856,7 +856,7 @@ async function startExec(req, res, next) {
}
async function startExecWebSocket(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.params.execId, 'string');
const columns = req.query.columns ? parseInt(req.query.columns, 10) : null;
@@ -870,7 +870,7 @@ async function startExecWebSocket(req, res, next) {
// in a badly configured reverse proxy, we might be here without an upgrade
if (req.headers['upgrade'] !== 'websocket') return next(new HttpError(404, 'exec requires websocket'));
const [error, duplexStream] = await safe(apps.startExec(req.app, req.params.execId, { rows, columns, tty }));
const [error, duplexStream] = await safe(apps.startExec(req.resources.app, req.params.execId, { rows, columns, tty }));
if (error) return next(BoxError.toHttpError(error));
req.clearTimeout();
@@ -899,16 +899,16 @@ async function startExecWebSocket(req, res, next) {
}
async function getExec(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.params.execId, 'string');
const [error, result] = await safe(apps.getExec(req.app, req.params.execId));
const [error, result] = await safe(apps.getExec(req.resources.app, req.params.execId));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, result)); // { exitCode, running }
}
async function listBackups(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const page = typeof req.query.page !== 'undefined' ? parseInt(req.query.page) : 1;
if (!page || page < 0) return next(new HttpError(400, 'page query param has to be a postive number'));
@@ -916,14 +916,14 @@ async function listBackups(req, res, next) {
const perPage = typeof req.query.per_page !== 'undefined'? parseInt(req.query.per_page) : 25;
if (!perPage || perPage < 0) return next(new HttpError(400, 'per_page query param has to be a postive number'));
const [error, result] = await safe(apps.listBackups(req.app, page, perPage));
const [error, result] = await safe(apps.listBackups(req.resources.app, page, perPage));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, { backups: result }));
}
async function updateBackup(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.params.backupId, 'string');
assert.strictEqual(typeof req.body, 'object');
@@ -931,17 +931,17 @@ async function updateBackup(req, res, next) {
if (typeof label !== 'string') return next(new HttpError(400, 'label must be a string'));
if (typeof preserveSecs !== 'number') return next(new HttpError(400, 'preserveSecs must be a number'));
const [error] = await safe(apps.updateBackup(req.app, req.params.backupId, { label, preserveSecs }));
const [error] = await safe(apps.updateBackup(req.resources.app, req.params.backupId, { label, preserveSecs }));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
}
async function downloadBackup(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.params.backupId, 'string');
const [error, result] = await safe(apps.getBackupDownloadStream(req.app, req.params.backupId));
const [error, result] = await safe(apps.getBackupDownloadStream(req.resources.app, req.params.backupId));
if (error) return next(BoxError.toHttpError(error));
res.attachment(result.filename);
@@ -949,7 +949,7 @@ async function downloadBackup(req, res, next) {
}
async function uploadFile(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
assert.strictEqual(typeof req.files, 'object');
if (typeof req.query.file !== 'string' || !req.query.file) return next(new HttpError(400, 'file query argument must be provided'));
@@ -957,7 +957,7 @@ async function uploadFile(req, res, next) {
req.clearTimeout();
const [error] = await safe(apps.uploadFile(req.app, req.files.file.path, req.query.file));
const [error] = await safe(apps.uploadFile(req.resources.app, req.files.file.path, req.query.file));
safe.fs.unlinkSync(req.files.file.path);
if (error) return next(BoxError.toHttpError(error));
@@ -965,13 +965,13 @@ async function uploadFile(req, res, next) {
}
async function downloadFile(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.query.file !== 'string' || !req.query.file) return next(new HttpError(400, 'file query argument must be provided'));
req.clearTimeout();
const [error, result] = await safe(apps.downloadFile(req.app, req.query.file));
const [error, result] = await safe(apps.downloadFile(req.resources.app, req.query.file));
if (error) return next(BoxError.toHttpError(error));
const { stream, filename, size } = result;
@@ -988,7 +988,7 @@ async function downloadFile(req, res, next) {
async function setMounts(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (!Array.isArray(req.body.mounts)) return next(new HttpError(400, 'mounts should be an array'));
for (const m of req.body.mounts) {
@@ -997,7 +997,7 @@ async function setMounts(req, res, next) {
if (typeof m.readOnly !== 'boolean') return next(new HttpError(400, 'readOnly must be a boolean'));
}
const [error, result] = await safe(apps.setMounts(req.app, req.body.mounts, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setMounts(req.resources.app, req.body.mounts, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -1005,11 +1005,11 @@ async function setMounts(req, res, next) {
async function setDevices(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.devices !== 'object') return next(new HttpError(400, 'devices should be an object'));
const [error, result] = await safe(apps.setDevices(req.app, req.body.devices, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.setDevices(req.resources.app, req.body.devices, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { taskId: result.taskId }));
@@ -1017,18 +1017,18 @@ async function setDevices(req, res, next) {
async function setUpstreamUri(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (typeof req.body.upstreamUri !== 'string') return next(new HttpError(400, 'upstreamUri must be a string'));
const [error] = await safe(apps.setUpstreamUri(req.app, req.body.upstreamUri, AuditSource.fromRequest(req)));
const [error] = await safe(apps.setUpstreamUri(req.resources.app, req.body.upstreamUri, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
}
async function listEventlog(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const page = typeof req.query.page !== 'undefined' ? parseInt(req.query.page) : 1;
if (!page || page < 0) return next(new HttpError(400, 'page query param has to be a postive number'));
@@ -1036,14 +1036,14 @@ async function listEventlog(req, res, next) {
const perPage = typeof req.query.per_page !== 'undefined'? parseInt(req.query.per_page) : 25;
if (!perPage || perPage < 0) return next(new HttpError(400, 'per_page query param has to be a postive number'));
const [error, eventlogs] = await safe(apps.listEventlog(req.app, page, perPage));
const [error, eventlogs] = await safe(apps.listEventlog(req.resources.app, page, perPage));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, { eventlogs }));
}
async function checkForUpdates(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
// it can take a while sometimes to get all the app updates one by one
req.clearTimeout();
@@ -1053,9 +1053,9 @@ async function checkForUpdates(req, res, next) {
}
async function getTask(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
const [error, result] = await safe(apps.getTask(req.app));
const [error, result] = await safe(apps.getTask(req.resources.app));
if (error) return next(BoxError.toHttpError(error));
if (result === null) return next(new HttpError(400, 'No active task'));
@@ -1063,7 +1063,7 @@ async function getTask(req, res, next) {
}
async function getMetrics(req, res, next) {
assert.strictEqual(typeof req.app, 'object');
assert.strictEqual(typeof req.resources.app, 'object');
if (!req.query.fromSecs || !parseInt(req.query.fromSecs)) return next(new HttpError(400, 'fromSecs must be a number'));
if (!req.query.intervalSecs || !parseInt(req.query.intervalSecs)) return next(new HttpError(400, 'intervalSecs must be a number'));
@@ -1071,7 +1071,7 @@ async function getMetrics(req, res, next) {
const fromSecs = parseInt(req.query.fromSecs);
const intervalSecs = parseInt(req.query.intervalSecs);
const noNullPoints = !!req.query.noNullPoints;
const [error, result] = await safe(metrics.getContainers(req.app.id, { fromSecs, noNullPoints, intervalSecs }));
const [error, result] = await safe(metrics.getContainers(req.resources.app.id, { fromSecs, noNullPoints, intervalSecs }));
if (error) return next(new HttpError(500, error));
next(new HttpSuccess(200, result));
+7 -7
View File
@@ -26,7 +26,7 @@ async function load(req, res, next) {
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'Backup not found'));
req.resource = result;
req.resources.archive = result;
next();
}
@@ -47,12 +47,12 @@ async function list(req, res, next) {
async function get(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
next(new HttpSuccess(200, req.resource));
next(new HttpSuccess(200, req.resources.archive));
}
async function getIcon(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.archive, 'object');
const [error, icon] = await safe(archives.getIcon(req.params.id, { original: req.query.original }));
if (error) return next(BoxError.toHttpError(error));
@@ -62,9 +62,9 @@ async function getIcon(req, res, next) {
async function del(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.archive, 'object');
const [error] = await safe(archives.del(req.resource, AuditSource.fromRequest(req)));
const [error] = await safe(archives.del(req.resources.archive, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -72,7 +72,7 @@ async function del(req, res, next) {
async function unarchive(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.archive, 'object');
assert.strictEqual(typeof req.body, 'object');
const data = req.body;
@@ -89,7 +89,7 @@ async function unarchive(req, res, next) {
if (Object.keys(data.secondaryDomains).some(function (key) { return typeof data.secondaryDomains[key].domain !== 'string' || typeof data.secondaryDomains[key].subdomain !== 'string'; })) return next(new HttpError(400, 'secondaryDomain object must contain domain and subdomain strings'));
}
const [error, result] = await safe(apps.unarchive(req.resource, req.body, AuditSource.fromRequest(req)));
const [error, result] = await safe(apps.unarchive(req.resources.archive, req.body, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, { id: result.id, taskId: result.taskId }));
+9 -9
View File
@@ -27,7 +27,7 @@ async function load(req, res, next) {
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'Group not found'));
req.resource = result;
req.resources.group = result;
next();
}
@@ -46,41 +46,41 @@ async function add(req, res, next) {
async function get(req, res, next) {
assert.strictEqual(typeof req.params.groupId, 'string');
next(new HttpSuccess(200, req.resource));
next(new HttpSuccess(200, req.resources.group));
}
async function setName(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.group, 'object');
assert.strictEqual(typeof req.body, 'object');
if (typeof req.body.name !== 'string') return next(new HttpError(400, 'name must be a string'));
const [error] = await safe(groups.setName(req.resource, req.body.name, AuditSource.fromRequest(req)));
const [error] = await safe(groups.setName(req.resources.group, req.body.name, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
}
async function setMembers(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.group, 'object');
if (!req.body.userIds) return next(new HttpError(404, 'missing or invalid userIds fields'));
if (!Array.isArray(req.body.userIds)) return next(new HttpError(404, 'userIds must be an array'));
if (req.body.userIds.some((u) => typeof u !== 'string')) return next(new HttpError(400, 'userIds array must contain strings'));
const [error] = await safe(groups.setMembers(req.resource, req.body.userIds, { skipSourceCheck: false }, AuditSource.fromRequest(req)));
const [error] = await safe(groups.setMembers(req.resources.group, req.body.userIds, { skipSourceCheck: false }, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
}
async function setAllowedApps(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.group, 'object');
if (!req.body.appIds) return next(new HttpError(404, 'missing or invalid userIds fields'));
if (!Array.isArray(req.body.appIds)) return next(new HttpError(404, 'appIds must be an array'));
if (req.body.appIds.some((a) => typeof a !== 'string')) return next(new HttpError(400, 'appIds array must contain strings'));
const [error] = await safe(groups.setAllowedApps(req.resource, req.body.appIds, AuditSource.fromRequest(req)));
const [error] = await safe(groups.setAllowedApps(req.resources.group, req.body.appIds, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -96,7 +96,7 @@ async function list(req, res, next) {
async function del(req, res, next) {
assert.strictEqual(typeof req.params.groupId, 'string');
const [error] = await safe(groups.del(req.resource, AuditSource.fromRequest(req)));
const [error] = await safe(groups.del(req.resources.group, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
+7 -6
View File
@@ -21,14 +21,15 @@ async function load(req, res, next) {
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'Notification not found'));
req.notification = result;
req.resources.notification = result;
next();
}
function get(req, res, next) {
assert.strictEqual(typeof req.notification, 'object');
assert.strictEqual(typeof req.resources.notification, 'object');
next(new HttpSuccess(200, req.notification));
next(new HttpSuccess(200, req.resources.notification));
}
async function list(req, res, next) {
@@ -40,7 +41,7 @@ async function list(req, res, next) {
if (req.query.acknowledged && !(req.query.acknowledged === 'true' || req.query.acknowledged === 'false')) return next(new HttpError(400, 'acknowledged must be a true or false'));
let filters = {};
const filters = {};
if (req.query.acknowledged) filters.acknowledged = req.query.acknowledged === 'true';
const [error, result] = await safe(notifications.list(filters, page, perPage));
@@ -49,12 +50,12 @@ async function list(req, res, next) {
}
async function update(req, res, next) {
assert.strictEqual(typeof req.notification, 'object');
assert.strictEqual(typeof req.resources.notification, 'object');
assert.strictEqual(typeof req.body, 'object');
if (typeof req.body.acknowledged !== 'boolean') return next(new HttpError(400, 'acknowledged must be a boolean'));
const [error] = await safe(notifications.update(req.notification, { acknowledged: req.body.acknowledged }));
const [error] = await safe(notifications.update(req.resources.notification, { acknowledged: req.body.acknowledged }));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204, {}));
}
+3 -2
View File
@@ -55,14 +55,15 @@ async function loadClient(req, res, next) {
if (!client) return next(new HttpError(404, 'OIDC client not found'));
if (client.appId) return next(new HttpError(422, 'OIDC client of an internal app'));
req.oidcClient = client;
req.resources.oidcClient = client;
next();
}
async function getClient(req, res, next) {
assert.strictEqual(typeof req.params.clientId, 'string');
next(new HttpSuccess(200, req.oidcClient));
next(new HttpSuccess(200, req.resources.oidcClient));
}
async function updateClient(req, res, next) {
+10 -9
View File
@@ -25,14 +25,15 @@ async function load(req, res, next) {
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'Task not found'));
req.task = result;
req.resources.task = result;
next();
}
async function get(req, res, next) {
assert.strictEqual(typeof req.params.taskId, 'string');
next(new HttpSuccess(200, tasks.removePrivateFields(req.task)));
next(new HttpSuccess(200, tasks.removePrivateFields(req.resources.task)));
}
async function list(req, res, next) {
@@ -51,16 +52,16 @@ async function list(req, res, next) {
}
async function stopTask(req, res, next) {
assert.strictEqual(typeof req.task, 'object');
assert.strictEqual(typeof req.resources.task, 'object');
const [error] = await safe(tasks.stopTask(req.task.id));
const [error] = await safe(tasks.stopTask(req.resources.task.id));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204, {}));
}
async function getLogs(req, res, next) {
assert.strictEqual(typeof req.task, 'object');
assert.strictEqual(typeof req.resources.task, 'object');
const lines = 'lines' in req.query ? parseInt(req.query.lines, 10) : 10; // we ignore last-event-id
if (isNaN(lines)) return next(new HttpError(400, 'lines must be a number'));
@@ -71,12 +72,12 @@ async function getLogs(req, res, next) {
format: req.query.format || 'json'
};
const [error, logStream] = await safe(tasks.getLogs(req.task, options));
const [error, logStream] = await safe(tasks.getLogs(req.resources.task, options));
if (error) return next(BoxError.toHttpError(error));
res.writeHead(200, {
'Content-Type': 'application/x-logs',
'Content-Disposition': `attachment; filename="task-${req.task.id}.log"`,
'Content-Disposition': `attachment; filename="task-${req.resources.task.id}.log"`,
'Cache-Control': 'no-cache',
'X-Accel-Buffering': 'no' // disable nginx buffering
});
@@ -86,7 +87,7 @@ async function getLogs(req, res, next) {
// this route is for streaming logs
async function getLogStream(req, res, next) {
assert.strictEqual(typeof req.task, 'object');
assert.strictEqual(typeof req.resources.task, 'object');
const lines = 'lines' in req.query ? parseInt(req.query.lines, 10) : 10; // we ignore last-event-id
if (isNaN(lines)) return next(new HttpError(400, 'lines must be a valid number'));
@@ -101,7 +102,7 @@ async function getLogStream(req, res, next) {
format: 'json'
};
const [error, logStream] = await safe(tasks.getLogs(req.task, options));
const [error, logStream] = await safe(tasks.getLogs(req.resources.task, options));
if (error) return next(BoxError.toHttpError(error));
res.writeHead(200, {
+43 -42
View File
@@ -42,7 +42,8 @@ async function load(req, res, next) {
const [error, result] = await safe(users.get(req.params.userId));
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'User not found'));
req.resource = result; // this is not req.user because req.user is already the authenticated user
req.resources.user = result; // this is not req.user because req.user is already the authenticated user
next();
}
@@ -73,40 +74,40 @@ async function add(req, res, next) {
}
async function setRole(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
assert.strictEqual(typeof req.user, 'object');
assert.strictEqual(typeof req.body, 'object');
if (typeof req.body.role !== 'string') return next(new HttpError(400, 'role must be a string'));
if (req.user.id === req.resource.id) return next(new HttpError(409, 'Cannot set role flag on self'));
if (req.user.id === req.resources.user.id) return next(new HttpError(409, 'Cannot set role flag on self'));
if (users.compareRoles(req.user.role, req.body.role) < 0) return next(new HttpError(403, `role '${req.body.role}' is required but you are only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but you are only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but you are only '${req.user.role}'`));
const [error] = await safe(users.update(req.resource, { role: req.body.role }, AuditSource.fromRequest(req)));
const [error] = await safe(users.update(req.resources.user, { role: req.body.role }, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
}
async function setActive(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
assert.strictEqual(typeof req.user, 'object');
assert.strictEqual(typeof req.body, 'object');
if (typeof req.body.active !== 'boolean') return next(new HttpError(400, 'active must be a boolean'));
if (req.user.id === req.resource.id) return next(new HttpError(409, 'Cannot set active flag on self'));
if (req.user.id === req.resources.user.id) return next(new HttpError(409, 'Cannot set active flag on self'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but you are only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but you are only '${req.user.role}'`));
const [error] = await safe(users.update(req.resource, { active: req.body.active }, AuditSource.fromRequest(req)));
const [error] = await safe(users.update(req.resources.user, { active: req.body.active }, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
}
async function updateProfile(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
assert.strictEqual(typeof req.user, 'object');
assert.strictEqual(typeof req.body, 'object');
@@ -115,10 +116,10 @@ async function updateProfile(req, res, next) {
if ('fallbackEmail' in req.body && typeof req.body.fallbackEmail !== 'string') return next(new HttpError(400, 'fallbackEmail must be string'));
if ('displayName' in req.body && typeof req.body.displayName !== 'string') return next(new HttpError(400, 'displayName must be string'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but you are only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but you are only '${req.user.role}'`));
const data = _.pick(req.body, ['username', 'email', 'fallbackEmail', 'displayName']);
const [error] = await safe(users.updateProfile(req.resource, data, AuditSource.fromRequest(req)));
const [error] = await safe(users.updateProfile(req.resources.user, data, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -142,19 +143,19 @@ async function list(req, res, next) {
}
function get(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
assert.strictEqual(typeof req.user, 'object');
next(new HttpSuccess(200, users.removePrivateFields(req.resource)));
next(new HttpSuccess(200, users.removePrivateFields(req.resources.user)));
}
async function del(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (req.user.id === req.resource.id) return next(new HttpError(409, 'Not allowed to remove yourself.'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (req.user.id === req.resources.user.id) return next(new HttpError(409, 'Not allowed to remove yourself.'));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(users.del(req.resource, AuditSource.fromRequest(req)));
const [error] = await safe(users.del(req.resources.user, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -175,11 +176,11 @@ async function verifyPassword(req, res, next) {
}
async function disableTwoFactorAuthentication(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(users.disableTwoFactorAuthentication(req.resource, AuditSource.fromRequest(req)));
const [error] = await safe(users.disableTwoFactorAuthentication(req.resources.user, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, {}));
@@ -187,13 +188,13 @@ async function disableTwoFactorAuthentication(req, res, next) {
async function setLocalGroups(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (!Array.isArray(req.body.groupIds)) return next(new HttpError(400, 'API call requires a groups array.'));
if (req.body.groupIds.some((gid) => typeof gid !== 'string')) return next(new HttpError(400, 'groupIds array must contain strings'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(groups.setLocalMembership(req.resource, req.body.groupIds, AuditSource.fromRequest(req)));
const [error] = await safe(groups.setLocalMembership(req.resources.user, req.body.groupIds, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -201,13 +202,13 @@ async function setLocalGroups(req, res, next) {
async function setGhost(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (typeof req.body.password !== 'string' || !req.body.password) return next(new HttpError(400, 'password must be non-empty string'));
if ('expiresAt' in req.body && typeof req.body.expiresAt !== 'number') return next(new HttpError(400, 'expiresAt must be a number'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(users.setGhost(req.resource, req.body.password, req.body.expiresAt || 0));
const [error] = await safe(users.setGhost(req.resources.user, req.body.password, req.body.expiresAt || 0));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -215,12 +216,12 @@ async function setGhost(req, res, next) {
async function setPassword(req, res, next) {
assert.strictEqual(typeof req.body, 'object');
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (typeof req.body.password !== 'string') return next(new HttpError(400, 'password must be a string'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(users.setPassword(req.resource, req.body.password, AuditSource.fromRequest(req)));
const [error] = await safe(users.setPassword(req.resources.user, req.body.password, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -228,46 +229,46 @@ async function setPassword(req, res, next) {
// This will always return a reset link, if none is set or expired a new one will be created
async function getPasswordResetLink(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error, passwordResetLink] = await safe(users.getPasswordResetLink(req.resource, AuditSource.fromRequest(req)));
const [error, passwordResetLink] = await safe(users.getPasswordResetLink(req.resources.user, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, { passwordResetLink }));
}
async function sendPasswordResetEmail(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (!req.body.email || typeof req.body.email !== 'string') return next(new HttpError(400, 'email must be a non-empty string'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(users.sendPasswordResetEmail(req.resource, req.body.email, AuditSource.fromRequest(req)));
const [error] = await safe(users.sendPasswordResetEmail(req.resources.user, req.body.email, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
}
async function getInviteLink(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error, inviteLink] = await safe(users.getInviteLink(req.resource, AuditSource.fromRequest(req)));
const [error, inviteLink] = await safe(users.getInviteLink(req.resources.user, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, { inviteLink }));
}
async function sendInviteEmail(req, res, next) {
assert.strictEqual(typeof req.resource, 'object');
assert.strictEqual(typeof req.resources.user, 'object');
if (!req.body.email || typeof req.body.email !== 'string') return next(new HttpError(400, 'email must be a non-empty string'));
if (users.compareRoles(req.user.role, req.resource.role) < 0) return next(new HttpError(403, `role '${req.resource.role}' is required but user has only '${req.user.role}'`));
if (users.compareRoles(req.user.role, req.resources.user.role) < 0) return next(new HttpError(403, `role '${req.resources.user.role}' is required but user has only '${req.user.role}'`));
const [error] = await safe(users.sendInviteEmail(req.resource, req.body.email, AuditSource.fromRequest(req)));
const [error] = await safe(users.sendInviteEmail(req.resources.user, req.body.email, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202, {}));
+8 -6
View File
@@ -25,7 +25,9 @@ async function load(req, res, next) {
const [error, result] = await safe(volumes.get(req.params.id));
if (error) return next(BoxError.toHttpError(error));
if (!result) return next(new HttpError(404, 'Volume not found'));
req.volume = result;
req.resources.volume = result;
next();
}
@@ -46,7 +48,7 @@ async function add(req, res, next) {
async function get(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
next(new HttpSuccess(200, volumes.removePrivateFields(req.volume)));
next(new HttpSuccess(200, volumes.removePrivateFields(req.resources.volume)));
}
async function update(req, res, next) {
@@ -54,7 +56,7 @@ async function update(req, res, next) {
if (!req.body.mountOptions || typeof req.body.mountOptions !== 'object') return next(new HttpError(400, 'mountOptions must be a non-null object'));
const [error] = await safe(volumes.update(req.volume.id, req.body.mountOptions, AuditSource.fromRequest(req)));
const [error] = await safe(volumes.update(req.resources.volume.id, req.body.mountOptions, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
@@ -63,7 +65,7 @@ async function update(req, res, next) {
async function del(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
const [error] = await safe(volumes.del(req.volume, AuditSource.fromRequest(req)));
const [error] = await safe(volumes.del(req.resources.volume, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(204));
}
@@ -80,7 +82,7 @@ async function list(req, res, next) {
async function remount(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
const [error] = await safe(volumes.remount(req.volume, AuditSource.fromRequest(req)));
const [error] = await safe(volumes.remount(req.resources.volume, AuditSource.fromRequest(req)));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(202));
}
@@ -88,7 +90,7 @@ async function remount(req, res, next) {
async function getStatus(req, res, next) {
assert.strictEqual(typeof req.params.id, 'string');
const [error, status] = await safe(volumes.getStatus(req.volume));
const [error, status] = await safe(volumes.getStatus(req.resources.volume));
if (error) return next(BoxError.toHttpError(error));
next(new HttpSuccess(200, status));
}