Skip to content

Commit

Permalink
feat: E2EE room setup header (#32446)
Browse files Browse the repository at this point in the history
Co-authored-by: gabriellsh <[email protected]>
Co-authored-by: Hugo Costa <[email protected]>
  • Loading branch information
3 people authored Jun 17, 2024
1 parent 465c8ed commit 2ef71e8
Show file tree
Hide file tree
Showing 8 changed files with 121 additions and 13 deletions.
6 changes: 6 additions & 0 deletions .changeset/gold-flowers-shake.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'@rocket.chat/i18n': minor
'@rocket.chat/meteor': minor
---

Added E2EE room setup header, with just limited functionality and room actions.
2 changes: 2 additions & 0 deletions apps/meteor/client/ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,5 @@ export const quickActionHooks = [
useCloseChatQuickAction,
useOnHoldChatQuickAction,
] satisfies (() => QuickActionsActionConfig | undefined)[];

export const roomActionHooksForE2EESetup = [useChannelSettingsRoomAction, useMembersListRoomAction, useE2EERoomAction];
24 changes: 16 additions & 8 deletions apps/meteor/client/views/room/Header/Header.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import type { IRoom } from '@rocket.chat/core-typings';
import { isVoipRoom } from '@rocket.chat/core-typings';
import { isDirectMessageRoom, isVoipRoom } from '@rocket.chat/core-typings';
import { HeaderToolbar } from '@rocket.chat/ui-client';
import { useLayout } from '@rocket.chat/ui-contexts';
import { useLayout, useSetting } from '@rocket.chat/ui-contexts';
import type { ReactElement } from 'react';
import React, { lazy, memo, useMemo } from 'react';

import SidebarToggler from '../../../components/SidebarToggler';

const DirectRoomHeader = lazy(() => import('./DirectRoomHeader'));
const OmnichannelRoomHeader = lazy(() => import('./Omnichannel/OmnichannelRoomHeader'));
const VoipRoomHeader = lazy(() => import('./Omnichannel/VoipRoomHeader'));
const RoomHeaderE2EESetup = lazy(() => import('./RoomHeaderE2EESetup'));
const DirectRoomHeader = lazy(() => import('./DirectRoomHeader'));
const RoomHeader = lazy(() => import('./RoomHeader'));

type HeaderProps<T> = {
Expand All @@ -18,6 +19,9 @@ type HeaderProps<T> = {

const Header = ({ room }: HeaderProps<IRoom>): ReactElement | null => {
const { isMobile, isEmbedded, showTopNavbarEmbeddedLayout } = useLayout();
const encrypted = Boolean(room.encrypted);
const unencryptedMessagesAllowed = useSetting<boolean>('E2E_Allow_Unencrypted_Messages');
const shouldDisplayE2EESetup = encrypted && !unencryptedMessagesAllowed;

const slots = useMemo(
() => ({
Expand All @@ -34,10 +38,6 @@ const Header = ({ room }: HeaderProps<IRoom>): ReactElement | null => {
return null;
}

if (room.t === 'd' && (room.uids?.length ?? 0) < 3) {
return <DirectRoomHeader slots={slots} room={room} />;
}

if (room.t === 'l') {
return <OmnichannelRoomHeader slots={slots} />;
}
Expand All @@ -46,7 +46,15 @@ const Header = ({ room }: HeaderProps<IRoom>): ReactElement | null => {
return <VoipRoomHeader slots={slots} room={room} />;
}

return <RoomHeader slots={slots} room={room} topic={room.topic} />;
if (shouldDisplayE2EESetup) {
return <RoomHeaderE2EESetup room={room} topic={room.topic} slots={slots} />;
}

if (isDirectMessageRoom(room) && (room.uids?.length ?? 0) < 3) {
return <DirectRoomHeader slots={slots} room={room} />;
}

return <RoomHeader room={room} topic={room.topic} slots={slots} />;
};

export default memo(Header);
5 changes: 3 additions & 2 deletions apps/meteor/client/views/room/Header/RoomHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ export type RoomHeaderProps = {
pos?: unknown;
};
};
roomToolbox?: JSX.Element;
};

const RoomHeader = ({ room, topic = '', slots = {} }: RoomHeaderProps) => {
const RoomHeader = ({ room, topic = '', slots = {}, roomToolbox }: RoomHeaderProps) => {
const t = useTranslation();

return (
Expand Down Expand Up @@ -65,7 +66,7 @@ const RoomHeader = ({ room, topic = '', slots = {} }: RoomHeaderProps) => {
<Suspense fallback={null}>
<HeaderToolbar aria-label={t('Toolbox_room_actions')}>
{slots?.toolbox?.pre}
{slots?.toolbox?.content || <RoomToolbox />}
{slots?.toolbox?.content || roomToolbox || <RoomToolbox />}
{slots?.toolbox?.pos}
</HeaderToolbar>
</Suspense>
Expand Down
29 changes: 29 additions & 0 deletions apps/meteor/client/views/room/Header/RoomHeaderE2EESetup.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { isDirectMessageRoom } from '@rocket.chat/core-typings';
import React, { lazy } from 'react';

import { E2EEState } from '../../../../app/e2e/client/E2EEState';
import { E2ERoomState } from '../../../../app/e2e/client/E2ERoomState';
import { useE2EERoomState } from '../hooks/useE2EERoomState';
import { useE2EEState } from '../hooks/useE2EEState';
import DirectRoomHeader from './DirectRoomHeader';
import RoomHeader from './RoomHeader';
import type { RoomHeaderProps } from './RoomHeader';

const RoomToolboxE2EESetup = lazy(() => import('./RoomToolbox/RoomToolboxE2EESetup'));

const RoomHeaderE2EESetup = ({ room, topic = '', slots = {} }: RoomHeaderProps) => {
const e2eeState = useE2EEState();
const e2eRoomState = useE2EERoomState(room._id);

if (e2eeState === E2EEState.SAVE_PASSWORD || e2eeState === E2EEState.ENTER_PASSWORD || e2eRoomState === E2ERoomState.WAITING_KEYS) {
return <RoomHeader room={room} topic={topic} slots={slots} roomToolbox={<RoomToolboxE2EESetup />} />;
}

if (isDirectMessageRoom(room) && (room.uids?.length ?? 0) < 3) {
return <DirectRoomHeader slots={slots} room={room} />;
}

return <RoomHeader room={room} topic={topic} slots={slots} />;
};

export default RoomHeaderE2EESetup;
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { useStableArray } from '@rocket.chat/fuselage-hooks';
import { HeaderToolbarAction } from '@rocket.chat/ui-client';
import { useTranslation } from '@rocket.chat/ui-contexts';
import React from 'react';

import { roomActionHooksForE2EESetup } from '../../../../ui';
import type { RoomToolboxActionConfig } from '../../contexts/RoomToolboxContext';
import { useRoomToolbox } from '../../contexts/RoomToolboxContext';

const RoomToolboxE2EESetup = () => {
const t = useTranslation();
const toolbox = useRoomToolbox();

const { tab } = toolbox;

const actions = useStableArray(
roomActionHooksForE2EESetup
.map((roomActionHook) => roomActionHook())
.filter((roomAction): roomAction is RoomToolboxActionConfig => !!roomAction),
);

return (
<>
{actions.map(({ id, icon, title, action, disabled, tooltip }, index) => (
<HeaderToolbarAction
key={id}
index={index}
id={id}
icon={icon}
title={t(title)}
pressed={id === tab?.id}
action={action ?? (() => toolbox.openTab(id))}
disabled={disabled}
tooltip={tooltip}
/>
))}
</>
);
};

export default RoomToolboxE2EESetup;
23 changes: 20 additions & 3 deletions apps/meteor/tests/e2e/e2e-encryption.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -429,11 +429,17 @@ test.describe.serial('e2ee room setup', () => {

await poHomeChannel.dismissToast();

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

await page.locator('role=button[name="Save E2EE password"]').waitFor();
await expect(page.locator('role=button[name="Save E2EE password"]')).toBeVisible();

await poHomeChannel.tabs.btnE2EERoomSetupDisableE2E.waitFor();
await expect(poHomeChannel.tabs.btnE2EERoomSetupDisableE2E).toBeVisible();
await expect(poHomeChannel.tabs.btnTabMembers).toBeVisible();
await expect(poHomeChannel.tabs.btnRoomInfo).toBeVisible();

await expect(poHomeChannel.content.inputMessage).not.toBeVisible();

await page.locator('role=button[name="Save E2EE password"]').click();
Expand Down Expand Up @@ -477,11 +483,17 @@ test.describe.serial('e2ee room setup', () => {

await poHomeChannel.dismissToast();

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

await page.locator('role=button[name="Enter your E2E password"]').waitFor();

await expect(page.locator('role=banner >> text="Enter your E2E password"')).toBeVisible();

await poHomeChannel.tabs.btnE2EERoomSetupDisableE2E.waitFor();
await expect(poHomeChannel.tabs.btnE2EERoomSetupDisableE2E).toBeVisible();
await expect(poHomeChannel.tabs.btnTabMembers).toBeVisible();
await expect(poHomeChannel.tabs.btnRoomInfo).toBeVisible();

await expect(poHomeChannel.content.inputMessage).not.toBeVisible();

await page.locator('role=button[name="Enter your E2E password"]').click();
Expand Down Expand Up @@ -518,7 +530,7 @@ test.describe.serial('e2ee room setup', () => {

await poHomeChannel.dismissToast();

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

await poHomeChannel.content.sendMessage('hello world');

Expand Down Expand Up @@ -551,5 +563,10 @@ test.describe.serial('e2ee room setup', () => {

await expect(poHomeChannel.content.inputMessage).not.toBeVisible();
await expect(page.locator('.rcx-states__title')).toContainText('Check back later');

await poHomeChannel.tabs.btnE2EERoomSetupDisableE2E.waitFor();
await expect(poHomeChannel.tabs.btnE2EERoomSetupDisableE2E).toBeVisible();
await expect(poHomeChannel.tabs.btnTabMembers).toBeVisible();
await expect(poHomeChannel.tabs.btnRoomInfo).toBeVisible();
});
});
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 @@ -44,6 +44,10 @@ export class HomeFlextab {
return this.page.locator('role=menuitem[name="Notifications Preferences"]');
}

get btnE2EERoomSetupDisableE2E(): Locator {
return this.page.locator('[data-qa-id=ToolBoxAction-key]');
}

get btnDisableE2E(): Locator {
return this.page.locator('role=menuitem[name="Disable E2E"]');
}
Expand Down

0 comments on commit 2ef71e8

Please sign in to comment.