import React, { useState, useEffect, useContext } from 'react'; import Container from 'components/Container'; import styled from 'styled-components'; import Card from 'react-bootstrap/Card'; import Form from 'react-bootstrap/Form'; import constants from 'utils/strings/constants'; import { Formik, FormikHelpers } from 'formik'; import * as Yup from 'yup'; import Button from 'react-bootstrap/Button'; import { logoutUser, putAttributes } from 'services/userService'; import { getData, LS_KEYS, setData } from 'utils/storage/localStorage'; import { useRouter } from 'next/router'; import { getKey, SESSION_KEYS, setKey } from 'utils/storage/sessionStorage'; import { B64EncryptionResult } from 'services/uploadService'; import CryptoWorker from 'utils/crypto/cryptoWorker'; const Image = styled.img` width: 200px; margin-bottom: 20px; max-width: 100%; `; interface formValues { passphrase: string; confirm: string; } interface KEK { key: string; opsLimit: number; memLimit: number; } export default function Generate() { const [loading, setLoading] = useState(false); const [token, setToken] = useState(); const router = useRouter(); const key = getKey(SESSION_KEYS.ENCRYPTION_KEY); useEffect(() => { router.prefetch('/gallery'); const user = getData(LS_KEYS.USER); if (!user?.token) { router.push('/'); } else if (key) { router.push('/gallery'); } else { setToken(user.token); } }, []); const onSubmit = async ( values: formValues, { setFieldError }: FormikHelpers ) => { setLoading(true); try { const { passphrase, confirm } = values; if (passphrase === confirm) { const cryptoWorker = await new CryptoWorker(); const key: string = await cryptoWorker.generateMasterKey(); const kekSalt: string = await cryptoWorker.generateSaltToDeriveKey(); const kek: KEK = await cryptoWorker.deriveSensitiveKey( passphrase, kekSalt ); const encryptedKeyAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64( key, kek.key ); const keyPair = await cryptoWorker.generateKeyPair(); const encryptedKeyPairAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64( keyPair.privateKey, key ); const keyAttributes = { kekSalt, encryptedKey: encryptedKeyAttributes.encryptedData, keyDecryptionNonce: encryptedKeyAttributes.nonce, publicKey: keyPair.publicKey, encryptedSecretKey: encryptedKeyPairAttributes.encryptedData, secretKeyDecryptionNonce: encryptedKeyPairAttributes.nonce, opsLimit: kek.opsLimit, memLimit: kek.memLimit, }; await putAttributes( token, getData(LS_KEYS.USER).name, keyAttributes ); setData( LS_KEYS.KEY_ATTRIBUTES, await generateIntermediateKey( passphrase, keyAttributes, key ) ); const sessionKeyAttributes = await cryptoWorker.encryptToB64( key ); const sessionKey = sessionKeyAttributes.key; const sessionNonce = sessionKeyAttributes.nonce; const encryptionKey = sessionKeyAttributes.encryptedData; setKey(SESSION_KEYS.ENCRYPTION_KEY, { encryptionKey }); setData(LS_KEYS.SESSION, { sessionKey, sessionNonce }); router.push('/gallery'); } else { setFieldError('confirm', constants.PASSPHRASE_MATCH_ERROR); } } catch (e) { setFieldError( 'passphrase', `${constants.UNKNOWN_ERROR} ${e.message}` ); } setLoading(false); }; async function generateIntermediateKey(passphrase, keyAttributes, key) { const cryptoWorker = await new CryptoWorker(); const intermediateKekSalt: string = await cryptoWorker.generateSaltToDeriveKey(); const intermediateKek: KEK = await cryptoWorker.deriveIntermediateKey( passphrase, intermediateKekSalt ); const encryptedKeyAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64( key, intermediateKek.key ); return { intermediateKekSalt, encryptedKey: encryptedKeyAttributes.encryptedData, keyDecryptionNonce: encryptedKeyAttributes.nonce, publicKey: keyAttributes.publicKey, encryptedSecretKey: keyAttributes.encryptedSecretKey, secretKeyDecryptionNonce: keyAttributes.secretKeyDecryptionNonce, opsLimit: intermediateKek.opsLimit, memLimit: intermediateKek.memLimit, }; } return ( {/* vault */}

{constants.ENTER_ENC_PASSPHRASE}

{constants.PASSPHRASE_DISCLAIMER()}
initialValues={{ passphrase: '', confirm: '' }} validationSchema={Yup.object().shape({ passphrase: Yup.string().required( constants.REQUIRED ), confirm: Yup.string().required(constants.REQUIRED), })} onSubmit={onSubmit} > {({ values, touched, errors, handleChange, handleBlur, handleSubmit, }) => (
{errors.passphrase} {errors.confirm}
)}
); }