Flavien modal two
[ProtonMail-WebClient.git] / packages / components / containers / keys / exportKey / ExportPrivateKeyModal.tsx
blob5dd1bceb352988bb5d823a56a628318f610bee65
1 import { useState } from 'react';
3 import { c } from 'ttag';
5 import { Button } from '@proton/atoms';
6 import Form from '@proton/components/components/form/Form';
7 import type { ModalProps } from '@proton/components/components/modalTwo/Modal';
8 import Modal from '@proton/components/components/modalTwo/Modal';
9 import ModalContent from '@proton/components/components/modalTwo/ModalContent';
10 import ModalFooter from '@proton/components/components/modalTwo/ModalFooter';
11 import ModalHeader from '@proton/components/components/modalTwo/ModalHeader';
12 import type { PrivateKeyReference } from '@proton/crypto';
13 import { CryptoProxy } from '@proton/crypto';
14 import { useLoading } from '@proton/hooks';
15 import { KEY_FILE_EXTENSION } from '@proton/shared/lib/constants';
16 import downloadFile from '@proton/shared/lib/helpers/downloadFile';
17 import { passwordLengthValidator } from '@proton/shared/lib/helpers/formValidators';
18 import generateUID from '@proton/utils/generateUID';
19 import noop from '@proton/utils/noop';
21 import { InputFieldTwo, PasswordInputTwo, useFormErrors } from '../../../components';
22 import { useModals } from '../../../hooks';
23 import UnlockModal from '../../login/UnlockModal';
25 const handleExport = async (name: string, privateKey: PrivateKeyReference, password: string) => {
26     const fingerprint = privateKey.getFingerprint();
27     const filename = ['privatekey.', name, '-', fingerprint, KEY_FILE_EXTENSION].join('');
28     const armoredEncryptedKey = await CryptoProxy.exportPrivateKey({ privateKey: privateKey, passphrase: password });
29     const blob = new Blob([armoredEncryptedKey], { type: 'text/plain' });
30     downloadFile(blob, filename);
33 interface Props extends ModalProps {
34     name: string;
35     privateKey: PrivateKeyReference;
36     onSuccess?: () => void;
39 const ExportPrivateKeyModal = ({ name, privateKey, onSuccess, onClose, ...rest }: Props) => {
40     const { createModal } = useModals();
41     const [loading, withLoading] = useLoading();
42     const { validator, onFormSubmit } = useFormErrors();
44     const [id] = useState(() => generateUID('exportKey'));
45     const [password, setPassword] = useState('');
47     const handleSubmit = async () => {
48         // Force a login since the private key is sensitive
49         await new Promise<string>((resolve, reject) => {
50             createModal(<UnlockModal onClose={() => reject()} onSuccess={resolve} />);
51         });
52         await handleExport(name, privateKey, password);
53         onSuccess?.();
54         onClose?.();
55     };
57     const handleClose = loading ? noop : onClose;
59     return (
60         <Modal
61             as={Form}
62             onSubmit={() => {
63                 if (!onFormSubmit()) {
64                     return;
65                 }
67                 void withLoading(handleSubmit());
68             }}
69             onClose={handleClose}
70             {...rest}
71         >
72             <ModalHeader title={c('Title').t`Export private key`} />
73             <ModalContent>
74                 <div className="mb-4">
75                     {c('Info')
76                         .t`This will download a file containing your private key. Protect this file by encrypting it with a password.`}
77                 </div>
78                 <InputFieldTwo
79                     id={id}
80                     as={PasswordInputTwo}
81                     label={c('Label').t`Create password`}
82                     placeholder={c('Placeholder').t`Password`}
83                     value={password}
84                     onValue={setPassword}
85                     error={validator([passwordLengthValidator(password)])}
86                     autoFocus
87                 />
88                 <div>
89                     {c('Info')
90                         .t`Store this password and file in a safe place. You’ll need them again to import your key.`}
91                 </div>
92             </ModalContent>
93             <ModalFooter>
94                 <Button onClick={handleClose} disabled={loading}>
95                     {c('Action').t`Cancel`}
96                 </Button>
98                 <Button loading={loading} type="submit" color="norm">
99                     {c('Action').t`Encrypt and export`}
100                 </Button>
101             </ModalFooter>
102         </Modal>
103     );
106 export default ExportPrivateKeyModal;