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

feat: E2EE messages mentions #32510

Merged
merged 31 commits into from
Sep 20, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
1976fff
feat: E2EE messages mentions
hugocostadev May 28, 2024
24cdb06
Merge remote-tracking branch 'origin/develop' into feat/e2e-messages-…
hugocostadev May 28, 2024
1dafb56
adding E2E_Enabled_Mentions settings
hugocostadev May 28, 2024
5442f41
fix: setting description
hugocostadev Jun 3, 2024
f3656fc
test: adding mention tests
hugocostadev Jun 3, 2024
85a4786
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jun 3, 2024
d12a819
Create late-planes-sniff.md
hugocostadev Jun 3, 2024
e98ddaf
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jun 4, 2024
184d931
test: fix flaky keypress behavior
hugocostadev Jun 5, 2024
8c68d7d
fix changeset
hugocostadev Jun 12, 2024
b94db45
Merge remote-tracking branch 'origin/develop' into feat/e2e-messages-…
hugocostadev Jun 14, 2024
9f4c217
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jun 17, 2024
a97716a
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jun 18, 2024
cc5425f
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jun 19, 2024
ad187fa
fix: changeset
hugocostadev Jun 20, 2024
912b80e
fix: e2e test
hugocostadev Jun 20, 2024
701b5ab
fix: getting username
hugocostadev Jun 20, 2024
0bca0d1
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jun 21, 2024
66bc1dd
fix: ts check
hugocostadev Jun 21, 2024
5098368
Merge remote-tracking branch 'origin' into feat/e2e-messages-mentions
hugocostadev Jun 24, 2024
8d1cf4d
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jul 2, 2024
b961662
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jul 10, 2024
5b2267a
Merge remote-tracking branch 'origin/develop' into feat/e2e-messages-…
hugocostadev Jul 10, 2024
7b5b337
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jul 11, 2024
ea93b90
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jul 12, 2024
c8d67bf
Merge branch 'develop' into feat/e2e-messages-mentions
hugocostadev Jul 15, 2024
ad582e9
fix: isE2EEMessage helper usage
hugocostadev Jul 25, 2024
6e374c3
test: add user and channel test case
hugocostadev Jul 25, 2024
887d710
Merge remote-tracking branch 'origin/develop' into feat/e2e-messages-…
hugocostadev Jul 25, 2024
eed82a3
Merge remote-tracking branch 'origin/develop' into feat/e2e-messages-…
hugocostadev Aug 27, 2024
1eeff2d
Merge branch 'develop' into feat/e2e-messages-mentions
kodiakhq[bot] Sep 17, 2024
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
7 changes: 7 additions & 0 deletions .changeset/late-planes-sniff.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"@rocket.chat/meteor": minor
"@rocket.chat/core-typings": patch
"@rocket.chat/i18n": patch
---

Added a new setting to enable mentions in end to end encrypted channels
2 changes: 1 addition & 1 deletion apps/meteor/app/lib/server/methods/updateMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { hasPermissionAsync } from '../../../authorization/server/functions/hasP
import { settings } from '../../../settings/server';
import { updateMessage } from '../functions/updateMessage';

const allowedEditedFields = ['tshow', 'alias', 'attachments', 'avatar', 'emoji', 'msg', 'customFields', 'content'];
const allowedEditedFields = ['tshow', 'alias', 'attachments', 'avatar', 'emoji', 'msg', 'customFields', 'content', 'e2eMentions'];

export async function executeUpdateMessage(
uid: IUser['_id'],
Expand Down
20 changes: 15 additions & 5 deletions apps/meteor/app/mentions/server/Mentions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
* Mentions is a named function that will process Mentions
* @param {Object} message - The message object
*/
import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings';
import { isE2EEMessage, type IMessage, type IRoom, type IUser } from '@rocket.chat/core-typings';

import { type MentionsParserArgs, MentionsParser } from '../lib/MentionsParser';

Expand Down Expand Up @@ -43,8 +43,13 @@ export class MentionsServer extends MentionsParser {
});
}

