Skip to content

Commit

Permalink
feat: Disable OTR messages selection when exporting messages (#34220)
Browse files Browse the repository at this point in the history
Co-authored-by: gabriellsh <[email protected]>
  • Loading branch information
dougfabris and gabriellsh authored Dec 20, 2024
1 parent 24170d9 commit ff04c19
Show file tree
Hide file tree
Showing 10 changed files with 104 additions and 8 deletions.
5 changes: 5 additions & 0 deletions .changeset/pretty-islands-wink.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@rocket.chat/meteor': minor
---

Disables OTR messages selection when exporting messages
Original file line number Diff line number Diff line change
Expand Up @@ -55,8 +55,10 @@ const RoomMessage = ({
const { openUserCard, triggerProps } = useUserCard();

const selecting = useIsSelecting();
const isOTRMessage = message.t === 'otr' || message.t === 'otr-ack';

const toggleSelected = useToggleSelect(message._id);
const selected = useIsSelectedMessage(message._id);
const selected = useIsSelectedMessage(message._id, isOTRMessage);

useCountSelected();

Expand All @@ -70,7 +72,7 @@ const RoomMessage = ({
aria-roledescription={t('message')}
tabIndex={0}
aria-labelledby={`${message._id}-displayName ${message._id}-time ${message._id}-content ${message._id}-read-status`}
onClick={selecting ? toggleSelected : undefined}
onClick={selecting && !isOTRMessage ? toggleSelected : undefined}
isSelected={selected}
isEditing={editing}
isPending={message.temp}
Expand Down Expand Up @@ -99,7 +101,7 @@ const RoomMessage = ({
{...triggerProps}
/>
)}
{selecting && <CheckBox checked={selected} onChange={toggleSelected} />}
{selecting && <CheckBox disabled={isOTRMessage} checked={selected} onChange={toggleSelected} />}
{sequential && <StatusIndicators message={message} />}
</MessageLeftContainer>
<MessageContainer>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,10 @@ const ThreadMessagePreview = ({ message, showUserAvatar, sequential, ...props }:
const { t } = useTranslation();

const isSelecting = useIsSelecting();
const isOTRMessage = message.t === 'otr' || message.t === 'otr-ack';

const toggleSelected = useToggleSelect(message._id);
const isSelected = useIsSelectedMessage(message._id);
const isSelected = useIsSelectedMessage(message._id, isOTRMessage);
useCountSelected();

const messageType = parentMessage.isSuccess ? MessageTypes.getType(parentMessage.data) : null;
Expand All @@ -65,6 +67,10 @@ const ThreadMessagePreview = ({ message, showUserAvatar, sequential, ...props }:
return goToThread({ rid: message.rid, tmid: message.tmid, msg: message._id });
}

if (isOTRMessage) {
return;
}

return toggleSelected();
};

Expand Down Expand Up @@ -117,7 +123,7 @@ const ThreadMessagePreview = ({ message, showUserAvatar, sequential, ...props }:
size='x18'
/>
)}
{isSelecting && <CheckBox checked={isSelected} onChange={toggleSelected} />}
{isSelecting && <CheckBox disabled={isOTRMessage} checked={isSelected} onChange={toggleSelected} />}
</ThreadMessageLeftContainer>
<ThreadMessageContainer>
<ThreadMessageBody>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export const SelectedMessageContext = createContext({
selectedMessageStore,
} as SelectMessageContextValue);

export const useIsSelectedMessage = (mid: string): boolean => {
export const useIsSelectedMessage = (mid: string, omit?: boolean): boolean => {
const { selectedMessageStore } = useContext(SelectedMessageContext);

const subscribe = useCallback(
Expand All @@ -24,14 +24,14 @@ export const useIsSelectedMessage = (mid: string): boolean => {
const isSelected = useSyncExternalStore(subscribe, getSnapshot);

useEffect(() => {
if (isSelected) {
if (isSelected || omit) {
return;
}

selectedMessageStore.addAvailableMessage(mid);

return () => selectedMessageStore.removeAvailableMessage(mid);
}, [mid, selectedMessageStore, isSelected]);
}, [mid, selectedMessageStore, isSelected, omit]);

return isSelected;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,13 @@ const ExportMessages = () => {
<ContextualbarScrollableContent>
<form ref={formFocus} tabIndex={-1} aria-labelledby={`${formId}-title`} id={formId} onSubmit={handleSubmit(handleExport)}>
<FieldGroup>
{room.createdOTR && (
<Field>
<Callout role='alert' type='warning'>
{t('OTR_messages_cannot_be_exported')}
</Callout>
</Field>
)}
<Field>
<FieldLabel htmlFor={methodField}>{t('Method')}</FieldLabel>
<FieldRow>
Expand Down
46 changes: 46 additions & 0 deletions apps/meteor/tests/e2e/otr.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Users } from './fixtures/userStates';
import { HomeChannel } from './page-objects';
import { createDirectMessage } from './utils';
import { test, expect } from './utils/test';

test.use({ storageState: Users.admin.state });

test.describe.serial('OTR', () => {
let poHomeChannel: HomeChannel;

test.beforeEach(async ({ page, api }) => {
await createDirectMessage(api);
poHomeChannel = new HomeChannel(page);

await page.goto('/home');
});

test('should not allow export OTR messages', async ({ browser }) => {
const user1Page = await browser.newPage({ storageState: Users.user1.state });
const user1Channel = new HomeChannel(user1Page);

await test.step('log in user1', async () => {
await user1Page.goto(`/direct/${Users.admin.data.username}`);
await user1Channel.content.waitForChannel();
});

await test.step('invite OTR with user1', async () => {
await poHomeChannel.sidenav.openChat(Users.user1.data.username);
await poHomeChannel.tabs.kebab.click({ force: true });
await poHomeChannel.tabs.btnEnableOTR.click({ force: true });
await poHomeChannel.tabs.otr.btnStartOTR.click();
});

await test.step('accept handshake with user1', async () => {
await user1Channel.tabs.otr.btnAcceptOTR.click();
});

await poHomeChannel.content.sendMessage('hello OTR');
await poHomeChannel.tabs.kebab.click({ force: true });
await poHomeChannel.tabs.btnExportMessages.click();
await poHomeChannel.content.getMessageByText('hello OTR').click();
await expect(poHomeChannel.content.btnClearSelection).toBeDisabled();

await user1Page.close();
});
});
4 changes: 4 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/home-content.ts
Original file line number Diff line number Diff line change
Expand Up @@ -417,4 +417,8 @@ export class HomeContent {
await this.page.getByRole('dialog').getByRole('textbox', { name: 'Message' }).fill(text);
await this.page.getByRole('dialog').getByRole('button', { name: 'Send', exact: true }).click();
}

get btnClearSelection() {
return this.page.getByRole('button', { name: 'Clear selection' });
}
}
21 changes: 21 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/home-flextab-otr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Locator, Page } from '@playwright/test';

export class HomeFlextabOtr {
private readonly page: Page;

constructor(page: Page) {
this.page = page;
}

get otrDialog(): Locator {
return this.page.getByRole('dialog', { name: 'OTR' });
}

get btnStartOTR(): Locator {
return this.otrDialog.getByRole('button', { name: 'Start OTR' });
}

get btnAcceptOTR(): Locator {
return this.page.getByRole('dialog').getByRole('button', { name: 'Yes' });
}
}
4 changes: 4 additions & 0 deletions apps/meteor/tests/e2e/page-objects/fragments/home-flextab.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { HomeFlextabChannels } from './home-flextab-channels';
import { HomeFlextabExportMessages } from './home-flextab-exportMessages';
import { HomeFlextabMembers } from './home-flextab-members';
import { HomeFlextabNotificationPreferences } from './home-flextab-notificationPreferences';
import { HomeFlextabOtr } from './home-flextab-otr';
import { HomeFlextabRoom } from './home-flextab-room';

export class HomeFlextab {
Expand All @@ -17,6 +18,8 @@ export class HomeFlextab {

readonly notificationPreferences: HomeFlextabNotificationPreferences;

readonly otr: HomeFlextabOtr;

readonly exportMessages: HomeFlextabExportMessages;

constructor(page: Page) {
Expand All @@ -25,6 +28,7 @@ export class HomeFlextab {
this.room = new HomeFlextabRoom(page);
this.channels = new HomeFlextabChannels(page);
this.notificationPreferences = new HomeFlextabNotificationPreferences(page);
this.otr = new HomeFlextabOtr(page);
this.exportMessages = new HomeFlextabExportMessages(page);
}

Expand Down
1 change: 1 addition & 0 deletions packages/i18n/src/locales/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -4231,6 +4231,7 @@
"others": "others",
"Others": "Others",
"OTR": "OTR",
"OTR_messages_cannot_be_exported": "OTR messages cannot be exported",
"OTR_unavailable_for_federation": "OTR is unavailable for federated rooms",
"OTR_Description": "Off-the-record chats are secure, private and disappear once ended.",
"OTR_Chat_Declined_Title": "OTR Chat invite Declined",
Expand Down

0 comments on commit ff04c19

Please sign in to comment.