Skip to content

Commit d0d2094

Browse files
add maxMessageParseSize parameter to parser
1 parent 72fb0bd commit d0d2094

8 files changed

Lines changed: 73 additions & 19 deletions

File tree

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { useSetting } from '@rocket.chat/ui-contexts';
2+
import { useMemo } from 'react';
3+
4+
import { MESSAGE_PARSE_HARD_LIMIT } from '../../../lib/constants';
5+
6+
/**
7+
* Returns the maximum allowed size for message parsing.
8+
* Uses Math.min to ensure it never exceeds the hard limit to avoid performance issues.
9+
* Always returns a number, never null or undefined.
10+
*/
11+
export const useMaxMessageParseSize = (): number => {
12+
const settingValue = useSetting('Message_MaxAllowedSize', 5000);
13+
14+
return useMemo(() => {
15+
const maxSize = typeof settingValue === 'number' ? settingValue : 5000;
16+
return Math.min(maxSize, MESSAGE_PARSE_HARD_LIMIT);
17+
}, [settingValue]);
18+
};

apps/meteor/client/components/message/hooks/useNormalizedMessage.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ const normalizeAttachments = (attachments: MessageAttachment[], name?: string, t
5757
});
5858
};
5959

60-
export const useNormalizedMessage = <TMessage extends IMessage>(message: TMessage): MessageWithMdEnforced => {
60+
export const useNormalizedMessage = <TMessage extends IMessage>(message: TMessage, maxMessageParseSize: number): MessageWithMdEnforced => {
6161
const katex = useMessageListKatex();
6262
const katexEnabled = !!katex;
6363
const customDomains = useAutoLinkDomains();
@@ -77,7 +77,7 @@ export const useNormalizedMessage = <TMessage extends IMessage>(message: TMessag
7777
}),
7878
};
7979

80-
const normalizedMessage = parseMessageTextToAstMarkdown(message, parseOptions, autoTranslateOptions);
80+
const normalizedMessage = parseMessageTextToAstMarkdown(message, parseOptions, autoTranslateOptions, maxMessageParseSize);
8181

8282
if (normalizedMessage.attachments) {
8383
normalizedMessage.attachments = normalizeAttachments(
@@ -88,5 +88,14 @@ export const useNormalizedMessage = <TMessage extends IMessage>(message: TMessag
8888
}
8989

9090
return normalizedMessage;
91-
}, [showColors, customDomains, katexEnabled, katex?.dollarSyntaxEnabled, katex?.parenthesisSyntaxEnabled, message, autoTranslateOptions]);
91+
}, [
92+
showColors,
93+
customDomains,
94+
katexEnabled,
95+
katex?.dollarSyntaxEnabled,
96+
katex?.parenthesisSyntaxEnabled,
97+
message,
98+
autoTranslateOptions,
99+
maxMessageParseSize,
100+
]);
92101
};

apps/meteor/client/components/message/variants/ThreadMessagePreview.tsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { useGoToThread } from '../../../views/room/hooks/useGoToThread';
3131
import Emoji from '../../Emoji';
3232
import { useShowTranslated } from '../list/MessageListContext';
3333
import ThreadMessagePreviewBody from './threadPreview/ThreadMessagePreviewBody';
34+
import { useMaxMessageParseSize } from '../hooks/useMaxMessageParseSize';
3435

