diff --git a/CHANGES b/CHANGES index e9e7c8346..aebe72e9c 100644 --- a/CHANGES +++ b/CHANGES @@ -2882,3 +2882,5 @@ * postgres: enable vector extension * docker: fallback to downloading images from quay if dockerhub does not work +[8.2.1] +* apps: fix bug where update and notes indicator was shown to normal users diff --git a/src/apps.js b/src/apps.js index 5afa7c6e0..8f0d1f3e2 100644 --- a/src/apps.js +++ b/src/apps.js @@ -4,8 +4,7 @@ exports = module.exports = { canAccess, isOperator, accessLevel, - removeInternalFields, - removeRestrictedFields, + pickFields, // database crud add, @@ -587,35 +586,35 @@ async function getStorageDir(app) { return path.join(volume.hostPath, app.storageVolumePrefix); } -function removeCertificateKeys(app) { - if (app.certificate) delete app.certificate.key; - app.secondaryDomains.forEach(sd => { if (sd.certificate) delete sd.certificate.key; }); - app.aliasDomains.forEach(ad => { if (ad.certificate) delete ad.certificate.key; }); - app.redirectDomains.forEach(rd => { if (rd.certificate) delete rd.certificate.key; }); -} +function pickFields(app, accessLevel) { + assert.strictEqual(typeof app, 'object'); + assert.strictEqual(typeof accessLevel, 'string'); -function removeInternalFields(app) { - const result = _.pick(app, - 'id', 'appStoreId', 'installationState', 'error', 'runState', 'health', 'taskId', - 'subdomain', 'domain', 'fqdn', 'certificate', 'crontab', 'upstreamUri', - 'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuQuota', 'operators', - 'sso', 'debugMode', 'reverseProxyConfig', 'enableBackup', 'creationTime', 'updateTime', 'ts', 'tags', - 'label', 'notes', 'secondaryDomains', 'redirectDomains', 'aliasDomains', 'devices', 'env', 'enableAutomaticUpdate', - 'storageVolumeId', 'storageVolumePrefix', 'mounts', 'enableTurn', 'enableRedis', 'checklist', - 'enableMailbox', 'mailboxDisplayName', 'mailboxName', 'mailboxDomain', 'enableInbox', 'inboxName', 'inboxDomain'); + if (accessLevel === exports.ACCESS_LEVEL_NONE) return null; // cannot happen! - removeCertificateKeys(result); - return result; -} + let result; + if (accessLevel === exports.ACCESS_LEVEL_USER) { + result = _.pick(app, + 'id', 'appStoreId', 'installationState', 'error', 'runState', 'health', 'taskId', 'accessRestriction', + 'secondaryDomains', 'redirectDomains', 'aliasDomains', 'sso', 'subdomain', 'domain', 'fqdn', 'certificate', + 'manifest', 'portBindings', 'iconUrl', 'creationTime', 'ts', 'tags', 'label', 'upstreamUri'); + } else { // admin or operator + result = _.pick(app, + 'id', 'appStoreId', 'installationState', 'error', 'runState', 'health', 'taskId', + 'subdomain', 'domain', 'fqdn', 'certificate', 'crontab', 'upstreamUri', + 'accessRestriction', 'manifest', 'portBindings', 'iconUrl', 'memoryLimit', 'cpuQuota', 'operators', + 'sso', 'debugMode', 'reverseProxyConfig', 'enableBackup', 'creationTime', 'updateTime', 'ts', 'tags', + 'label', 'notes', 'secondaryDomains', 'redirectDomains', 'aliasDomains', 'devices', 'env', 'enableAutomaticUpdate', + 'storageVolumeId', 'storageVolumePrefix', 'mounts', 'enableTurn', 'enableRedis', 'checklist', + 'enableMailbox', 'mailboxDisplayName', 'mailboxName', 'mailboxDomain', 'enableInbox', 'inboxName', 'inboxDomain'); + } -// non-admins can only see these -function removeRestrictedFields(app) { - const result = _.pick(app, - 'id', 'appStoreId', 'installationState', 'error', 'runState', 'health', 'taskId', 'accessRestriction', - 'secondaryDomains', 'redirectDomains', 'aliasDomains', 'sso', 'subdomain', 'domain', 'fqdn', 'certificate', - 'manifest', 'portBindings', 'iconUrl', 'creationTime', 'ts', 'tags', 'label', 'upstreamUri'); + // remove private certificate key + if (result.certificate) delete result.certificate.key; + result.secondaryDomains.forEach(sd => { if (sd.certificate) delete sd.certificate.key; }); + result.aliasDomains.forEach(ad => { if (ad.certificate) delete ad.certificate.key; }); + result.redirectDomains.forEach(rd => { if (rd.certificate) delete rd.certificate.key; }); - removeCertificateKeys(result); return result; } diff --git a/src/routes/apps.js b/src/routes/apps.js index e931e67c2..055a272ba 100644 --- a/src/routes/apps.js +++ b/src/routes/apps.js @@ -100,8 +100,9 @@ async function load(req, res, next) { function getApp(req, res, next) { assert.strictEqual(typeof req.app, 'object'); - const result = apps.removeInternalFields(req.app); - result.accessLevel = apps.accessLevel(req.app, req.user); + const accessLevel = apps.accessLevel(req.app, req.user); + const result = apps.pickFields(req.app, accessLevel); + result.accessLevel = accessLevel; next(new HttpSuccess(200, result)); } @@ -109,13 +110,14 @@ function getApp(req, res, next) { async function listByUser(req, res, next) { assert.strictEqual(typeof req.user, 'object'); - const [error, result] = await safe(apps.listByUser(req.user)); + const [error, results] = await safe(apps.listByUser(req.user)); if (error) return next(BoxError.toHttpError(error)); - const filteredResult = result.map(r => { - const app = apps.removeRestrictedFields(r); - app.accessLevel = apps.accessLevel(r, req.user); - return app; + const filteredResult = results.map(app => { + const accessLevel = apps.accessLevel(app, req.user); + const result = apps.pickFields(app, accessLevel); + result.accessLevel = accessLevel; + return result; }); next(new HttpSuccess(200, { apps: filteredResult }));