async getUsersByMentions({ msg, rid, u: sender }: Pick<IMessage, 'msg' | 'rid' | 'u'>): Promise<IMessage['mentions']> {
const mentions = this.getUserMentions(msg);
async getUsersByMentions(message: IMessage): Promise<IMessage['mentions']> {
const { msg, rid, u: sender, e2eMentions }: Pick<IMessage, 'msg' | 'rid' | 'u' | 't' | 'e2eMentions'> = message;

const mentions =
isE2EEMessage(message) && e2eMentions?.e2eUserMentions && e2eMentions?.e2eUserMentions.length > 0
? e2eMentions?.e2eUserMentions
: this.getUserMentions(msg);
const mentionsAll: { _id: string; username: string }[] = [];
const userMentions = [];

Expand All @@ -67,8 +72,13 @@ export class MentionsServer extends MentionsParser {
return [...mentionsAll, ...(userMentions.length ? await this.getUsers(userMentions) : [])];
}

async getChannelbyMentions({ msg }: Pick<IMessage, 'msg'>) {
const channels = this.getChannelMentions(msg);
async getChannelbyMentions(message: IMessage) {
const { msg, e2eMentions }: Pick<IMessage, 'msg' | 't' | 'e2eMentions'> = message;

const channels =
isE2EEMessage(message) && e2eMentions?.e2eChannelMentions && e2eMentions?.e2eChannelMentions.length > 0
? e2eMentions?.e2eChannelMentions
: this.getChannelMentions(msg);
return this.getChannels(channels.map((c) => c.trim().substr(1)));
}

Expand Down
22 changes: 22 additions & 0 deletions apps/meteor/client/startup/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import { Tracker } from 'meteor/tracker';

import { E2EEState } from '../../app/e2e/client/E2EEState';
import { e2e } from '../../app/e2e/client/rocketchat.e2e';
import { MentionsParser } from '../../app/mentions/lib/MentionsParser';
import { ChatRoom } from '../../app/models/client';
import { settings } from '../../app/settings/client';
import { onClientBeforeSendMessage } from '../lib/onClientBeforeSendMessage';
Expand Down Expand Up @@ -88,6 +89,27 @@ Meteor.startup(() => {
return message;
}

const mentionsEnabled = settings.get<boolean>('E2E_Enabled_Mentions');

if (mentionsEnabled) {
const me = Meteor.user()?.username || '';
const pattern = settings.get('UTF8_User_Names_Validation');
const useRealName = settings.get('UI_Use_Real_Name');

const mentions = new MentionsParser({
pattern: () => pattern,
useRealName: () => useRealName,
hugocostadev marked this conversation as resolved.
Show resolved Hide resolved
me: () => me,
});

const e2eMentions: IMessage['e2eMentions'] = {
e2eUserMentions: mentions.getUserMentions(message.msg),
e2eChannelMentions: mentions.getChannelMentions(message.msg),
};

message.e2eMentions = e2eMentions;
}

// Should encrypt this message.
return e2eRoom.encryptMessage(message);
});
Expand Down
6 changes: 6 additions & 0 deletions apps/meteor/server/settings/e2e.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,10 @@ export const createE2ESettings = () =>
public: true,
enableQuery: { _id: 'E2E_Enable', value: true },
});

await this.add('E2E_Enabled_Mentions', false, {
type: 'boolean',
public: true,
enableQuery: { _id: 'E2E_Enable', value: true },
});
});
71 changes: 71 additions & 0 deletions apps/meteor/tests/e2e/e2e-encryption.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -133,11 +133,13 @@ test.describe.serial('e2e-encryption', () => {

test.beforeAll(async ({ api }) => {
expect((await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: true })).status()).toBe(200);
expect((await api.post('/settings/E2E_Enabled_Mentions', { value: true })).status()).toBe(200);
});

test.afterAll(async ({ api }) => {
expect((await api.post('/settings/E2E_Enable', { value: false })).status()).toBe(200);
expect((await api.post('/settings/E2E_Allow_Unencrypted_Messages', { value: false })).status()).toBe(200);
expect((await api.post('/settings/E2E_Enabled_Mentions', { value: false })).status()).toBe(200);
});

