Merge branch 'master' into search

This commit is contained in:
Abhinav-grd 2021-05-18 12:22:17 +05:30
commit 41d117f04e
11 changed files with 228 additions and 218 deletions

View file

@ -5,6 +5,7 @@ import constants from 'utils/strings/constants';
export interface MessageAttributes {
title?: string;
staticBackdrop?: boolean;
nonClosable?: boolean;
content?: any;
close?: { text?: string; variant?: string };
proceed?: {
@ -35,10 +36,14 @@ export default function MessageDialog({
return (
<Modal
{...props}
onHide={attributes.nonClosable ? () => null : props.onHide}
centered
backdrop={attributes.staticBackdrop ? 'static' : 'true'}
>
<Modal.Header style={{ borderBottom: 'none' }} closeButton>
<Modal.Header
style={{ borderBottom: 'none' }}
closeButton={!attributes.nonClosable}
>
{attributes.title && (
<Modal.Title>
<strong>{attributes.title}</strong>
@ -50,53 +55,55 @@ export default function MessageDialog({
{children ? children : <h5>{attributes.content}</h5>}
</Modal.Body>
)}
<Modal.Footer style={{ borderTop: 'none' }}>
<div
style={{
display: 'flex',
flexWrap: 'wrap',
}}
>
{attributes.close && (
<Button
variant={`outline-${
attributes.close?.variant ?? 'secondary'
}`}
onClick={props.onHide}
style={{
padding: '6px 3em',
margin: '0 20px',
marginBottom: '20px',
flex: 1,
whiteSpace: 'nowrap',
}}
>
{attributes.close?.text ?? constants.OK}
</Button>
)}
{attributes.proceed && (
<Button
variant={`outline-${
attributes.proceed?.variant ?? 'primary'
}`}
onClick={() => {
attributes.proceed.action();
props.onHide();
}}
style={{
padding: '6px 3em',
margin: '0 20px',
marginBottom: '20px',
flex: 1,
whiteSpace: 'nowrap',
}}
disabled={attributes.proceed.disabled}
>
{attributes.proceed.text}
</Button>
)}
</div>
</Modal.Footer>
{(attributes.close || attributes.proceed) && (
<Modal.Footer style={{ borderTop: 'none' }}>
<div
style={{
display: 'flex',
flexWrap: 'wrap',
}}
>
{attributes.close && (
<Button
variant={`outline-${
attributes.close?.variant ?? 'secondary'
}`}
onClick={props.onHide}
style={{
padding: '6px 3em',
margin: '0 20px',
marginBottom: '20px',
flex: 1,
whiteSpace: 'nowrap',
}}
>
{attributes.close?.text ?? constants.OK}
</Button>
)}
{attributes.proceed && (
<Button
variant={`outline-${
attributes.proceed?.variant ?? 'primary'
}`}
onClick={() => {
attributes.proceed.action();
props.onHide();
}}
style={{
padding: '6px 3em',
margin: '0 20px',
marginBottom: '20px',
flex: 1,
whiteSpace: 'nowrap',
}}
disabled={attributes.proceed.disabled}
>
{attributes.proceed.text}
</Button>
)}
</div>
</Modal.Footer>
)}
</Modal>
);
}

View file

@ -1,109 +0,0 @@
import React, { useEffect, useState } from 'react';
import Container from 'components/Container';
import Button from 'react-bootstrap/Button';
import constants from 'utils/strings/constants';
import { Card, Form, Spinner } from 'react-bootstrap';
import { Formik, FormikHelpers } from 'formik';
import * as Yup from 'yup';
import SubmitButton from './SubmitButton';
interface formValues {
passphrase: string;
}
interface Props {
callback: (passphrase: string, setFieldError) => void;
fieldType: string;
title: string;
placeholder: string;
buttonText: string;
alternateOption: { text: string; click: () => void };
back: () => void;
}
export default function PassPhraseForm(props: Props) {
const [loading, SetLoading] = useState(false);
const submitForm = async (
values: formValues,
{ setFieldError }: FormikHelpers<formValues>
) => {
SetLoading(true);
await props.callback(values.passphrase, setFieldError);
SetLoading(false);
};
return (
<Container>
<Card
style={{ minWidth: '320px', padding: '40px 30px' }}
className="text-center"
>
<Card.Body>
<Card.Title style={{ marginBottom: '24px' }}>
{props.title}
</Card.Title>
<Formik<formValues>
initialValues={{ passphrase: '' }}
onSubmit={submitForm}
validationSchema={Yup.object().shape({
passphrase: Yup.string().required(
constants.REQUIRED
),
})}
validateOnChange={false}
validateOnBlur={false}
>
{({
values,
touched,
errors,
handleChange,
handleSubmit,
}) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group>
<Form.Control
type={props.fieldType}
placeholder={props.placeholder}
value={values.passphrase}
onChange={handleChange('passphrase')}
isInvalid={Boolean(
touched.passphrase &&
errors.passphrase
)}
disabled={loading}
autoFocus={true}
/>
<Form.Control.Feedback type="invalid">
{errors.passphrase}
</Form.Control.Feedback>
</Form.Group>
<SubmitButton
buttonText={props.buttonText}
loading={loading}
/>
<br />
<div
style={{
display: 'flex',
flexDirection: 'column',
marginTop: '12px',
}}
>
<Button
variant="link"
onClick={props.alternateOption.click}
>
{props.alternateOption.text}
</Button>
<Button variant="link" onClick={props.back}>
{constants.GO_BACK}
</Button>
</div>
</Form>
)}
</Formik>
</Card.Body>
</Card>
</Container>
);
}

View file

@ -19,7 +19,7 @@ interface formValues {
passphrase: string;
confirm: string;
}
function SetPassword(props: Props) {
function SetPasswordForm(props: Props) {
const [loading, setLoading] = useState(false);
const onSubmit = async (
values: formValues,
@ -94,7 +94,7 @@ function SetPassword(props: Props) {
<Form.Control
type="password"
placeholder={
constants.PASSPHRASE_CONFIRM
constants.RE_ENTER_PASSPHRASE
}
value={values.confirm}
onChange={handleChange('confirm')}
@ -129,4 +129,4 @@ function SetPassword(props: Props) {
</Container>
);
}
export default SetPassword;
export default SetPasswordForm;

View file

@ -32,7 +32,7 @@ interface Props {
files: File[];
collections: Collection[];
setDialogMessage: SetDialogMessage;
setPlanModalView;
showPlanSelectorModal: () => void;
}
export default function Sidebar(props: Props) {
const [usage, SetUsage] = useState<string>(null);
@ -44,6 +44,7 @@ export default function Sidebar(props: Props) {
}, []);
const [isOpen, setIsOpen] = useState(false);
const [recoverModalView, setRecoveryModalView] = useState(false);
const [accountDeleteModalView, setAccountDeleteModalView] = useState(false);
useEffect(() => {
const main = async () => {
if (!isOpen) {
@ -93,7 +94,7 @@ export default function Sidebar(props: Props) {
const router = useRouter();
function onManageClick() {
setIsOpen(false);
props.setPlanModalView(true);
props.showPlanSelectorModal();
}
return (
<Menu
@ -234,7 +235,7 @@ export default function Sidebar(props: Props) {
></div>
<LinkButton
variant="danger"
style={{ marginTop: '30px', marginBottom: '50px' }}
style={{ marginTop: '30px' }}
onClick={() =>
props.setDialogMessage({
title: `${constants.CONFIRM} ${constants.LOGOUT}`,
@ -251,6 +252,7 @@ export default function Sidebar(props: Props) {
>
logout
</LinkButton>
<div style={{ marginBottom: '50px' }} />
</Menu>
);
}

View file

@ -0,0 +1,66 @@
import React, { useState } from 'react';
import constants from 'utils/strings/constants';
import { Form } from 'react-bootstrap';
import { Formik, FormikHelpers } from 'formik';
import * as Yup from 'yup';
import SubmitButton from './SubmitButton';
interface formValues {
passphrase: string;
}
interface Props {
callback: (passphrase: string, setFieldError) => void;
fieldType: string;
placeholder: string;
buttonText: string;
}
export default function SingleInputForm(props: Props) {
const [loading, SetLoading] = useState(false);
const submitForm = async (
values: formValues,
{ setFieldError }: FormikHelpers<formValues>
) => {
SetLoading(true);
await props.callback(values.passphrase, setFieldError);
SetLoading(false);
};
return (
<Formik<formValues>
initialValues={{ passphrase: '' }}
onSubmit={submitForm}
validationSchema={Yup.object().shape({
passphrase: Yup.string().required(constants.REQUIRED),
})}
validateOnChange={false}
validateOnBlur={false}
>
{({ values, touched, errors, handleChange, handleSubmit }) => (
<Form noValidate onSubmit={handleSubmit}>
<Form.Group>
<Form.Control
type={props.fieldType}
placeholder={props.placeholder}
value={values.passphrase}
onChange={handleChange('passphrase')}
isInvalid={Boolean(
touched.passphrase && errors.passphrase
)}
disabled={loading}
autoFocus={true}
/>
<Form.Control.Feedback type="invalid">
{errors.passphrase}
</Form.Control.Feedback>
</Form.Group>
<SubmitButton
buttonText={props.buttonText}
loading={loading}
/>
<br />
</Form>
)}
</Formik>
);
}

View file

@ -10,7 +10,7 @@ import CryptoWorker, {
} from 'utils/crypto';
import { getActualKey } from 'utils/common/key';
import { logoutUser, setKeys, UpdatedKey } from 'services/userService';
import PasswordForm from 'components/PasswordForm';
import SetPasswordForm from 'components/SetPasswordForm';
export interface KEK {
key: string;
@ -44,10 +44,8 @@ export default function Generate() {
setFieldError('confirm', constants.PASSWORD_GENERATION_FAILED);
return;
}
const encryptedKeyAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64(
key,
kek.key
);
const encryptedKeyAttributes: B64EncryptionResult =
await cryptoWorker.encryptToB64(key, kek.key);
const updatedKey: UpdatedKey = {
kekSalt,
encryptedKey: encryptedKeyAttributes.encryptedData,
@ -73,7 +71,7 @@ export default function Generate() {
router.push('/gallery');
};
return (
<PasswordForm
<SetPasswordForm
callback={onSubmit}
buttonText={constants.CHANGE_PASSWORD}
back={

View file

@ -12,7 +12,9 @@ import CryptoWorker, {
} from 'utils/crypto';
import { logoutUser } from 'services/userService';
import { isFirstLogin } from 'utils/storage';
import PassPhraseForm from 'components/PassphraseForm';
import SingleInputForm from 'components/SingleInputForm';
import Container from 'components/Container';
import { Button, Card } from 'react-bootstrap';
export default function Credentials() {
const router = useRouter();
@ -72,17 +74,42 @@ export default function Credentials() {
};
return (
<PassPhraseForm
callback={verifyPassphrase}
title={constants.ENTER_PASSPHRASE}
placeholder={constants.RETURN_PASSPHRASE_HINT}
buttonText={constants.VERIFY_PASSPHRASE}
fieldType="password"
alternateOption={{
text: constants.FORGOT_PASSWORD,
click: () => router.push('/recover'),
}}
back={logoutUser}
/>
<>
<Container>
<Card
style={{ minWidth: '320px', padding: '40px 30px' }}
className="text-center"
>
<Card.Body>
<Card.Title style={{ marginBottom: '24px' }}>
{constants.ENTER_PASSPHRASE}
</Card.Title>
<SingleInputForm
callback={verifyPassphrase}
placeholder={constants.RETURN_PASSPHRASE_HINT}
buttonText={constants.VERIFY_PASSPHRASE}
fieldType="password"
/>
<div
style={{
display: 'flex',
flexDirection: 'column',
marginTop: '12px',
}}
>
<Button
variant="link"
onClick={() => router.push('/recover')}
>
{constants.FORGOT_PASSWORD}
</Button>
<Button variant="link" onClick={logoutUser}>
{constants.GO_BACK}
</Button>
</div>
</Card.Body>
</Card>
</Container>
</>
);
}

View file

@ -194,6 +194,7 @@ export default function Gallery() {
action: logoutUser,
variant: 'primary',
},
nonClosable: true,
});
break;
case errorCodes.ERR_KEY_MISSING:
@ -328,7 +329,7 @@ export default function Gallery() {
files={files}
collections={collections}
setDialogMessage={setDialogMessage}
setPlanModalView={setPlanModalView}
showPlanSelectorModal={() => setPlanModalView(true)}
/>
<UploadButton openFileUploader={openFileUploader} />
<PhotoFrame

View file

@ -9,7 +9,7 @@ import CryptoWorker, {
setSessionKeys,
generateAndSaveIntermediateKeyAttributes,
} from 'utils/crypto';
import PasswordForm from 'components/PasswordForm';
import SetPasswordForm from 'components/SetPasswordForm';
import { KeyAttributes } from 'types';
import { setJustSignedUp } from 'utils/storage';
import RecoveryKeyModal from 'components/RecoveryKeyModal';
@ -52,24 +52,16 @@ export default function Generate() {
setFieldError('confirm', constants.PASSWORD_GENERATION_FAILED);
return;
}
const masterKeyEncryptedWithKek: B64EncryptionResult = await cryptoWorker.encryptToB64(
masterKey,
kek.key
);
const masterKeyEncryptedWithRecoveryKey: B64EncryptionResult = await cryptoWorker.encryptToB64(
masterKey,
recoveryKey
);
const recoveryKeyEncryptedWithMasterKey: B64EncryptionResult = await cryptoWorker.encryptToB64(
recoveryKey,
masterKey
);
const masterKeyEncryptedWithKek: B64EncryptionResult =
await cryptoWorker.encryptToB64(masterKey, kek.key);
const masterKeyEncryptedWithRecoveryKey: B64EncryptionResult =
await cryptoWorker.encryptToB64(masterKey, recoveryKey);
const recoveryKeyEncryptedWithMasterKey: B64EncryptionResult =
await cryptoWorker.encryptToB64(recoveryKey, masterKey);
const keyPair = await cryptoWorker.generateKeyPair();
const encryptedKeyPairAttributes: B64EncryptionResult = await cryptoWorker.encryptToB64(
keyPair.privateKey,
masterKey
);
const encryptedKeyPairAttributes: B64EncryptionResult =
await cryptoWorker.encryptToB64(keyPair.privateKey, masterKey);
const keyAttributes: KeyAttributes = {
kekSalt,
@ -101,7 +93,7 @@ export default function Generate() {
return (
<>
<PasswordForm
<SetPasswordForm
callback={onSubmit}
buttonText={constants.SET_PASSPHRASE}
back={logoutUser}

View file

@ -5,8 +5,10 @@ import { getData, LS_KEYS } from 'utils/storage/localStorage';
import { useRouter } from 'next/router';
import { KeyAttributes } from 'types';
import CryptoWorker, { setSessionKeys } from 'utils/crypto';
import PassPhraseForm from 'components/PassphraseForm';
import SingleInputForm from 'components/SingleInputForm';
import MessageDialog from 'components/MessageDialog';
import Container from 'components/Container';
import { Card, Button } from 'react-bootstrap';
export default function Recover() {
const router = useRouter();
@ -43,28 +45,51 @@ export default function Recover() {
return (
<>
<PassPhraseForm
callback={recover}
fieldType="text"
title={constants.RECOVER_ACCOUNT}
placeholder={constants.RETURN_RECOVERY_KEY_HINT}
buttonText={constants.RECOVER}
alternateOption={{
text: constants.NO_RECOVERY_KEY,
click: () => SetMessageDialogView(true),
}}
back={router.back}
/>
<Container>
<Card
style={{ minWidth: '320px', padding: '40px 30px' }}
className="text-center"
>
<Card.Body>
<Card.Title style={{ marginBottom: '24px' }}>
{constants.RECOVER_ACCOUNT}
</Card.Title>
<SingleInputForm
callback={recover}
fieldType="text"
placeholder={constants.RETURN_RECOVERY_KEY_HINT}
buttonText={constants.RECOVER}
/>
<div
style={{
display: 'flex',
flexDirection: 'column',
marginTop: '12px',
}}
>
<Button
variant="link"
onClick={() => SetMessageDialogView(true)}
>
{constants.NO_RECOVERY_KEY}
</Button>
<Button variant="link" onClick={router.back}>
{constants.GO_BACK}
</Button>
</div>
</Card.Body>
</Card>
</Container>
<MessageDialog
size={'lg'}
show={messageDialogView}
onHide={() => SetMessageDialogView(false)}
attributes={{
title: constants.SORRY,
close: {},
content: constants.NO_RECOVERY_KEY_MESSAGE,
}}
>
{constants.NO_RECOVERY_KEY_MESSAGE}
</MessageDialog>
/>
</>
);
}

View file

@ -51,7 +51,8 @@ const englishConstants = {
</p>
),
PASSPHRASE_HINT: 'password',
PASSPHRASE_CONFIRM: 'password again',
RE_ENTER_PASSPHRASE: 'password again',
CONFIRM_PASSPHRASE: 'confirm your password',
PASSPHRASE_MATCH_ERROR: `passwords don't match`,
CONSOLE_WARNING_STOP: 'STOP!',
CONSOLE_WARNING_DESC: `This is a browser feature intended for developers. Please don't copy-paste unverified code here.`,