| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284 |
- import AuthorizationManager from './AuthorizationManager.js'
- import logger from '@overleaf/logger'
- import mongodb from 'mongodb-legacy'
- import Errors from '../Errors/Errors.js'
- import HttpErrorHandler from '../Errors/HttpErrorHandler.js'
- import AuthenticationController from '../Authentication/AuthenticationController.js'
- import SessionManager from '../Authentication/SessionManager.js'
- import TokenAccessHandler from '../TokenAccess/TokenAccessHandler.js'
- import { expressify } from '@overleaf/promise-utils'
- import AdminAuthorizationHelper from '../Helpers/AdminAuthorizationHelper.js'
- import UrlHelper from '../Helpers/UrlHelper.js'
- const { ObjectId } = mongodb
- function _handleAdminDomainRedirect(req, res) {
- if (
- AdminAuthorizationHelper.canRedirectToAdminDomain(
- SessionManager.getSessionUser(req.session)
- )
- ) {
- logger.warn({ req }, 'redirecting admin user to admin domain')
- res.redirect(UrlHelper.getSafeAdminDomainRedirect(req.originalUrl))
- return true
- }
- return false
- }
- 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
- )
- if (!canRead) {
- return _redirectToRestricted(req, res, next)
- }
- }
- next()
- }
- 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.debug({ userId, projectId }, 'allowing user read access to project')
- return next()
- }
- logger.debug({ userId, projectId }, 'denying user read access to project')
- HttpErrorHandler.forbidden(req, res)
- }
- 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
- )
- if (!canRename) {
- return HttpErrorHandler.forbidden(req, res)
- }
- }
- const otherParams = Object.keys(req.body).filter(x => x !== 'name')
- if (otherParams.length > 0) {
- const canWrite =
- await AuthorizationManager.promises.canUserWriteProjectSettings(
- userId,
- projectId,
- token
- )
- if (!canWrite) {
- return HttpErrorHandler.forbidden(req, res)
- }
- }
- next()
- }
- async function ensureUserCanDeleteOrResolveThread(req, res, next) {
- const projectId = _getProjectId(req)
- const threadId = _getThreadId(req)
- const userId = _getUserId(req)
- const token = TokenAccessHandler.getRequestToken(req, projectId)
- const canDeleteThread =
- await AuthorizationManager.promises.canUserDeleteOrResolveThread(
- userId,
- projectId,
- threadId,
- token
- )
- if (canDeleteThread) {
- logger.debug(
- { userId, projectId },
- 'allowing user to delete or resolve a comment thread'
- )
- return next()
- }
- logger.debug(
- { userId, projectId, threadId },
- 'denying user to delete or resolve a comment thread'
- )
- return HttpErrorHandler.forbidden(req, res)
- }
- 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.debug(
- { userId, projectId },
- 'allowing user write access to project content'
- )
- return next()
- }
- logger.debug(
- { userId, projectId },
- 'denying user write access to project settings'
- )
- HttpErrorHandler.forbidden(req, res)
- }
- async function ensureUserCanWriteOrReviewProjectContent(req, res, next) {
- const projectId = _getProjectId(req)
- const userId = _getUserId(req)
- const token = TokenAccessHandler.getRequestToken(req, projectId)
- const canWriteOrReviewProjectContent =
- await AuthorizationManager.promises.canUserWriteOrReviewProjectContent(
- userId,
- projectId,
- token
- )
- if (canWriteOrReviewProjectContent) {
- logger.debug(
- { userId, projectId },
- 'allowing user write or review access to project content'
- )
- return next()
- }
- logger.debug(
- { userId, projectId },
- 'denying user write or review access to project content'
- )
- return HttpErrorHandler.forbidden(req, res)
- }
- 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.debug({ userId, projectId }, 'allowing user admin access to project')
- return next()
- }
- logger.debug({ userId, projectId }, 'denying user admin access to project')
- HttpErrorHandler.forbidden(req, res)
- }
- async function ensureUserIsSiteAdmin(req, res, next) {
- const userId = _getUserId(req)
- if (await AuthorizationManager.promises.isUserSiteAdmin(userId)) {
- logger.debug({ userId }, 'allowing user admin access to site')
- return next()
- }
- if (_handleAdminDomainRedirect(req, res)) return
- logger.debug({ userId }, 'denying user admin access to site')
- _redirectToRestricted(req, res, next)
- }
- 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
- }
- function _getThreadId(req) {
- const threadId = req.params.thread_id
- if (!threadId) {
- throw new Error('Expected thread_id in request parameters')
- }
- if (!ObjectId.isValid(threadId)) {
- throw new Errors.NotFoundError(`invalid threadId: ${threadId}`)
- }
- return threadId
- }
- function _getUserId(req) {
- return (
- SessionManager.getLoggedInUserId(req.session) ||
- (req.oauth_user && req.oauth_user._id?.toString()) ||
- null
- )
- }
- 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.debug({ from }, 'redirecting to login')
- if (from) {
- AuthenticationController.setRedirectInSession(req, from)
- }
- res.redirect('/login')
- }
- export default {
- ensureUserCanReadMultipleProjects: expressify(
- ensureUserCanReadMultipleProjects
- ),
- blockRestrictedUserFromProject: expressify(blockRestrictedUserFromProject),
- ensureUserCanReadProject: expressify(ensureUserCanReadProject),
- ensureUserCanWriteProjectSettings: expressify(
- ensureUserCanWriteProjectSettings
- ),
- ensureUserCanDeleteOrResolveThread: expressify(
- ensureUserCanDeleteOrResolveThread
- ),
- ensureUserCanWriteProjectContent: expressify(
- ensureUserCanWriteProjectContent
- ),
- ensureUserCanWriteOrReviewProjectContent: expressify(
- ensureUserCanWriteOrReviewProjectContent
- ),
- ensureUserCanAdminProject: expressify(ensureUserCanAdminProject),
- ensureUserIsSiteAdmin: expressify(ensureUserIsSiteAdmin),
- restricted,
- }
|