diff --git a/app/action-links/client/lib/actionLinks.js b/app/action-links/client/lib/actionLinks.js index 42aef4d55dcf..6586a42205a6 100644 --- a/app/action-links/client/lib/actionLinks.js +++ b/app/action-links/client/lib/actionLinks.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { handleError } from '../../../../client/lib/utils/handleError'; -import { Messages, Subscriptions } from '../../../models/client'; +import { Messages } from '../../../models/client'; // Action Links namespace creation. export const actionLinks = { @@ -24,16 +24,6 @@ export const actionLinks = { }); } - const subscription = Subscriptions.findOne({ - 'rid': message.rid, - 'u._id': userId, - }); - if (!subscription) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - function: 'actionLinks.getMessage', - }); - } - if (!message.actionLinks || !message.actionLinks[name]) { throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link', { function: 'actionLinks.getMessage', diff --git a/app/action-links/server/lib/actionLinks.js b/app/action-links/server/lib/actionLinks.js index 6dbbd4c5c4c1..f04553d6656c 100644 --- a/app/action-links/server/lib/actionLinks.js +++ b/app/action-links/server/lib/actionLinks.js @@ -1,6 +1,16 @@ import { Meteor } from 'meteor/meteor'; -import { Messages, Subscriptions } from '../../../models/server'; +import { getMessageForUser } from '../../../../server/lib/messages/getMessageForUser'; + +function getMessageById(messageId) { + try { + return Promise.await(getMessageForUser(messageId, Meteor.userId())); + } catch (e) { + throw new Meteor.Error(e.message, 'Invalid message', { + function: 'actionLinks.getMessage', + }); + } +} // Action Links namespace creation. export const actionLinks = { @@ -9,30 +19,14 @@ export const actionLinks = { actionLinks.actions[name] = funct; }, getMessage(name, messageId) { - const userId = Meteor.userId(); - if (!userId) { - throw new Meteor.Error('error-invalid-user', 'Invalid user', { - function: 'actionLinks.getMessage', - }); - } + const message = getMessageById(messageId); - const message = Messages.findOne({ _id: messageId }); if (!message) { throw new Meteor.Error('error-invalid-message', 'Invalid message', { function: 'actionLinks.getMessage', }); } - const subscription = Subscriptions.findOne({ - 'rid': message.rid, - 'u._id': userId, - }); - if (!subscription) { - throw new Meteor.Error('error-not-allowed', 'Not allowed', { - function: 'actionLinks.getMessage', - }); - } - if (!message.actionLinks || !message.actionLinks[name]) { throw new Meteor.Error('error-invalid-actionlink', 'Invalid action link', { function: 'actionLinks.getMessage', diff --git a/app/lib/lib/roomTypes/private.js b/app/lib/lib/roomTypes/private.js index d4dd7e931a05..fae84f6c5677 100644 --- a/app/lib/lib/roomTypes/private.js +++ b/app/lib/lib/roomTypes/private.js @@ -1,6 +1,6 @@ import { Meteor } from 'meteor/meteor'; -import { ChatRoom, ChatSubscription } from '../../../models'; +import { ChatRoom } from '../../../models'; import { openRoom } from '../../../ui-utils'; import { settings } from '../../../settings'; import { hasAtLeastOnePermission, hasPermission } from '../../../authorization'; @@ -74,15 +74,6 @@ export class PrivateRoomType extends RoomTypeConfig { return hasAtLeastOnePermission(['add-user-to-any-p-room', 'add-user-to-joined-room'], room._id); } - canSendMessage(roomId) { - // TODO: remove duplicated code - return ( - ChatSubscription.find({ - rid: roomId, - }).count() > 0 - ); - } - allowRoomSettingChange(room, setting) { switch (setting) { case RoomSettingsEnum.JOIN_CODE: diff --git a/app/lib/lib/roomTypes/public.js b/app/lib/lib/roomTypes/public.js index 7282b4a00c56..e3dcc4123d89 100644 --- a/app/lib/lib/roomTypes/public.js +++ b/app/lib/lib/roomTypes/public.js @@ -1,7 +1,7 @@ import { Meteor } from 'meteor/meteor'; import { openRoom } from '../../../ui-utils'; -import { ChatRoom, ChatSubscription } from '../../../models'; +import { ChatRoom } from '../../../models'; import { settings } from '../../../settings'; import { hasAtLeastOnePermission } from '../../../authorization'; import { getUserPreference, RoomTypeConfig, RoomTypeRouteConfig, RoomSettingsEnum, UiTextContext, RoomMemberActions } from '../../../utils'; @@ -86,20 +86,6 @@ export class PublicRoomType extends RoomTypeConfig { return hasAtLeastOnePermission(['add-user-to-any-c-room', 'add-user-to-joined-room'], room._id); } - canSendMessage(roomId) { - const room = ChatRoom.findOne({ _id: roomId, t: 'c' }, { fields: { prid: 1 } }); - if (room.prid) { - return true; - } - - // TODO: remove duplicated code - return ( - ChatSubscription.find({ - rid: roomId, - }).count() > 0 - ); - } - enableMembersListProfile() { return true; } diff --git a/app/ui-utils/client/lib/openRoom.js b/app/ui-utils/client/lib/openRoom.js index 76e8f449ee5f..8f79eb5e789c 100644 --- a/app/ui-utils/client/lib/openRoom.js +++ b/app/ui-utils/client/lib/openRoom.js @@ -62,6 +62,7 @@ export const openRoom = async function (type, name, render = true) { } NewRoomManager.open(room._id); + Session.set('openedRoom', room._id); fireGlobalEvent('room-opened', _.omit(room, 'usernames')); diff --git a/app/videobridge/client/actionLink.js b/app/videobridge/client/actionLink.js index 838e56e4cc72..bc791c92ebea 100644 --- a/app/videobridge/client/actionLink.js +++ b/app/videobridge/client/actionLink.js @@ -7,20 +7,48 @@ import { Rooms } from '../../models'; import { dispatchToastMessage } from '../../../client/lib/toast'; actionLinks.register('joinJitsiCall', function (message, params, instance) { - if (Session.get('openedRoom')) { - const rid = Session.get('openedRoom'); + const rid = Session.get('openedRoom'); + if (!rid) { + return; + } + + const room = Rooms.findOne({ _id: rid }); + const username = Meteor.user()?.username; + + if (!room) { + dispatchToastMessage({ type: 'info', message: TAPi18n.__('Call Already Ended', '') }); + return; + } + + if (room?.muted?.includes(username)) { + dispatchToastMessage({ type: 'error', message: TAPi18n.__('You_have_been_muted', '') }); + return; + } + + const clickTime = new Date(); + const jitsiTimeout = new Date(room.jitsiTimeout); - const room = Rooms.findOne({ _id: rid }); - const username = Meteor.user()?.username; - const currentTime = new Date().getTime(); - const jitsiTimeout = new Date((room && room.jitsiTimeout) || currentTime).getTime(); + if (jitsiTimeout > clickTime) { + instance.tabBar.open('video'); + return; + } + + // Get updated room info from the server to check if the call is still happening + Meteor.call('getRoomById', rid, (err, result) => { + if (err) { + throw err; + } - if (room && room?.muted?.includes(username)) { - dispatchToastMessage({ type: 'error', message: TAPi18n.__('You_have_been_muted', '') }); - } else if (jitsiTimeout > currentTime) { + // If the openedRoom has changed, abort + if (rid !== Session.get('openedRoom')) { + return; + } + + if (result?.jitsiTimeout && result.jitsiTimeout instanceof Date && result.jitsiTimeout > clickTime) { instance.tabBar.open('video'); - } else { - dispatchToastMessage({ type: 'info', message: TAPi18n.__('Call Already Ended', '') }); + return; } - } + + dispatchToastMessage({ type: 'info', message: TAPi18n.__('Call Already Ended', '') }); + }); }); diff --git a/client/views/room/contextualBar/Call/Jitsi/CallJitsiWithData.js b/client/views/room/contextualBar/Call/Jitsi/CallJitsiWithData.js index a7dcd2d2e01f..b8a106f081ea 100644 --- a/client/views/room/contextualBar/Call/Jitsi/CallJitsiWithData.js +++ b/client/views/room/contextualBar/Call/Jitsi/CallJitsiWithData.js @@ -3,6 +3,7 @@ import { useMutableCallback, useSafely } from '@rocket.chat/fuselage-hooks'; import { clear } from '@rocket.chat/memo'; import React, { useRef, useEffect, useState, useMemo, useLayoutEffect, memo } from 'react'; +import { Subscriptions } from '../../../../../../app/models/client'; import { HEARTBEAT, TIMEOUT, DEBOUNCE } from '../../../../../../app/videobridge/constants'; import { useConnectionStatus } from '../../../../../contexts/ConnectionStatusContext'; import { useSetModal } from '../../../../../contexts/ModalContext'; @@ -44,6 +45,7 @@ const CallJitsiWithData = ({ rid }) => { const closeModal = useMutableCallback(() => setModal(null)); const generateAccessToken = useMethod('jitsi:generateAccessToken'); const updateTimeout = useMethod('jitsi:updateTimeout'); + const joinRoom = useMethod('joinRoom'); const dispatchToastMessage = useToastMessageDispatch(); const t = useTranslation(); @@ -187,6 +189,10 @@ const CallJitsiWithData = ({ rid }) => { } setAccepted(true); + const sub = Subscriptions.findOne({ rid, 'u._id': user._id }); + if (!sub) { + joinRoom(rid); + } if (openNewWindow) { handleClose(); diff --git a/server/lib/messages/getMessageForUser.ts b/server/lib/messages/getMessageForUser.ts new file mode 100644 index 000000000000..df462afb1986 --- /dev/null +++ b/server/lib/messages/getMessageForUser.ts @@ -0,0 +1,21 @@ +import type { IUser } from '../../../definition/IUser'; +import type { IMessage } from '../../../definition/IMessage/IMessage'; +import { Messages } from '../../../app/models/server/raw'; +import { canAccessRoomId } from '../../../app/authorization/server'; + +export async function getMessageForUser(messageId: IMessage['_id'], uid: IUser['_id']): Promise { + if (!uid) { + throw new Error('error-invalid-user'); + } + + const message = await Messages.findOne(messageId); + if (!message) { + return; + } + + if (!canAccessRoomId(message.rid, uid)) { + throw new Error('error-not-allowed'); + } + + return message; +}