3536
type ThreadMessagePreviewProps = {
3637
message: IThreadMessage;
@@ -51,7 +52,9 @@ const ThreadMessagePreview = ({ message, showUserAvatar, sequential, ...props }:
5152
useCountSelected();
5253

5354
const messageType = parentMessage.isSuccess ? MessageTypes.getType(parentMessage.data) : null;
54-
const messageBody = useMessageBody(parentMessage.data);
55+
56+
const maxMessageParseSize = useMaxMessageParseSize();
57+
const messageBody = useMessageBody(parentMessage.data, maxMessageParseSize);
5558

5659
const previewMessage = isParsedMessage(messageBody) ? { md: messageBody } : { msg: messageBody };
5760

apps/meteor/client/components/message/variants/room/RoomMessageContent.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import MessageActions from '../../content/MessageActions';
1818
import Reactions from '../../content/Reactions';
1919
import ThreadMetrics from '../../content/ThreadMetrics';
2020
import UrlPreviews from '../../content/UrlPreviews';
21+
import { useMaxMessageParseSize } from '../../hooks/useMaxMessageParseSize';
2122
import { useNormalizedMessage } from '../../hooks/useNormalizedMessage';
2223
import { useOembedLayout } from '../../hooks/useOembedLayout';
2324
import { useSubscriptionFromMessageQuery } from '../../hooks/useSubscriptionFromMessageQuery';
@@ -42,8 +43,9 @@ const RoomMessageContent = ({ message, unread, all, mention, searchText }: RoomM
4243
const messageUser = { ...message.u, roles: [], ...useUserPresence(message.u._id) };
4344
const chat = useChat();
4445
const { t } = useTranslation();
46+
const maxMessageParseSize = useMaxMessageParseSize();
4547

46-
const normalizedMessage = useNormalizedMessage(message);
48+
const normalizedMessage = useNormalizedMessage(message, maxMessageParseSize);
4749
const isMessageEncrypted = encrypted && normalizedMessage?.e2e === 'pending';
4850

4951
const quotes = normalizedMessage?.attachments?.filter(isQuoteAttachment) || [];

apps/meteor/client/components/message/variants/thread/ThreadMessageContent.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import Location from '../../content/Location';
1515
import MessageActions from '../../content/MessageActions';
1616
import Reactions from '../../content/Reactions';
1717
import UrlPreviews from '../../content/UrlPreviews';
18+
import { useMaxMessageParseSize } from '../../hooks/useMaxMessageParseSize';
1819
import { useNormalizedMessage } from '../../hooks/useNormalizedMessage';
1920
import { useOembedLayout } from '../../hooks/useOembedLayout';
2021
import { useSubscriptionFromMessageQuery } from '../../hooks/useSubscriptionFromMessageQuery';
@@ -33,10 +34,11 @@ const ThreadMessageContent = ({ message }: ThreadMessageContentProps): ReactElem
3334
const uid = useUserId();
3435
const { enabled: readReceiptEnabled } = useMessageListReadReceipts();
3536
const messageUser = { ...message.u, roles: [], ...useUserPresence(message.u._id) };
37+
const maxMessageParseSize = useMaxMessageParseSize();
3638

3739
const { t } = useTranslation();
3840

39-
const normalizedMessage = useNormalizedMessage(message);
41+
const normalizedMessage = useNormalizedMessage(message, maxMessageParseSize);
4042

4143
const isMessageEncrypted = encrypted && normalizedMessage?.e2e === 'pending';
4244

apps/meteor/client/lib/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ export const BIO_TEXT_MAX_LENGTH = 260;
33
export const VIDEOCONF_STACK_MAX_USERS = 6;
44
export const NAVIGATION_REGION_ID = 'navigation-region';
55
export const MAX_FILE_SIZE_PREVIEW = 10485760; // 10MB
6+
export const MESSAGE_PARSE_HARD_LIMIT = 5000;

apps/meteor/client/lib/parseMessageTextToAstMarkdown.ts

Lines changed: 29 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,19 +28,22 @@ export const parseMessageTextToAstMarkdown = <
2828
message: TMessage,
2929
parseOptions: Options,
3030
autoTranslateOptions: AutoTranslateOptions,
31+
maxMessageParseSize: number,
3132
): MessageWithMdEnforced => {
3233
const msg = removePossibleNullMessageValues(message);
3334
const { showAutoTranslate, autoTranslateLanguage } = autoTranslateOptions;
3435
const translations = autoTranslateLanguage && isTranslatedMessage(msg) && msg.translations;
3536
const translated = showAutoTranslate(message);
3637

3738
const text = (translated && translations && translations[autoTranslateLanguage]) || msg.msg;
38-
3939
return {
4040
...msg,
41-
md: isE2EEMessage(message) || translated ? textToMessageToken(text, parseOptions) : (msg.md ?? textToMessageToken(text, parseOptions)),
41+
md:
42+
isE2EEMessage(message) || translated
43+
? textToMessageToken(text, parseOptions, maxMessageParseSize)
44+
: (msg.md ?? textToMessageToken(text, parseOptions, maxMessageParseSize)),
4245
...(msg.attachments && {
43-
attachments: parseMessageAttachments(msg.attachments, parseOptions, { autoTranslateLanguage, translated }),
46+
attachments: parseMessageAttachments(msg.attachments, parseOptions, { autoTranslateLanguage, translated }, maxMessageParseSize),
4447
}),
4548
};
4649
};
@@ -49,14 +52,15 @@ export const parseMessageAttachment = <T extends MessageAttachment>(
4952
attachment: T,
5053
parseOptions: Options,
5154
autoTranslateOptions: { autoTranslateLanguage?: string; translated: boolean },
55+
maxMessageParseSize: number,
5256
): T => {
5357
const { translated, autoTranslateLanguage } = autoTranslateOptions;
5458
if (!attachment.text) {
5559
return attachment;
5660
}
5761

5862
if (isQuoteAttachment(attachment) && attachment.attachments) {
59-
attachment.attachments = parseMessageAttachments(attachment.attachments, parseOptions, autoTranslateOptions);
63+
attachment.attachments = parseMessageAttachments(attachment.attachments, parseOptions, autoTranslateOptions, maxMessageParseSize);
6064
}
6165

6266
const text =
@@ -66,15 +70,18 @@ export const parseMessageAttachment = <T extends MessageAttachment>(
6670

6771
return {
6872
...attachment,
69-
md: translated ? textToMessageToken(text, parseOptions) : (attachment.md ?? textToMessageToken(text, parseOptions)),
73+
md: translated
74+
? textToMessageToken(text, parseOptions, maxMessageParseSize)
75+
: (attachment.md ?? textToMessageToken(text, parseOptions, maxMessageParseSize)),
7076
};
7177
};
7278

7379
export const parseMessageAttachments = <T extends MessageAttachment>(
7480
attachments: T[],
7581
parseOptions: Options,
7682
autoTranslateOptions: { autoTranslateLanguage?: string; translated: boolean },
77-
): T[] => attachments.map((attachment) => parseMessageAttachment(attachment, parseOptions, autoTranslateOptions));
83+
maxMessageParseSize: number,
84+
): T[] => attachments.map((attachment) => parseMessageAttachment(attachment, parseOptions, autoTranslateOptions, maxMessageParseSize));
7885

7986
const isNotNullOrUndefined = (value: unknown): boolean => value !== null && value !== undefined;
8087

@@ -105,17 +112,30 @@ export const removePossibleNullMessageValues = <TMessage extends IMessage = IMes
105112
...(isNotNullOrUndefined(reactions) && { reactions }),
106113
});
107114

