[go: nahoru, domu]

Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prevent broadcasting of system messages when hide setting is enabled #32522

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .changeset/grumpy-games-greet.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
'@rocket.chat/meteor': patch
---
Changed streaming logic to prevent hidden system messages from being broadcasted through `stream-room-messages`.
7 changes: 5 additions & 2 deletions apps/meteor/app/lib/server/functions/loadMessageHistory.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import type { IMessage } from '@rocket.chat/core-typings';
import type { IMessage, MessageTypesValues } from '@rocket.chat/core-typings';
import { Messages, Rooms } from '@rocket.chat/models';
import type { FindOptions } from 'mongodb';

import { settings } from '../../../settings/server/cached';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages';

Expand Down Expand Up @@ -29,7 +30,9 @@ export async function loadMessageHistory({
throw new Error('error-invalid-room');
}

const hiddenMessageTypes = getHiddenSystemMessages(room);
const hiddenSystemMessages = settings.get<MessageTypesValues[]>('Hide_System_Messages');

const hiddenMessageTypes = getHiddenSystemMessages(room, hiddenSystemMessages);

AllanPazRibeiro marked this conversation as resolved.
Show resolved Hide resolved
const options: FindOptions<IMessage> = {
sort: {
Expand Down
24 changes: 4 additions & 20 deletions apps/meteor/app/lib/server/lib/getHiddenSystemMessages.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,10 @@
import type { MessageTypesValues, IRoom } from '@rocket.chat/core-typings';

import { settings } from '../../../settings/server';

const hideMessagesOfTypeServer = new Set<MessageTypesValues>();

settings.watch<MessageTypesValues[]>('Hide_System_Messages', (values) => {
if (!values || !Array.isArray(values)) {
return;
}

const hiddenTypes = values.reduce((array, value): MessageTypesValues[] => {
export const getHiddenSystemMessages = (room: IRoom, hiddenSystemMessages: MessageTypesValues[]): MessageTypesValues[] => {
const hiddenTypes = hiddenSystemMessages.reduce((array, value): MessageTypesValues[] => {
const newValue: MessageTypesValues[] = value === 'mute_unmute' ? ['user-muted', 'user-unmuted'] : [value];

return [...array, ...newValue];
}, [] as MessageTypesValues[]);

hideMessagesOfTypeServer.clear();

hiddenTypes.forEach((item) => hideMessagesOfTypeServer.add(item));
});

// TODO probably remove on chained event system
export function getHiddenSystemMessages(room: IRoom): MessageTypesValues[] {
return Array.isArray(room?.sysMes) ? room.sysMes : [...hideMessagesOfTypeServer];
}
return Array.isArray(room?.sysMes) ? room.sysMes : hiddenTypes;
};
7 changes: 5 additions & 2 deletions apps/meteor/app/lib/server/methods/getChannelHistory.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { IMessage } from '@rocket.chat/core-typings';
import type { IMessage, MessageTypesValues } from '@rocket.chat/core-typings';
import { Messages, Subscriptions, Rooms } from '@rocket.chat/models';
import type { ServerMethods } from '@rocket.chat/ui-contexts';
import { check } from 'meteor/check';
Expand All @@ -7,6 +7,7 @@ import _ from 'underscore';

import { canAccessRoomAsync } from '../../../authorization/server';
import { hasPermissionAsync } from '../../../authorization/server/functions/hasPermission';
import { settings } from '../../../settings/server/cached';
import { normalizeMessagesForUser } from '../../../utils/server/lib/normalizeMessagesForUser';
import { getHiddenSystemMessages } from '../lib/getHiddenSystemMessages';

Expand Down Expand Up @@ -67,7 +68,9 @@ Meteor.methods<ServerMethods>({
throw new Meteor.Error('error-invalid-date', 'Invalid date', { method: 'getChannelHistory' });
}

const hiddenMessageTypes = getHiddenSystemMessages(room);
const hiddenSystemMessages = settings.get<MessageTypesValues[]>('Hide_System_Messages');

const hiddenMessageTypes = getHiddenSystemMessages(room, hiddenSystemMessages);

const options: Record<string, unknown> = {
sort: {
Expand Down
13 changes: 13 additions & 0 deletions apps/meteor/server/lib/systemMessage/hideSystemMessage.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import type { MessageTypesValues } from '@rocket.chat/core-typings';

export const isMutedUnmuted = (messageType: string): boolean => {
return messageType === 'user-muted' || messageType === 'user-unmuted';
};

export const shouldHideSystemMessage = (messageType: MessageTypesValues, hideSystemMessage?: MessageTypesValues[]): boolean => {
if (!hideSystemMessage?.length) {
return false;
}

return hideSystemMessage.includes(messageType) || (isMutedUnmuted(messageType) && hideSystemMessage.includes('mute_unmute'));
};
15 changes: 13 additions & 2 deletions apps/meteor/server/modules/watchers/lib/messages.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import { api, dbWatchersDisabled } from '@rocket.chat/core-services';
import type { IMessage, SettingValue, IUser } from '@rocket.chat/core-typings';
import type { IMessage, IUser, MessageTypesValues } from '@rocket.chat/core-typings';
import { Messages, Settings, Users } from '@rocket.chat/models';
import mem from 'mem';

const getSettingCached = mem(async (setting: string): Promise<SettingValue> => Settings.getValueById(setting), { maxAge: 10000 });
import { shouldHideSystemMessage } from '../../../lib/systemMessage/hideSystemMessage';

const getUserNameCached = mem(
async (userId: string): Promise<string | undefined> => {
Expand All @@ -13,12 +13,23 @@ const getUserNameCached = mem(
{ maxAge: 10000 },
);

const getSettingCached = mem(Settings.getValueById, { maxAge: 10000 });

export async function getMessageToBroadcast({ id, data }: { id: IMessage['_id']; data?: IMessage }): Promise<IMessage | void> {
const message = data ?? (await Messages.findOneById(id));
if (!message) {
return;
}

if (message.t) {
const hiddenSystemMessages = (await getSettingCached('Hide_System_Messages')) as MessageTypesValues[];
const shouldHide = shouldHideSystemMessage(message.t, hiddenSystemMessages);

if (shouldHide) {
return;
}
}

if (message._hidden || message.imported != null) {
return;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
import type { MessageTypesValues, IRoom, IUser } from '@rocket.chat/core-typings';
import { expect } from 'chai';

import { getHiddenSystemMessages } from '../../../../../../app/lib/server/lib/getHiddenSystemMessages';

describe('getHiddenSystemMessages', () => {
it('should return room.sysMes if it is an array', async () => {
const room: IRoom = {
_id: 'roomId',
sysMes: ['mute_unmute', 'room_changed_description'] as MessageTypesValues[],
t: 'c',
msgs: 0,
u: {} as IUser,
usersCount: 0,
_updatedAt: new Date(),
};

const result = getHiddenSystemMessages(room, []);

expect(result).to.deep.equal(room.sysMes);
});

it('should return cached hidden system messages if room.sysMes is not an array', async () => {
const cachedHiddenSystemMessage: MessageTypesValues[] = ['mute_unmute', 'room_changed_description'];

const room: IRoom = {
_id: 'roomId',
t: 'c',
msgs: 0,
u: {} as IUser,
usersCount: 0,
_updatedAt: new Date(),
};

const result = getHiddenSystemMessages(room, cachedHiddenSystemMessage);

expect(result).to.deep.equal(['user-muted', 'user-unmuted', 'room_changed_description']);
});

it('should return an empty array if both room.sysMes and cached hidden system messages are undefined', async () => {
const room: IRoom = {
_id: 'roomId',
t: 'c',
msgs: 0,
u: {} as IUser,
usersCount: 0,
_updatedAt: new Date(),
};

const result = getHiddenSystemMessages(room, []);

expect(result).to.deep.equal([]);
});

it('should return cached hidden system messages if room.sysMes is null', async () => {
AllanPazRibeiro marked this conversation as resolved.
Show resolved Hide resolved
const cachedHiddenSystemMessage: MessageTypesValues[] = ['subscription-role-added', 'room_changed_announcement'];

const room: IRoom = {
_id: 'roomId',
sysMes: undefined,
t: 'c',
msgs: 0,
u: {} as IUser,
usersCount: 0,
_updatedAt: new Date(),
};

const result = getHiddenSystemMessages(room, cachedHiddenSystemMessage);

expect(result).to.deep.equal(cachedHiddenSystemMessage);
});

it('should return cached hidden system messages if room.sysMes array and hidden system message is available', async () => {
const cachedHiddenSystemMessage: MessageTypesValues[] = ['room_changed_announcement', 'room-archived'];

const room: IRoom = {
_id: 'roomId',
sysMes: ['mute_unmute', 'room_changed_description'] as MessageTypesValues[],
t: 'c',
msgs: 0,
u: {} as IUser,
usersCount: 0,
_updatedAt: new Date(),
};

const result = getHiddenSystemMessages(room, cachedHiddenSystemMessage);

expect(result).to.deep.equal(['mute_unmute', 'room_changed_description']);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import type { MessageTypesValues } from '@rocket.chat/core-typings';
import { expect } from 'chai';

import { isMutedUnmuted, shouldHideSystemMessage } from '../../../../../server/lib/systemMessage/hideSystemMessage';

describe('hideSystemMessage', () => {
describe('isMutedUnmuted', () => {
it('should return true for user-muted', () => {
expect(isMutedUnmuted('user-muted')).to.be.true;
});

it('should return true for user-unmuted', () => {
expect(isMutedUnmuted('user-unmuted')).to.be.true;
});

it('should return false for other message types', () => {
expect(isMutedUnmuted('some-other-type')).to.be.false;
});
});

describe('shouldHideSystemMessage', () => {
it('should return true if message type is in hidden system messages', async () => {
const hiddenMessages: MessageTypesValues[] = ['user-muted', 'mute_unmute'];

const result = shouldHideSystemMessage('user-muted', hiddenMessages);
expect(result).to.be.true;
});

it('should return true if message type is user-muted and mute_unmute is in hidden system messages', async () => {
const hiddenMessages: MessageTypesValues[] = ['mute_unmute'];

const result = shouldHideSystemMessage('user-muted', hiddenMessages);
expect(result).to.be.true;
});

it('should return false if message type is not in hidden system messages', async () => {
const hiddenMessages: MessageTypesValues[] = ['room-archived'];

const result = shouldHideSystemMessage('user-muted', hiddenMessages);
expect(result).to.be.false;
});

it('should return false if hidden system messages are undefined', async () => {
const result = shouldHideSystemMessage('user-muted', undefined);
expect(result).to.be.false;
});
});
});
Loading
Loading