From c30b3486680c6df7ba61187ab66000df12335172 Mon Sep 17 00:00:00 2001 From: Domagoj Kriskovic Date: Wed, 10 Sep 2025 11:11:19 +0200 Subject: [PATCH] For editing/deleting chat messages ensure user is a message author GitOrigin-RevId: d7d4f1bb9f004d8fed8644f0aabe621ed863437b --- .../Authorization/AuthorizationMiddleware.mjs | 41 +++++++++++++++++++ services/web/app/src/router.mjs | 2 + 2 files changed, 43 insertions(+) diff --git a/services/web/app/src/Features/Authorization/AuthorizationMiddleware.mjs b/services/web/app/src/Features/Authorization/AuthorizationMiddleware.mjs index bea31ca533..a38d1e6e2f 100644 --- a/services/web/app/src/Features/Authorization/AuthorizationMiddleware.mjs +++ b/services/web/app/src/Features/Authorization/AuthorizationMiddleware.mjs @@ -10,6 +10,7 @@ import TokenAccessHandler from '../TokenAccess/TokenAccessHandler.mjs' import { expressify } from '@overleaf/promise-utils' import AdminAuthorizationHelper from '../Helpers/AdminAuthorizationHelper.mjs' import UrlHelper from '../Helpers/UrlHelper.mjs' +import ChatApiHandler from '../Chat/ChatApiHandler.mjs' const { ObjectId } = mongodb @@ -202,6 +203,34 @@ async function ensureUserCanAdminProject(req, res, next) { HttpErrorHandler.forbidden(req, res) } +async function ensureUserIsMessageAuthor(req, res, next) { + const projectId = _getProjectId(req) + const messageId = _getMessageId(req) + const userId = _getUserId(req) + + if (!userId) { + logger.debug({ projectId, messageId }, 'denying access: no logged in user') + return HttpErrorHandler.forbidden(req, res) + } + + const message = await ChatApiHandler.promises.getGlobalMessage( + projectId, + messageId + ) + if (message.user_id === userId) { + logger.debug( + { userId, projectId, messageId }, + 'allowing user to modify their own message' + ) + return next() + } + logger.debug( + { userId, projectId, messageId, messageAuthor: message.user_id }, + 'denying user access to modify message: not the author' + ) + return HttpErrorHandler.forbidden(req, res) +} + async function ensureUserIsSiteAdmin(req, res, next) { const userId = _getUserId(req) if (await AuthorizationManager.promises.isUserSiteAdmin(userId)) { @@ -235,6 +264,17 @@ function _getThreadId(req) { return threadId } +function _getMessageId(req) { + const messageId = req.params.message_id + if (!messageId) { + throw new Error('Expected message_id in request parameters') + } + if (!ObjectId.isValid(messageId)) { + throw new Errors.NotFoundError(`invalid messageId: ${messageId}`) + } + return messageId +} + function _getUserId(req) { return ( SessionManager.getLoggedInUserId(req.session) || @@ -280,5 +320,6 @@ export default { ), ensureUserCanAdminProject: expressify(ensureUserCanAdminProject), ensureUserIsSiteAdmin: expressify(ensureUserIsSiteAdmin), + ensureUserIsMessageAuthor: expressify(ensureUserIsMessageAuthor), restricted, } diff --git a/services/web/app/src/router.mjs b/services/web/app/src/router.mjs index 0b5e9c1fa5..f1c36d2f4c 100644 --- a/services/web/app/src/router.mjs +++ b/services/web/app/src/router.mjs @@ -983,6 +983,7 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) { '/project/:project_id/messages/:message_id', AuthorizationMiddleware.blockRestrictedUserFromProject, AuthorizationMiddleware.ensureUserCanReadProject, + AuthorizationMiddleware.ensureUserIsMessageAuthor, PermissionsController.requirePermission('chat'), ChatController.deleteMessage ) @@ -990,6 +991,7 @@ async function initialize(webRouter, privateApiRouter, publicApiRouter) { '/project/:project_id/messages/:message_id/edit', AuthorizationMiddleware.blockRestrictedUserFromProject, AuthorizationMiddleware.ensureUserCanReadProject, + AuthorizationMiddleware.ensureUserIsMessageAuthor, PermissionsController.requirePermission('chat'), ChatController.editMessage )