diff --git a/services/web/app/src/Features/Authorization/AuthorizationManager.js b/services/web/app/src/Features/Authorization/AuthorizationManager.js index 5c101c8aeb..37fb47ac66 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationManager.js +++ b/services/web/app/src/Features/Authorization/AuthorizationManager.js @@ -1,16 +1,3 @@ -/* eslint-disable - camelcase, - handle-callback-err, - max-len, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ let AuthorizationManager const CollaboratorsHandler = require('../Collaborators/CollaboratorsHandler') const ProjectGetter = require('../Project/ProjectGetter') @@ -22,29 +9,25 @@ const { ObjectId } = require('mongojs') const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler') module.exports = AuthorizationManager = { - getPublicAccessLevel(project_id, callback) { - if (callback == null) { - callback = function(err, level) {} - } - if (!ObjectId.isValid(project_id)) { + getPublicAccessLevel(projectId, callback) { + if (!ObjectId.isValid(projectId)) { return callback(new Error('invalid project id')) } // Note, the Project property in the DB is `publicAccesLevel`, without the second `s` - return ProjectGetter.getProject( - project_id, - { publicAccesLevel: 1 }, - function(error, project) { - if (error != null) { - return callback(error) - } - if (project == null) { - return callback( - new Errors.NotFoundError(`no project found with id ${project_id}`) - ) - } - return callback(null, project.publicAccesLevel) + ProjectGetter.getProject(projectId, { publicAccesLevel: 1 }, function( + error, + project + ) { + if (error) { + return callback(error) } - ) + if (!project) { + return callback( + new Errors.NotFoundError(`no project found with id ${projectId}`) + ) + } + callback(null, project.publicAccesLevel) + }) }, // Get the privilege level that the user has for the project @@ -53,142 +36,131 @@ module.exports = AuthorizationManager = { // access. false if the user does not have access // * becausePublic: true if the access level is only because the project is public. // * becauseSiteAdmin: true if access level is only because user is admin - getPrivilegeLevelForProject(user_id, project_id, token, callback) { - if (callback == null) { - callback = function( - error, - privilegeLevel, - becausePublic, - becauseSiteAdmin - ) {} - } - if (user_id == null) { - // User is Anonymous, Try Token-based access - return AuthorizationManager.getPublicAccessLevel(project_id, function( - err, - publicAccessLevel - ) { - if (err != null) { - return callback(err) - } - if (publicAccessLevel === PublicAccessLevels.TOKEN_BASED) { - // Anonymous users can have read-only access to token-based projects, - // while read-write access must be logged in, - // unless the `enableAnonymousReadAndWriteSharing` setting is enabled - return TokenAccessHandler.isValidToken(project_id, token, function( - err, - isValidReadAndWrite, - isValidReadOnly - ) { - if (err != null) { - return callback(err) - } - if (isValidReadOnly) { - // Grant anonymous user read-only access - return callback(null, PrivilegeLevels.READ_ONLY, false, false) - } else if ( - isValidReadAndWrite && - TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED - ) { - // Grant anonymous user read-and-write access - return callback( - null, - PrivilegeLevels.READ_AND_WRITE, - false, - false - ) - } else { - // Deny anonymous access - return callback(null, PrivilegeLevels.NONE, false, false) - } - }) - } else if (publicAccessLevel === PublicAccessLevels.READ_ONLY) { - // Legacy public read-only access for anonymous user - return callback(null, PrivilegeLevels.READ_ONLY, true, false) - } else if (publicAccessLevel === PublicAccessLevels.READ_AND_WRITE) { - // Legacy public read-write access for anonymous user - return callback(null, PrivilegeLevels.READ_AND_WRITE, true, false) - } else { - // Deny anonymous user access - return callback(null, PrivilegeLevels.NONE, false, false) - } - }) + getPrivilegeLevelForProject(userId, projectId, token, callback) { + if (userId) { + AuthorizationManager.getPrivilegeLevelForProjectWithUser( + userId, + projectId, + token, + callback + ) } else { - // User is present, get their privilege level from database - return CollaboratorsHandler.getMemberIdPrivilegeLevel( - user_id, - project_id, - function(error, privilegeLevel) { - if (error != null) { - return callback(error) - } - if ( - privilegeLevel != null && - privilegeLevel !== PrivilegeLevels.NONE - ) { - // The user has direct access - return callback(null, privilegeLevel, false, false) - } else { - return AuthorizationManager.isUserSiteAdmin(user_id, function( - error, - isAdmin - ) { - if (error != null) { - return callback(error) - } - if (isAdmin) { - return callback(null, PrivilegeLevels.OWNER, false, true) - } else { - // Legacy public-access system - // User is present (not anonymous), but does not have direct access - return AuthorizationManager.getPublicAccessLevel( - project_id, - function(err, publicAccessLevel) { - if (err != null) { - return callback(err) - } - if (publicAccessLevel === PublicAccessLevels.READ_ONLY) { - return callback( - null, - PrivilegeLevels.READ_ONLY, - true, - false - ) - } else if ( - publicAccessLevel === PublicAccessLevels.READ_AND_WRITE - ) { - return callback( - null, - PrivilegeLevels.READ_AND_WRITE, - true, - false - ) - } else { - return callback(null, PrivilegeLevels.NONE, false, false) - } - } - ) - } - }) - } - } + AuthorizationManager.getPrivilegeLevelForProjectWithoutUser( + projectId, + token, + callback ) } }, - canUserReadProject(user_id, project_id, token, callback) { - if (callback == null) { - callback = function(error, canRead) {} - } - return AuthorizationManager.getPrivilegeLevelForProject( - user_id, - project_id, - token, - function(error, privilegeLevel) { - if (error != null) { + // User is present, get their privilege level from database + getPrivilegeLevelForProjectWithUser(userId, projectId, token, callback) { + CollaboratorsHandler.getMemberIdPrivilegeLevel(userId, projectId, function( + error, + privilegeLevel + ) { + if (error) { + return callback(error) + } + if (privilegeLevel && privilegeLevel !== PrivilegeLevels.NONE) { + // The user has direct access + return callback(null, privilegeLevel, false, false) + } + AuthorizationManager.isUserSiteAdmin(userId, function(error, isAdmin) { + if (error) { return callback(error) } - return callback( + if (isAdmin) { + return callback(null, PrivilegeLevels.OWNER, false, true) + } + // Legacy public-access system + // User is present (not anonymous), but does not have direct access + AuthorizationManager.getPublicAccessLevel(projectId, function( + err, + publicAccessLevel + ) { + if (err) { + return callback(err) + } + if (publicAccessLevel === PublicAccessLevels.READ_ONLY) { + return callback(null, PrivilegeLevels.READ_ONLY, true, false) + } + if (publicAccessLevel === PublicAccessLevels.READ_AND_WRITE) { + return callback(null, PrivilegeLevels.READ_AND_WRITE, true, false) + } + callback(null, PrivilegeLevels.NONE, false, false) + }) + }) + }) + }, + + // User is Anonymous, Try Token-based access + getPrivilegeLevelForProjectWithoutUser(projectId, token, callback) { + AuthorizationManager.getPublicAccessLevel(projectId, function( + err, + publicAccessLevel + ) { + if (err) { + return callback(err) + } + if (publicAccessLevel === PublicAccessLevels.READ_ONLY) { + // Legacy public read-only access for anonymous user + return callback(null, PrivilegeLevels.READ_ONLY, true, false) + } + if (publicAccessLevel === PublicAccessLevels.READ_AND_WRITE) { + // Legacy public read-write access for anonymous user + return callback(null, PrivilegeLevels.READ_AND_WRITE, true, false) + } + if (publicAccessLevel === PublicAccessLevels.TOKEN_BASED) { + return AuthorizationManager.getPrivilegeLevelForProjectWithToken( + projectId, + token, + callback + ) + } + // Deny anonymous user access + callback(null, PrivilegeLevels.NONE, false, false) + }) + }, + + getPrivilegeLevelForProjectWithToken(projectId, token, callback) { + // Anonymous users can have read-only access to token-based projects, + // while read-write access must be logged in, + // unless the `enableAnonymousReadAndWriteSharing` setting is enabled + TokenAccessHandler.isValidToken(projectId, token, function( + err, + isValidReadAndWrite, + isValidReadOnly + ) { + if (err) { + return callback(err) + } + if (isValidReadOnly) { + // Grant anonymous user read-only access + return callback(null, PrivilegeLevels.READ_ONLY, false, false) + } + if ( + isValidReadAndWrite && + TokenAccessHandler.ANONYMOUS_READ_AND_WRITE_ENABLED + ) { + // Grant anonymous user read-and-write access + return callback(null, PrivilegeLevels.READ_AND_WRITE, false, false) + } + // Deny anonymous access + callback(null, PrivilegeLevels.NONE, false, false) + }) + }, + + canUserReadProject(userId, projectId, token, callback) { + AuthorizationManager.getPrivilegeLevelForProject( + userId, + projectId, + token, + function(error, privilegeLevel) { + if (error) { + return callback(error) + } + callback( null, [ PrivilegeLevels.OWNER, @@ -200,19 +172,16 @@ module.exports = AuthorizationManager = { ) }, - canUserWriteProjectContent(user_id, project_id, token, callback) { - if (callback == null) { - callback = function(error, canWriteContent) {} - } - return AuthorizationManager.getPrivilegeLevelForProject( - user_id, - project_id, + canUserWriteProjectContent(userId, projectId, token, callback) { + AuthorizationManager.getPrivilegeLevelForProject( + userId, + projectId, token, function(error, privilegeLevel) { - if (error != null) { + if (error) { return callback(error) } - return callback( + callback( null, [PrivilegeLevels.OWNER, PrivilegeLevels.READ_AND_WRITE].includes( privilegeLevel @@ -222,45 +191,39 @@ module.exports = AuthorizationManager = { ) }, - canUserWriteProjectSettings(user_id, project_id, token, callback) { - if (callback == null) { - callback = function(error, canWriteSettings) {} - } - return AuthorizationManager.getPrivilegeLevelForProject( - user_id, - project_id, + canUserWriteProjectSettings(userId, projectId, token, callback) { + AuthorizationManager.getPrivilegeLevelForProject( + userId, + projectId, token, function(error, privilegeLevel, becausePublic) { - if (error != null) { + if (error) { return callback(error) } if (privilegeLevel === PrivilegeLevels.OWNER) { return callback(null, true) - } else if ( + } + if ( privilegeLevel === PrivilegeLevels.READ_AND_WRITE && !becausePublic ) { return callback(null, true) - } else { - return callback(null, false) } + callback(null, false) } ) }, - canUserAdminProject(user_id, project_id, token, callback) { - if (callback == null) { - callback = function(error, canAdmin, becauseSiteAdmin) {} - } - return AuthorizationManager.getPrivilegeLevelForProject( - user_id, - project_id, + canUserAdminProject(userId, projectId, token, callback) { + AuthorizationManager.getPrivilegeLevelForProject( + userId, + projectId, token, function(error, privilegeLevel, becausePublic, becauseSiteAdmin) { - if (error != null) { + if (error) { return callback(error) } - return callback( + callback( null, privilegeLevel === PrivilegeLevels.OWNER, becauseSiteAdmin @@ -269,21 +232,15 @@ module.exports = AuthorizationManager = { ) }, - isUserSiteAdmin(user_id, callback) { - if (callback == null) { - callback = function(error, isAdmin) {} - } - if (user_id == null) { + isUserSiteAdmin(userId, callback) { + if (!userId) { return callback(null, false) } - return User.findOne({ _id: user_id }, { isAdmin: 1 }, function( - error, - user - ) { - if (error != null) { + User.findOne({ _id: userId }, { isAdmin: 1 }, function(error, user) { + if (error) { return callback(error) } - return callback(null, (user != null ? user.isAdmin : undefined) === true) + callback(null, (user && user.isAdmin) === true) }) } } diff --git a/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js b/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js index bae9a9d7b0..5c9eedeb2a 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js +++ b/services/web/app/src/Features/Authorization/AuthorizationMiddleware.js @@ -1,17 +1,3 @@ -/* eslint-disable - camelcase, - handle-callback-err, - max-len, -*/ -// TODO: This file was created by bulk-decaffeinate. -// Fix any style issues and re-enable lint. -/* - * decaffeinate suggestions: - * DS102: Remove unnecessary code created because of implicit returns - * DS103: Rewrite code to no longer use __guard__ - * DS207: Consider shorter variations of null checks - * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md - */ let AuthorizationMiddleware const AuthorizationManager = require('./AuthorizationManager') const async = require('async') @@ -23,276 +9,242 @@ const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler') module.exports = AuthorizationMiddleware = { ensureUserCanReadMultipleProjects(req, res, next) { - const project_ids = (req.query.project_ids || '').split(',') - return AuthorizationMiddleware._getUserId(req, function(error, user_id) { - if (error != null) { + const projectIds = (req.query.project_ids || '').split(',') + AuthorizationMiddleware._getUserId(req, function(error, userId) { + if (error) { return next(error) } // Remove the projects we have access to. Note rejectSeries doesn't use // errors in callbacks - return async.rejectSeries( - project_ids, - function(project_id, cb) { - const token = TokenAccessHandler.getRequestToken(req, project_id) - return AuthorizationManager.canUserReadProject( - user_id, - project_id, + async.rejectSeries( + projectIds, + function(projectId, cb) { + const token = TokenAccessHandler.getRequestToken(req, projectId) + AuthorizationManager.canUserReadProject( + userId, + projectId, token, function(error, canRead) { - if (error != null) { + if (error) { return next(error) } - return cb(canRead) + cb(canRead) } ) }, - function(unauthorized_project_ids) { - if (unauthorized_project_ids.length > 0) { + function(unauthorizedProjectIds) { + if (unauthorizedProjectIds.length > 0) { return AuthorizationMiddleware.redirectToRestricted(req, res, next) - } else { - return next() } + next() } ) }) }, ensureUserCanReadProject(req, res, next) { - return AuthorizationMiddleware._getUserAndProjectId(req, function( + AuthorizationMiddleware._getUserAndProjectId(req, function( error, - user_id, - project_id + userId, + projectId ) { - if (error != null) { + if (error) { return next(error) } - const token = TokenAccessHandler.getRequestToken(req, project_id) - return AuthorizationManager.canUserReadProject( - user_id, - project_id, + const token = TokenAccessHandler.getRequestToken(req, projectId) + AuthorizationManager.canUserReadProject( + userId, + projectId, token, function(error, canRead) { - if (error != null) { + if (error) { return next(error) } if (canRead) { logger.log( - { user_id, project_id }, + { userId, projectId }, 'allowing user read access to project' ) return next() - } else { - logger.log( - { user_id, project_id }, - 'denying user read access to project' - ) - if ( - __guard__( - req.headers != null ? req.headers['accept'] : undefined, - x => x.match(/^application\/json.*$/) - ) - ) { - return res.sendStatus(403) - } else { - return AuthorizationMiddleware.redirectToRestricted( - req, - res, - next - ) - } } + logger.log( + { userId, projectId }, + 'denying user read access to project' + ) + const acceptHeader = req.headers && req.headers['accept'] + if (acceptHeader && acceptHeader.match(/^application\/json.*$/)) { + return res.sendStatus(403) + } + AuthorizationMiddleware.redirectToRestricted(req, res, next) } ) }) }, ensureUserCanWriteProjectSettings(req, res, next) { - return AuthorizationMiddleware._getUserAndProjectId(req, function( + AuthorizationMiddleware._getUserAndProjectId(req, function( error, - user_id, - project_id + userId, + projectId ) { - if (error != null) { + if (error) { return next(error) } - const token = TokenAccessHandler.getRequestToken(req, project_id) - return AuthorizationManager.canUserWriteProjectSettings( - user_id, - project_id, + const token = TokenAccessHandler.getRequestToken(req, projectId) + AuthorizationManager.canUserWriteProjectSettings( + userId, + projectId, token, function(error, canWrite) { - if (error != null) { + if (error) { return next(error) } if (canWrite) { logger.log( - { user_id, project_id }, + { userId, projectId }, 'allowing user write access to project settings' ) return next() - } else { - logger.log( - { user_id, project_id }, - 'denying user write access to project settings' - ) - return AuthorizationMiddleware.redirectToRestricted(req, res, next) } + logger.log( + { userId, projectId }, + 'denying user write access to project settings' + ) + AuthorizationMiddleware.redirectToRestricted(req, res, next) } ) }) }, ensureUserCanWriteProjectContent(req, res, next) { - return AuthorizationMiddleware._getUserAndProjectId(req, function( + AuthorizationMiddleware._getUserAndProjectId(req, function( error, - user_id, - project_id + userId, + projectId ) { - if (error != null) { + if (error) { return next(error) } - const token = TokenAccessHandler.getRequestToken(req, project_id) - return AuthorizationManager.canUserWriteProjectContent( - user_id, - project_id, + const token = TokenAccessHandler.getRequestToken(req, projectId) + AuthorizationManager.canUserWriteProjectContent( + userId, + projectId, token, function(error, canWrite) { - if (error != null) { + if (error) { return next(error) } if (canWrite) { logger.log( - { user_id, project_id }, + { userId, projectId }, 'allowing user write access to project content' ) return next() - } else { - logger.log( - { user_id, project_id }, - 'denying user write access to project settings' - ) - return AuthorizationMiddleware.redirectToRestricted(req, res, next) } + logger.log( + { userId, projectId }, + 'denying user write access to project settings' + ) + AuthorizationMiddleware.redirectToRestricted(req, res, next) } ) }) }, ensureUserCanAdminProject(req, res, next) { - return AuthorizationMiddleware._getUserAndProjectId(req, function( + AuthorizationMiddleware._getUserAndProjectId(req, function( error, - user_id, - project_id + userId, + projectId ) { - if (error != null) { + if (error) { return next(error) } - const token = TokenAccessHandler.getRequestToken(req, project_id) - return AuthorizationManager.canUserAdminProject( - user_id, - project_id, + const token = TokenAccessHandler.getRequestToken(req, projectId) + AuthorizationManager.canUserAdminProject( + userId, + projectId, token, function(error, canAdmin) { - if (error != null) { + if (error) { return next(error) } if (canAdmin) { logger.log( - { user_id, project_id }, + { userId, projectId }, 'allowing user admin access to project' ) return next() - } else { - logger.log( - { user_id, project_id }, - 'denying user admin access to project' - ) - return AuthorizationMiddleware.redirectToRestricted(req, res, next) } + logger.log( + { userId, projectId }, + 'denying user admin access to project' + ) + AuthorizationMiddleware.redirectToRestricted(req, res, next) } ) }) }, ensureUserIsSiteAdmin(req, res, next) { - return AuthorizationMiddleware._getUserId(req, function(error, user_id) { - if (error != null) { + AuthorizationMiddleware._getUserId(req, function(error, userId) { + if (error) { return next(error) } - return AuthorizationManager.isUserSiteAdmin(user_id, function( - error, - isAdmin - ) { - if (error != null) { + AuthorizationManager.isUserSiteAdmin(userId, function(error, isAdmin) { + if (error) { return next(error) } if (isAdmin) { - logger.log({ user_id }, 'allowing user admin access to site') + logger.log({ userId }, 'allowing user admin access to site') return next() - } else { - logger.log({ user_id }, 'denying user admin access to site') - return AuthorizationMiddleware.redirectToRestricted(req, res, next) } + logger.log({ userId }, 'denying user admin access to site') + AuthorizationMiddleware.redirectToRestricted(req, res, next) }) }) }, _getUserAndProjectId(req, callback) { - if (callback == null) { - callback = function(error, user_id, project_id) {} - } - const project_id = - (req.params != null ? req.params.project_id : undefined) || - (req.params != null ? req.params.Project_id : undefined) - if (project_id == null) { + const projectId = req.params.project_id || req.params.Project_id + if (!projectId) { return callback(new Error('Expected project_id in request parameters')) } - if (!ObjectId.isValid(project_id)) { + if (!ObjectId.isValid(projectId)) { return callback( - new Errors.NotFoundError(`invalid project_id: ${project_id}`) + new Errors.NotFoundError(`invalid projectId: ${projectId}`) ) } - return AuthorizationMiddleware._getUserId(req, function(error, user_id) { - if (error != null) { + AuthorizationMiddleware._getUserId(req, function(error, userId) { + if (error) { return callback(error) } - return callback(null, user_id, project_id) + callback(null, userId, projectId) }) }, _getUserId(req, callback) { - if (callback == null) { - callback = function(error, user_id) {} - } - const user_id = + const userId = AuthenticationController.getLoggedInUserId(req) || - __guard__(req != null ? req.oauth_user : undefined, x => x._id) || + (req.oauth_user && req.oauth_user._id) || null - return callback(null, user_id) + callback(null, userId) }, redirectToRestricted(req, res, next) { // TODO: move this to throwing ForbiddenError - return res.redirect(`/restricted?from=${encodeURIComponent(req.url)}`) + res.redirect(`/restricted?from=${encodeURIComponent(req.url)}`) }, restricted(req, res, next) { if (AuthenticationController.isUserLoggedIn(req)) { return res.render('user/restricted', { title: 'restricted' }) - } else { - const { from } = req.query - logger.log({ from }, 'redirecting to login') - const redirect_to = '/login' - if (from != null) { - AuthenticationController.setRedirectInSession(req, from) - } - return res.redirect(redirect_to) } + const { from } = req.query + logger.log({ from }, 'redirecting to login') + if (from) { + AuthenticationController.setRedirectInSession(req, from) + } + res.redirect('/login') } } - -function __guard__(value, transform) { - return typeof value !== 'undefined' && value !== null - ? transform(value) - : undefined -} diff --git a/services/web/app/src/Features/Authorization/PrivilegeLevels.js b/services/web/app/src/Features/Authorization/PrivilegeLevels.js index 6e7c310cec..c70a33c0be 100644 --- a/services/web/app/src/Features/Authorization/PrivilegeLevels.js +++ b/services/web/app/src/Features/Authorization/PrivilegeLevels.js @@ -1,5 +1,3 @@ -// TODO: This file was created by bulk-decaffeinate. -// Sanity-check the conversion and remove this comment. module.exports = { NONE: false, READ_ONLY: 'readOnly', diff --git a/services/web/app/src/Features/Authorization/PublicAccessLevels.js b/services/web/app/src/Features/Authorization/PublicAccessLevels.js index ed918f4dab..0c9dc3282f 100644 --- a/services/web/app/src/Features/Authorization/PublicAccessLevels.js +++ b/services/web/app/src/Features/Authorization/PublicAccessLevels.js @@ -1,5 +1,3 @@ -// TODO: This file was created by bulk-decaffeinate. -// Sanity-check the conversion and remove this comment. module.exports = { READ_ONLY: 'readOnly', // LEGACY READ_AND_WRITE: 'readAndWrite', // LEGACY diff --git a/services/web/app/src/Features/Authorization/Sources.js b/services/web/app/src/Features/Authorization/Sources.js index 271e7fca46..bdcb8d5003 100644 --- a/services/web/app/src/Features/Authorization/Sources.js +++ b/services/web/app/src/Features/Authorization/Sources.js @@ -1,5 +1,3 @@ -// TODO: This file was created by bulk-decaffeinate. -// Sanity-check the conversion and remove this comment. module.exports = { INVITE: 'invite', TOKEN: 'token',