Skip to content

Commit 5906dac

Browse files
ergot-rpdougfabris
andauthored
fix(a11y): Added inline error to Enter E2EE password modal (#36350)
Co-authored-by: Douglas Fabris <devfabris@gmail.com>
1 parent 8a25819 commit 5906dac

9 files changed

Lines changed: 59 additions & 41 deletions

File tree

apps/meteor/client/lib/e2ee/rocketchat.e2e.ts

Lines changed: 36 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -521,29 +521,36 @@ class E2E extends Emitter {
521521
return randomPassword;
522522
}
523523

524-
openEnterE2EEPasswordModal(onEnterE2EEPassword?: (password: string) => void) {
524+
openEnterE2EEPasswordModal(onEnterE2EEPassword: (password: string) => Promise<void>) {
525+
const close = () => {
526+
this.closeAlert();
527+
imperativeModal.close();
528+
};
525529
imperativeModal.open({
526530
component: EnterE2EPasswordModal,
527531
props: {
528-
onClose: imperativeModal.close,
532+
onClose: close,
529533
onCancel: () => {
530534
failedToDecodeKey = false;
531535
dispatchToastMessage({ type: 'info', message: t('End_To_End_Encryption_Not_Enabled') });
532-
this.closeAlert();
533-
imperativeModal.close();
536+
close();
534537
},
535-
onConfirm: (password) => {
536-
onEnterE2EEPassword?.(password);
537-
this.closeAlert();
538-
imperativeModal.close();
538+
onConfirm: async (password) => {
539+
await onEnterE2EEPassword(password);
540+
dispatchToastMessage({ type: 'success', message: t('E2E_encryption_enabled') });
541+
close();
539542
},
540543
},
541544
});
542545
}
543546

544-
async requestPasswordAlert(): Promise<string> {
547+
async requestPasswordAlert(validatePassword: (password: string) => Promise<void>): Promise<void> {
545548
return new Promise((resolve) => {
546-
const showModal = () => this.openEnterE2EEPasswordModal((password) => resolve(password));
549+
const showModal = () =>
550+
this.openEnterE2EEPasswordModal(async (password) => {
551+
await validatePassword(password);
552+
resolve();
553+
});
547554

548555
const showAlert = () => {
549556
this.openAlert({
@@ -566,48 +573,47 @@ class E2E extends Emitter {
566573
});
567574
}
568575

569-
async requestPasswordModal(): Promise<string> {
570-
return new Promise((resolve) => this.openEnterE2EEPasswordModal((password) => resolve(password)));
576+
async requestPasswordModal(validatePassword: (password: string) => Promise<void>): Promise<void> {
577+
return new Promise((resolve) => {
578+
this.openEnterE2EEPasswordModal(async (password) => {
579+
await validatePassword(password);
580+
resolve();
581+
});
582+
});
571583
}
572584

573585
async decodePrivateKeyFlow() {
574-
const password = await this.requestPasswordModal();
575-
576586
if (!this.db_private_key) {
577587
return;
578588
}
579589

580590
try {
581-
const privateKey = await this.keychain.decryptKey(this.db_private_key, password);
591+
let privateKey: string | undefined;
592+
await this.requestPasswordModal(async (password) => {
593+
privateKey = await this.keychain.decryptKey(this.db_private_key as string, password);
594+
});
582595

583596
if (this.db_public_key && privateKey) {
584597
await this.loadKeys({ public_key: this.db_public_key, private_key: privateKey });
585-
this.setState('READY');
586598
} else {
587599
await this.createAndLoadKeys();
588-
this.setState('READY');
589600
}
601+
this.setState('READY');
602+
590603
dispatchToastMessage({ type: 'success', message: t('E2E_encryption_enabled') });
591604
} catch (error) {
592605
this.setState('ENTER_PASSWORD');
593-
dispatchToastMessage({ type: 'error', message: t('Your_E2EE_password_is_incorrect') });
594606
dispatchToastMessage({ type: 'info', message: t('End_To_End_Encryption_Not_Enabled') });
595-
throw new Error('E2E -> Error decrypting private key', { cause: error });
607+
throw new Error('E2E -> Error loading keys', { cause: error });
596608
}
597609
}
598610

599611
async decodePrivateKey(privateKey: string): Promise<string> {
600-
// const span = log.span('decodePrivateKey');
601-
const password = await this.requestPasswordAlert();
602-
try {
603-
const privKey = await this.keychain.decryptKey(privateKey, password);
604-
return privKey;
605-
} catch (error) {
606-
this.setState('ENTER_PASSWORD');
607-
dispatchToastMessage({ type: 'error', message: t('Your_E2EE_password_is_incorrect') });
608-
dispatchToastMessage({ type: 'info', message: t('End_To_End_Encryption_Not_Enabled') });
609-
throw new Error('E2E -> Error decrypting private key', { cause: error });
610-
}
612+
let decryptedKey: string | undefined;
613+
await this.requestPasswordAlert(async (password) => {
614+
decryptedKey = await this.keychain.decryptKey(privateKey, password);
615+
});
616+
return decryptedKey as string;
611617
}
612618

613619
async decryptFileContent(file: IUploadWithUser): Promise<IUploadWithUser> {

apps/meteor/client/views/e2e/EnterE2EPasswordModal/EnterE2EPasswordModal.tsx

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,33 +1,51 @@
11
import { Box, PasswordInput, Field, FieldGroup, FieldRow, FieldError, FieldLink } from '@rocket.chat/fuselage';
22
import { GenericModal } from '@rocket.chat/ui-client';
3+
import { useToastMessageDispatch } from '@rocket.chat/ui-contexts';
34
import { useEffect, useId, useState } from 'react';
45
import { Controller, useForm } from 'react-hook-form';
56
import { useTranslation } from 'react-i18next';
67

78
import { useResetE2EPasswordMutation } from '../../hooks/useResetE2EPasswordMutation';
89

10+
const isInvalidE2EEPasswordError = (error: unknown): boolean => error instanceof DOMException && error.name === 'OperationError';
11+
912
type EnterE2EPasswordModalProps = {
10-
onConfirm: (password: string) => void;
13+
onConfirm: (password: string) => void | Promise<void>;
1114
onClose: () => void;
1215
onCancel: () => void;
1316
};
1417

1518
const EnterE2EPasswordModal = ({ onConfirm, onClose, onCancel }: EnterE2EPasswordModalProps) => {
1619
const { t } = useTranslation();
20+
const dispatchToastMessage = useToastMessageDispatch();
1721
const [confirmResetPassword, setConfirmResetPassword] = useState(false);
1822
const resetE2EPassword = useResetE2EPasswordMutation({ options: { onSettled: () => onClose() } });
1923

2024
const {
2125
handleSubmit,
2226
control,
2327
setFocus,
28+
setError,
2429
formState: { errors },
2530
} = useForm({
2631
defaultValues: {
2732
password: '',
2833
},
2934
});
3035

36+
const handleValidatePassword = handleSubmit(async ({ password }) => {
37+
try {
38+
await onConfirm(password);
39+
} catch (error) {
40+
if (isInvalidE2EEPasswordError(error)) {
41+
setError('password', { message: t('Incorrect_encryption_password') });
42+
return;
43+
}
44+
dispatchToastMessage({ type: 'error', message: error });
45+
onClose();
46+
}
47+
});
48+
3149
const passwordInputId = useId();
3250

3351
useEffect(() => {
@@ -52,7 +70,7 @@ const EnterE2EPasswordModal = ({ onConfirm, onClose, onCancel }: EnterE2EPasswor
5270

5371
return (
5472
<GenericModal
55-
wrapperFunction={(props) => <Box is='form' onSubmit={handleSubmit(({ password }) => onConfirm(password))} {...props} />}
73+
wrapperFunction={(props) => <Box is='form' onSubmit={handleValidatePassword} {...props} />}
5674
variant='warning'
5775
title={t('Enter_E2E_password')}
5876
icon='warning'

apps/meteor/tests/e2e/e2e-encryption/e2ee-passphrase-management.spec.ts

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -247,6 +247,7 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => {
247247
});
248248

249249
test('expect enter password state on encrypted room', async ({ page }) => {
250+
const enterE2EEPasswordModal = new EnterE2EEPasswordModal(page);
250251
await page.goto('/home');
251252

252253
// Logout to remove e2ee keys
@@ -276,9 +277,7 @@ test.describe.serial('E2EE Passphrase Management - Room Setup States', () => {
276277

277278
await poHomeChannel.btnRoomEnterE2EEPassword.click();
278279

279-
await page.locator('#modal-root input').fill(e2eePassword);
280-
281-
await page.locator('#modal-root .rcx-button--primary').click();
280+
await enterE2EEPasswordModal.enterPassword(e2eePassword);
282281

283282
await expect(poHomeChannel.bannerEnterE2EEPassword).not.toBeVisible();
284283

packages/i18n/src/locales/en.i18n.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2668,6 +2668,7 @@
26682668
"Incoming_voice_call": "Incoming voice call",
26692669
"Incoming_voice_call_canceled_suddenly": "An Incoming Voice Call was canceled suddenly.",
26702670
"Incoming_voice_call_canceled_user_not_registered": "An Incoming Voice Call was canceled due to an unexpected error.",
2671+
"Incorrect_encryption_password": "Incorrect encryption password",
26712672
"Industry": "Industry",
26722673
"Info": "Info",
26732674
"Information_to_keep_top_of_mind": "Information to keep top-of-mind",
@@ -6034,7 +6035,6 @@
60346035
"You_will_not_be_able_to_recover_file": "You will not be able to recover this file!",
60356036
"You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "You won't receive email notifications because you have not verified your email.",
60366037
"Your_E2EE_password_is": "Your E2EE password is:",
6037-
"Your_E2EE_password_is_incorrect": "Your E2EE password is incorrect",
60386038
"Your_TOTP_has_been_reset": "Your Two Factor TOTP has been reset.",
60396039
"Your_e2e_key_has_been_reset": "Your e2e key has been reset.",
60406040
"Your_email_address_has_changed": "Your email address has been changed.",

packages/i18n/src/locales/nb.i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5918,7 +5918,6 @@
59185918
"You_will_not_be_able_to_recover_file": "Du vil ikke kunne gjenopprette denne filen!",
59195919
"You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "Du mottar ikke e-postvarsler fordi du ikke har bekreftet e-posten din.",
59205920
"Your_E2EE_password_is": "Ditt E2EE-passord er:",
5921-
"Your_E2EE_password_is_incorrect": "E2EE-passordet ditt er feil",
59225921
"Your_TOTP_has_been_reset": "To-faktor TOTP har blitt tilbakestilt.",
59235922
"Your_e2e_key_has_been_reset": "E2e-nøkkelen din har blitt tilbakestilt.",
59245923
"Your_email_address_has_changed": "E-postadressen din har blitt endret.",

packages/i18n/src/locales/nn.i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5205,7 +5205,6 @@
52055205
"You_will_not_be_able_to_recover_file": "Du vil ikke kunne gjenopprette denne filen!",
52065206
"You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "Du mottar ikke e-postvarsler fordi du ikke har bekreftet e-posten din.",
52075207
"Your_E2EE_password_is": "Ditt E2EE-passord er:",
5208-
"Your_E2EE_password_is_incorrect": "E2EE-passordet ditt er feil",
52095208
"Your_email_has_been_queued_for_sending": "E-posten din har vært i kø for å sende",
52105209
"Your_entry_has_been_deleted": "Oppføringen din er slettet.",
52115210
"Your_file_has_been_deleted": "Filen din er slettet.",

packages/i18n/src/locales/pt-BR.i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6018,7 +6018,6 @@
60186018
"You_will_not_be_able_to_recover_file": "Não será possível recuperar este arquivo!",
60196019
"You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "Você não receberá notificações de e-mail, porque você não confirmou seu e-mail.",
60206020
"Your_E2EE_password_is": "Sua senha do E2EE é:",
6021-
"Your_E2EE_password_is_incorrect": "Sua senha do E2EE está incorreta",
60226021
"Your_TOTP_has_been_reset": "Seu TOTP de dois fatores foi redefinido.",
60236022
"Your_e2e_key_has_been_reset": "Sua chave e2e foi redefinida.",
60246023
"Your_email_address_has_changed": "Seu endereço de e-mail foi alterado.",

packages/i18n/src/locales/sv.i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5663,7 +5663,6 @@
56635663
"You_will_not_be_able_to_recover_file": "Du kommer inte att kunna återskapa den här filen!",
56645664
"You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "Du kommer inte att få e-postmeddelanden eftersom du inte har verifierat din e-post.",
56655665
"Your_E2EE_password_is": "Ditt E2EE-lösenord är:",
5666-
"Your_E2EE_password_is_incorrect": "Ditt E2EE-lösenord är felaktigt",
56675666
"Your_TOTP_has_been_reset": "Ditt tidsbaserade engångslösenord för tvåfaktorsautentisering har återställts.",
56685667
"Your_e2e_key_has_been_reset": "Din E2E-nyckel har återställts.",
56695668
"Your_email_address_has_changed": "Din e-postadress har ändrats.",

packages/i18n/src/locales/zh.i18n.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5909,7 +5909,6 @@
59095909
"You_will_not_be_able_to_recover_file": "您将不能恢复此文件!",
59105910
"You_wont_receive_email_notifications_because_you_have_not_verified_your_email": "您将不会收到电子邮件通知,因为您还没有验证您的电子邮箱地址。",
59115911
"Your_E2EE_password_is": "你的 E2EE 密码是:",
5912-
"Your_E2EE_password_is_incorrect": "你的 E2EE 密码不正确",
59135912
"Your_TOTP_has_been_reset": "您的两步验证 TOTP 已重置。",
59145913
"Your_e2e_key_has_been_reset": "您的端到端加密密钥已被重置",
59155914
"Your_email_address_has_changed": "您的电子邮箱已更改。",

0 commit comments

Comments
 (0)