ente/packages/shared/components/VerifyMasterPasswordForm.tsx
2023-11-09 13:36:29 +05:30

124 lines
4.1 KiB
TypeScript

import SingleInputForm, {
SingleInputFormProps,
} from '../components/SingleInputForm';
import { logError } from '@ente/shared/sentry';
import { CustomError } from '../error';
import { ButtonProps, Input } from '@mui/material';
import { KeyAttributes, User } from '../user/types';
import { SRPAttributes } from '@ente/accounts/types/srp';
import ComlinkCryptoWorker from '../crypto';
import { t } from 'i18next';
export interface VerifyMasterPasswordFormProps {
user: User;
keyAttributes: KeyAttributes;
callback: (
key: string,
kek: string,
keyAttributes: KeyAttributes,
passphrase?: string
) => void;
buttonText: string;
submitButtonProps?: ButtonProps;
getKeyAttributes?: (kek: string) => Promise<KeyAttributes>;
srpAttributes?: SRPAttributes;
}
export default function VerifyMasterPasswordForm({
user,
keyAttributes,
srpAttributes,
callback,
buttonText,
submitButtonProps,
getKeyAttributes,
}: VerifyMasterPasswordFormProps) {
const verifyPassphrase: SingleInputFormProps['callback'] = async (
passphrase,
setFieldError
) => {
try {
const cryptoWorker = await ComlinkCryptoWorker.getInstance();
let kek: string;
try {
if (srpAttributes) {
kek = await cryptoWorker.deriveKey(
passphrase,
srpAttributes.kekSalt,
srpAttributes.opsLimit,
srpAttributes.memLimit
);
} else {
kek = await cryptoWorker.deriveKey(
passphrase,
keyAttributes.kekSalt,
keyAttributes.opsLimit,
keyAttributes.memLimit
);
}
} catch (e) {
logError(e, 'failed to derive key');
throw Error(CustomError.WEAK_DEVICE);
}
if (!keyAttributes && typeof getKeyAttributes === 'function') {
keyAttributes = await getKeyAttributes(kek);
}
if (!keyAttributes) {
throw Error("couldn't get key attributes");
}
try {
const key = await cryptoWorker.decryptB64(
keyAttributes.encryptedKey,
keyAttributes.keyDecryptionNonce,
kek
);
callback(key, kek, keyAttributes, passphrase);
} catch (e) {
logError(e, 'user entered a wrong password');
throw Error(CustomError.INCORRECT_PASSWORD);
}
} catch (e) {
if (e instanceof Error) {
if (e.message === CustomError.TWO_FACTOR_ENABLED) {
// two factor enabled, user has been redirected to two factor page
return;
}
logError(e, 'failed to verify passphrase');
switch (e.message) {
case CustomError.WEAK_DEVICE:
setFieldError(t('WEAK_DEVICE'));
break;
case CustomError.INCORRECT_PASSWORD:
setFieldError(t('INCORRECT_PASSPHRASE'));
break;
default:
setFieldError(`${t('UNKNOWN_ERROR')} ${e.message}`);
}
}
}
};
return (
<SingleInputForm
callback={verifyPassphrase}
placeholder={t('RETURN_PASSPHRASE_HINT')}
buttonText={buttonText}
submitButtonProps={submitButtonProps}
hiddenPreInput={
<Input
sx={{ display: 'none' }}
id="email"
name="email"
autoComplete="username"
type="email"
value={user?.email}
/>
}
autoComplete={'current-password'}
fieldType="password"
/>
);
}