Skip to content

Commit ee78069

Browse files
authored
fix(ui): mentions highlighting escaping username (#2362)
1 parent 8853481 commit ee78069

File tree

3 files changed

+128
-11
lines changed

3 files changed

+128
-11
lines changed

packages/stream_chat_flutter/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
## Upcoming
2+
3+
🐞 Fixed
4+
5+
- Fixed `.replaceMentions` not escaping special characters in the username.
6+
17
## 9.16.0
28

39
🐞 Fixed

packages/stream_chat_flutter/lib/src/utils/extensions.dart

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -386,18 +386,13 @@ extension MessageX on Message {
386386
for (final user in mentionedUsers.toSet()) {
387387
final userId = user.id;
388388
final userName = user.name;
389-
if (linkify) {
390-
messageTextToRender = messageTextToRender?.replaceAll(
391-
RegExp('@($userId|$userName)'),
392-
'[@$userName]($userId)',
393-
);
394-
} else {
395-
messageTextToRender = messageTextToRender?.replaceAll(
396-
RegExp('@($userId|$userName)'),
397-
'@$userName',
398-
);
399-
}
389+
390+
messageTextToRender = messageTextToRender?.replaceAll(
391+
RegExp('@(${RegExp.escape(userId)}|${RegExp.escape(userName)})'),
392+
linkify ? '[@$userName]($userId)' : '@$userName',
393+
);
400394
}
395+
401396
return copyWith(text: messageTextToRender);
402397
}
403398

packages/stream_chat_flutter/test/src/utils/extension_test.dart

Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,122 @@ void main() {
227227
},
228228
);
229229

230+
group('replaceMentions with special regex characters', () {
231+
test('should handle usernames with parentheses', () {
232+
final user = User(id: 'user1', name: 'Tester (X)');
233+
234+
final message = Message(
235+
text: 'Hello, @Tester (X)!',
236+
mentionedUsers: [user],
237+
);
238+
239+
final modifiedMessage = message.replaceMentions();
240+
241+
expect(modifiedMessage.text, equals('Hello, [@Tester (X)](user1)!'));
242+
});
243+
244+
test('should handle usernames with square brackets', () {
245+
final user = User(id: 'user1', name: 'User[123]');
246+
247+
final message = Message(
248+
text: 'Hello, @User[123]!',
249+
mentionedUsers: [user],
250+
);
251+
252+
final modifiedMessage = message.replaceMentions();
253+
254+
expect(modifiedMessage.text, equals('Hello, [@User[123]](user1)!'));
255+
});
256+
257+
test('should handle usernames with dots and asterisks', () {
258+
final user = User(id: 'user1', name: 'user.name*');
259+
260+
final message = Message(
261+
text: 'Hello, @user.name*!',
262+
mentionedUsers: [user],
263+
);
264+
265+
final modifiedMessage = message.replaceMentions();
266+
267+
expect(modifiedMessage.text, equals('Hello, [@user.name*](user1)!'));
268+
});
269+
270+
test('should handle usernames with plus and question marks', () {
271+
final user = User(id: 'user1', name: 'test+user?');
272+
273+
final message = Message(
274+
text: 'Hello, @test+user?!',
275+
mentionedUsers: [user],
276+
);
277+
278+
final modifiedMessage = message.replaceMentions();
279+
280+
expect(modifiedMessage.text, equals('Hello, [@test+user?](user1)!'));
281+
});
282+
283+
test('should handle usernames without linkify', () {
284+
final user = User(id: 'user1', name: 'Tester (X)');
285+
286+
final message = Message(
287+
text: 'Hello, @Tester (X)!',
288+
mentionedUsers: [user],
289+
);
290+
291+
final modifiedMessage = message.replaceMentions(linkify: false);
292+
293+
expect(modifiedMessage.text, equals('Hello, @Tester (X)!'));
294+
});
295+
296+
test('should not replace partial matches', () {
297+
final user = User(id: 'user1', name: 'Test (X)');
298+
299+
final message = Message(
300+
text: 'Hello, @Test (X) and @Test (Y)!',
301+
mentionedUsers: [user],
302+
);
303+
304+
final modifiedMessage = message.replaceMentions();
305+
306+
expect(
307+
modifiedMessage.text,
308+
equals('Hello, [@Test (X)](user1) and @Test (Y)!'),
309+
);
310+
});
311+
312+
test('should handle userIds with special characters', () {
313+
final user = User(id: 'user.id+123', name: 'TestUser');
314+
315+
final message = Message(
316+
text: 'Hello, @user.id+123!',
317+
mentionedUsers: [user],
318+
);
319+
320+
final modifiedMessage = message.replaceMentions();
321+
322+
expect(
323+
modifiedMessage.text,
324+
equals('Hello, [@TestUser](user.id+123)!'),
325+
);
326+
});
327+
328+
test('should handle both userId and userName with special characters',
329+
() {
330+
final user = User(id: 'user[123]', name: 'Test (X)');
331+
332+
final message = Message(
333+
text: 'Hello, @user[123] and @Test (X)!',
334+
mentionedUsers: [user],
335+
);
336+
337+
final modifiedMessage = message.replaceMentions();
338+
339+
expect(
340+
modifiedMessage.text,
341+
equals('Hello, [@Test (X)](user[123]) and [@Test (X)](user[123])!'),
342+
);
343+
});
344+
});
345+
230346
test('replaceMentionsWithId should replace user names with IDs', () {
231347
final user1 = User(id: 'user1', name: 'Alice');
232348
final user2 = User(id: 'user2', name: 'Bob');

0 commit comments

Comments
 (0)