test('expect create a private channel encrypted and send an encrypted message', async ({ page }) => {
Expand Down Expand Up @@ -265,6 +267,75 @@ test.describe.serial('e2e-encryption', () => {
await expect(poHomeChannel.content.lastUserMessage.locator('.rcx-icon--name-key')).toBeVisible();
});

test('expect create a encrypted private channel and mention user', async ({ page }) => {
const channelName = faker.string.uuid();

await poHomeChannel.sidenav.createEncryptedChannel(channelName);

await expect(page).toHaveURL(`/group/${channelName}`);

await poHomeChannel.dismissToast();

await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible();

await poHomeChannel.content.sendMessage('hello @user1');

const userMention = await page.getByRole('button', {
name: 'user1',
});

await expect(userMention).toBeVisible();
});

test('expect create a encrypted private channel, mention a channel and navigate to it', async ({ page }) => {
hugocostadev marked this conversation as resolved.
Show resolved Hide resolved
const channelName = faker.string.uuid();

await poHomeChannel.sidenav.createEncryptedChannel(channelName);

await expect(page).toHaveURL(`/group/${channelName}`);

await poHomeChannel.dismissToast();

await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible();

await poHomeChannel.content.sendMessage('Are you in the #general channel?');

const channelMention = await page.getByRole('button', {
name: 'general',
});

await expect(channelMention).toBeVisible();

await channelMention.click();
hugocostadev marked this conversation as resolved.
Show resolved Hide resolved

await expect(page).toHaveURL(`/channel/general`);
});

test('expect create a encrypted private channel, mention a channel and user', async ({ page }) => {
const channelName = faker.string.uuid();

await poHomeChannel.sidenav.createEncryptedChannel(channelName);

await expect(page).toHaveURL(`/group/${channelName}`);

await poHomeChannel.dismissToast();

await expect(poHomeChannel.content.encryptedRoomHeaderIcon).toBeVisible();

await poHomeChannel.content.sendMessage('Are you in the #general channel, @user1 ?');

const channelMention = await page.getByRole('button', {
name: 'general',
});

const userMention = await page.getByRole('button', {
name: 'user1',
});

await expect(userMention).toBeVisible();
await expect(channelMention).toBeVisible();
});

test('should encrypted field be available on edit room', async ({ page }) => {
const channelName = faker.string.uuid();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ export class HomeContent {
await this.joinRoomIfNeeded();
await this.page.waitForSelector('[name="msg"]:not([disabled])');
await this.page.locator('[name="msg"]').fill(text);
await this.page.keyboard.press('Enter');
await this.page.getByLabel('Send').click();
}

async dispatchSlashCommand(text: string): Promise<void> {
Expand Down
1 change: 1 addition & 0 deletions packages/core-typings/src/IMessage/IMessage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,7 @@ export interface IMessage extends IRocketChatRecord {
tcount?: number;
t?: MessageTypesValues;
e2e?: 'pending' | 'done';
e2eMentions?: { e2eUserMentions?: string[]; e2eChannelMentions?: string[] };
otrAck?: string;

urls?: MessageUrl[];
Expand Down
2 changes: 2 additions & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -1805,6 +1805,8 @@
"E2E_Enabled": "E2E Enabled",
"E2E_Enabled_Default_DirectRooms": "Enable encryption for Direct Rooms by default",
"E2E_Enabled_Default_PrivateRooms": "Enable encryption for Private Rooms by default",
"E2E_Enabled_Mentions": "Mentions",
"E2E_Enabled_Mentions_Description": "Notify people, and highlight user, channel, and team mentions in encrypted content.",
"E2E_Enable_Encrypt_Files": "Encrypt files",
"E2E_Enable_Encrypt_Files_Description": "Encrypt files sent inside encrypted rooms. Check for possible conflicts in [file upload settings.](admin/settings/FileUpload)",
"E2E_Encryption_Password_Change": "Change Encryption Password",
Expand Down
Loading