108-
const textToMessageToken = (textOrRoot: string | Root, parseOptions: Options): Root => {
115+
const textToMessageToken = (textOrRoot: string | Root, parseOptions: Options, maxMessageParseSize: number): Root => {
109116
if (!textOrRoot) {
110117
return [];
111118
}
112119

113120
if (isParsedMessage(textOrRoot)) {
114121
return textOrRoot;
115122
}
116-
const parsedMessage = parse(textOrRoot, parseOptions);
123+
if (textOrRoot.length > maxMessageParseSize) {
124+
return [
125+
{
126+
type: 'PARAGRAPH',
127+
value: [
128+
{
129+
type: 'PLAIN_TEXT',
130+
value: textOrRoot,
131+
},
132+
],
133+
},
134+
];
135+
}
136+
const result = parse(textOrRoot, parseOptions);
117137

118-
const parsedMessageCleaned = parsedMessage[0].type !== 'LINE_BREAK' ? parsedMessage : (parsedMessage.slice(1) as Root);
138+
const parsedMessageCleaned = result[0].type !== 'LINE_BREAK' ? result : (result.slice(1) as Root);
119139

120140
return parsedMessageCleaned;
121141
};

apps/meteor/client/views/room/MessageList/hooks/useMessageBody.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import { useAutoLinkDomains } from './useAutoLinkDomains';
66
import { useMessageListAutoTranslate } from '../../../../components/message/list/MessageListContext';
77
import { parseMessageTextToAstMarkdown } from '../../../../lib/parseMessageTextToAstMarkdown';
88

9-
export const useMessageBody = (message: IMessage | undefined): string | Root => {
9+
export const useMessageBody = (message: IMessage | undefined, maxMessageParseSize: number): string | Root => {
1010
const autoTranslateOptions = useMessageListAutoTranslate();
1111
const customDomains = useAutoLinkDomains();
1212

@@ -20,8 +20,7 @@ export const useMessageBody = (message: IMessage | undefined): string | Root =>
2020
customDomains,
2121
emoticons: true,
2222
};
23-
24-
const messageWithMd = parseMessageTextToAstMarkdown(message, parseOptions, autoTranslateOptions);
23+
const messageWithMd = parseMessageTextToAstMarkdown(message, parseOptions, autoTranslateOptions, maxMessageParseSize);
2524

2625
return messageWithMd.md;
2726
}
@@ -39,5 +38,5 @@ export const useMessageBody = (message: IMessage | undefined): string | Root =>
3938
}
4039

4140
return '';
42-
}, [message, customDomains, autoTranslateOptions]);
41+
}, [message, customDomains, autoTranslateOptions, maxMessageParseSize]);
4342
};

0 commit comments

Comments
 (0)