1 import { useState } from 'react';
3 import { c } from 'ttag';
5 import { useGetOrganizationKey } from '@proton/account/organizationKey/hooks';
6 import { Button, Href } from '@proton/atoms';
7 import Alert from '@proton/components/components/alert/Alert';
8 import Form from '@proton/components/components/form/Form';
9 import type { ModalProps } from '@proton/components/components/modalTwo/Modal';
10 import Modal from '@proton/components/components/modalTwo/Modal';
11 import ModalContent from '@proton/components/components/modalTwo/ModalContent';
12 import ModalFooter from '@proton/components/components/modalTwo/ModalFooter';
13 import ModalHeader from '@proton/components/components/modalTwo/ModalHeader';
14 import InputFieldTwo from '@proton/components/components/v2/field/InputField';
15 import PasswordInputTwo from '@proton/components/components/v2/input/PasswordInput';
16 import useFormErrors from '@proton/components/components/v2/useFormErrors';
17 import useApi from '@proton/components/hooks/useApi';
18 import useAuthentication from '@proton/components/hooks/useAuthentication';
19 import useEventManager from '@proton/components/hooks/useEventManager';
20 import useNotifications from '@proton/components/hooks/useNotifications';
21 import type { PrivateKeyReference } from '@proton/crypto';
22 import { CryptoProxy } from '@proton/crypto';
23 import { useLoading } from '@proton/hooks';
24 import { CacheType } from '@proton/redux-utilities';
25 import { activateOrganizationKey, getOrganizationBackupKeys } from '@proton/shared/lib/api/organization';
26 import { requiredValidator } from '@proton/shared/lib/helpers/formValidators';
27 import { getKnowledgeBaseUrl } from '@proton/shared/lib/helpers/url';
28 import { decryptPrivateKeyWithSalt } from '@proton/shared/lib/keys';
29 import noop from '@proton/utils/noop';
31 interface Props extends ModalProps {
32 mode: 'reactivate' | 'activate';
33 onResetKeys?: () => void;
36 const ReactivateOrganizationKeysModal = ({ onResetKeys, mode, onClose, ...rest }: Props) => {
37 const getOrganizationKey = useGetOrganizationKey();
38 const { createNotification } = useNotifications();
39 const { call } = useEventManager();
40 const authentication = useAuthentication();
42 const { validator, onFormSubmit } = useFormErrors();
44 const [loading, withLoading] = useLoading();
45 const [backupPassword, setBackupPassword] = useState('');
46 const [error, setError] = useState('');
48 const { title, message, warning, success } = (() => {
49 if (mode === 'activate') {
51 title: c('Title').t`Activate organization key`,
53 .t`You must activate your organization private key with the backup organization key password provided to you by your organization administrator.`,
55 .t`Without activation you will not be able to create new users, add addresses to existing users, or access non-private user accounts.`,
56 success: c('passwordless').t`Organization key activated`,
60 if (mode === 'reactivate') {
62 <Href key={1} href={getKnowledgeBaseUrl('/restore-administrator')}>
63 {c('Link').t`Learn more`}
67 title: c('Title').t`Restore administrator privileges`,
69 .jt`Enter the Organization Password to restore administrator privileges. ${learnMore}`,
71 .t`If another administrator changed this password, you will need to ask them for the new Organization Password.`,
72 success: c('passwordless').t`Organization key restored`,
76 throw new Error('Invalid mode');
79 const handleSubmit = async () => {
83 const { PrivateKey, KeySalt } = await api(getOrganizationBackupKeys());
84 let decryptedPrivateKey: PrivateKeyReference;
87 decryptedPrivateKey = await decryptPrivateKeyWithSalt({
89 password: backupPassword,
93 throw new Error(c('Error').t`Incorrect password`);
96 const armoredPrivateKey = await CryptoProxy.exportPrivateKey({
97 privateKey: decryptedPrivateKey,
98 passphrase: authentication.getPassword(),
100 await api(activateOrganizationKey(armoredPrivateKey));
102 // Warning: Force a refetch of the org key because it's not present in the event manager.
103 await getOrganizationKey({ cache: CacheType.None });
105 createNotification({ text: success });
112 const handleClose = loading ? noop : onClose;
118 if (!onFormSubmit()) {
121 void withLoading(handleSubmit());
123 onClose={handleClose}
126 <ModalHeader title={title} />
128 <div className="mb-4">{message}</div>
129 <Alert className="mb-4" type="warning">
133 id="organizationPassword"
134 as={PasswordInputTwo}
135 label={c('Label').t`Organization password`}
136 placeholder={c('Placeholder').t`Password`}
137 value={backupPassword}
138 onValue={(value: string) => {
140 setBackupPassword(value);
142 error={validator([requiredValidator(backupPassword), error])}
148 <Button onClick={handleClose} disabled={loading}>
149 {c('Action').t`Close`}
159 >{c('Action').t`Reset keys`}</Button>
161 <Button loading={loading} type="submit" color="norm">
162 {c('Action').t`Save`}
170 export default ReactivateOrganizationKeysModal;