2019-05-29 05:21:06 -04:00
|
|
|
const AuthorizationManager = require('./AuthorizationManager')
|
|
|
|
const logger = require('logger-sharelatex')
|
2020-09-23 04:49:26 -04:00
|
|
|
const { ObjectId } = require('mongodb')
|
2019-05-29 05:21:06 -04:00
|
|
|
const Errors = require('../Errors/Errors')
|
2020-07-09 09:47:43 -04:00
|
|
|
const HttpErrorHandler = require('../Errors/HttpErrorHandler')
|
2019-05-29 05:21:06 -04:00
|
|
|
const AuthenticationController = require('../Authentication/AuthenticationController')
|
2021-07-28 04:51:20 -04:00
|
|
|
const SessionManager = require('../Authentication/SessionManager')
|
2019-05-29 05:21:06 -04:00
|
|
|
const TokenAccessHandler = require('../TokenAccess/TokenAccessHandler')
|
2021-09-13 09:43:46 -04:00
|
|
|
const { expressify } = require('../../util/promises')
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
async function ensureUserCanReadMultipleProjects(req, res, next) {
|
|
|
|
const projectIds = (req.query.project_ids || '').split(',')
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
for (const projectId of projectIds) {
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
const canRead = await AuthorizationManager.promises.canUserReadProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
2021-09-13 09:43:46 -04:00
|
|
|
if (!canRead) {
|
|
|
|
return _redirectToRestricted(req, res, next)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
next()
|
|
|
|
}
|
2020-06-04 04:47:12 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
async function blockRestrictedUserFromProject(req, res, next) {
|
|
|
|
const projectId = _getProjectId(req)
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
const isRestrictedUser = await AuthorizationManager.promises.isRestrictedUserForProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
|
|
|
)
|
|
|
|
if (isRestrictedUser) {
|
|
|
|
return HttpErrorHandler.forbidden(req, res)
|
|
|
|
}
|
|
|
|
next()
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ensureUserCanReadProject(req, res, next) {
|
|
|
|
const projectId = _getProjectId(req)
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
const canRead = await AuthorizationManager.promises.canUserReadProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
|
|
|
)
|
|
|
|
if (canRead) {
|
|
|
|
logger.log({ userId, projectId }, 'allowing user read access to project')
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
logger.log({ userId, projectId }, 'denying user read access to project')
|
|
|
|
HttpErrorHandler.forbidden(req, res)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
async function ensureUserCanWriteProjectSettings(req, res, next) {
|
|
|
|
const projectId = _getProjectId(req)
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
|
|
|
|
if (req.body.name != null) {
|
|
|
|
const canRename = await AuthorizationManager.promises.canUserRenameProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
2021-09-13 09:43:46 -04:00
|
|
|
if (!canRename) {
|
|
|
|
return HttpErrorHandler.forbidden(req, res)
|
|
|
|
}
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
const otherParams = Object.keys(req.body).filter(x => x !== 'name')
|
|
|
|
if (otherParams.length > 0) {
|
|
|
|
const canWrite = await AuthorizationManager.promises.canUserWriteProjectSettings(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
2021-09-13 09:43:46 -04:00
|
|
|
if (!canWrite) {
|
|
|
|
return HttpErrorHandler.forbidden(req, res)
|
|
|
|
}
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
next()
|
|
|
|
}
|
|
|
|
|
|
|
|
async function ensureUserCanWriteProjectContent(req, res, next) {
|
|
|
|
const projectId = _getProjectId(req)
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
const canWrite = await AuthorizationManager.promises.canUserWriteProjectContent(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
|
|
|
)
|
|
|
|
if (canWrite) {
|
|
|
|
logger.log(
|
|
|
|
{ userId, projectId },
|
|
|
|
'allowing user write access to project content'
|
2021-04-14 09:17:21 -04:00
|
|
|
)
|
2021-09-13 09:43:46 -04:00
|
|
|
return next()
|
|
|
|
}
|
|
|
|
logger.log(
|
|
|
|
{ userId, projectId },
|
|
|
|
'denying user write access to project settings'
|
|
|
|
)
|
|
|
|
HttpErrorHandler.forbidden(req, res)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
async function ensureUserCanAdminProject(req, res, next) {
|
|
|
|
const projectId = _getProjectId(req)
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
const token = TokenAccessHandler.getRequestToken(req, projectId)
|
|
|
|
const canAdmin = await AuthorizationManager.promises.canUserAdminProject(
|
|
|
|
userId,
|
|
|
|
projectId,
|
|
|
|
token
|
|
|
|
)
|
|
|
|
if (canAdmin) {
|
|
|
|
logger.log({ userId, projectId }, 'allowing user admin access to project')
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
logger.log({ userId, projectId }, 'denying user admin access to project')
|
|
|
|
HttpErrorHandler.forbidden(req, res)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
async function ensureUserIsSiteAdmin(req, res, next) {
|
|
|
|
const userId = _getUserId(req)
|
|
|
|
const isAdmin = await AuthorizationManager.promises.isUserSiteAdmin(userId)
|
|
|
|
if (isAdmin) {
|
|
|
|
logger.log({ userId }, 'allowing user admin access to site')
|
|
|
|
return next()
|
|
|
|
}
|
|
|
|
logger.log({ userId }, 'denying user admin access to site')
|
|
|
|
_redirectToRestricted(req, res, next)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
function _getProjectId(req) {
|
|
|
|
const projectId = req.params.project_id || req.params.Project_id
|
|
|
|
if (!projectId) {
|
|
|
|
throw new Error('Expected project_id in request parameters')
|
|
|
|
}
|
|
|
|
if (!ObjectId.isValid(projectId)) {
|
|
|
|
throw new Errors.NotFoundError(`invalid projectId: ${projectId}`)
|
|
|
|
}
|
|
|
|
return projectId
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
function _getUserId(req) {
|
|
|
|
return (
|
|
|
|
SessionManager.getLoggedInUserId(req.session) ||
|
|
|
|
(req.oauth_user && req.oauth_user._id) ||
|
|
|
|
null
|
|
|
|
)
|
|
|
|
}
|
2019-05-29 05:21:06 -04:00
|
|
|
|
2021-09-13 09:43:46 -04:00
|
|
|
function _redirectToRestricted(req, res, next) {
|
|
|
|
// TODO: move this to throwing ForbiddenError
|
|
|
|
res.redirect(`/restricted?from=${encodeURIComponent(res.locals.currentUrl)}`)
|
|
|
|
}
|
|
|
|
|
|
|
|
function restricted(req, res, next) {
|
|
|
|
if (SessionManager.isUserLoggedIn(req.session)) {
|
|
|
|
return res.render('user/restricted', { title: 'restricted' })
|
|
|
|
}
|
|
|
|
const { from } = req.query
|
|
|
|
logger.log({ from }, 'redirecting to login')
|
|
|
|
if (from) {
|
|
|
|
AuthenticationController.setRedirectInSession(req, from)
|
|
|
|
}
|
|
|
|
res.redirect('/login')
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = {
|
|
|
|
ensureUserCanReadMultipleProjects: expressify(
|
|
|
|
ensureUserCanReadMultipleProjects
|
|
|
|
),
|
|
|
|
blockRestrictedUserFromProject: expressify(blockRestrictedUserFromProject),
|
|
|
|
ensureUserCanReadProject: expressify(ensureUserCanReadProject),
|
|
|
|
ensureUserCanWriteProjectSettings: expressify(
|
|
|
|
ensureUserCanWriteProjectSettings
|
|
|
|
),
|
|
|
|
ensureUserCanWriteProjectContent: expressify(
|
|
|
|
ensureUserCanWriteProjectContent
|
|
|
|
),
|
|
|
|
ensureUserCanAdminProject: expressify(ensureUserCanAdminProject),
|
|
|
|
ensureUserIsSiteAdmin: expressify(ensureUserIsSiteAdmin),
|
|
|
|
restricted,
|
2019-05-29 05:21:06 -04:00
|
|
|
}
|