1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-26 20:39:08 +01:00
metamask-extension/ui/components/app/modals/export-private-key-modal/export-private-key-modal.component.js
Monte Lai 0306422bbf
Add reveal to export private key (#18170)
Co-authored-by: George Marshall <george.marshall@consensys.net>
Co-authored-by: Brad Decker <bhdecker84@gmail.com>
Co-authored-by: David Walsh <davidwalsh83@gmail.com>
Co-authored-by: Howard Braham <howrad@gmail.com>

* change js to tsx

* update to typescript

* add labels to circle animation

* add willHide prop to hold to reveal modal

* add test

* convert to design system

* fix lint

* fix type

* bump coverage

* rename

* remove comments

* remove ts comment and add fix exhuastive dep check

* update coverage

* add hide modal test

* use banneralert

* update label

* remove unused

* fix text

* update aria label messages

* change exportAccountAndGetPrivateKey to be async

* fix lint

* update coverage target

* update coverage

* update input component

* update coverage

* update coverage

* fix blank line

* use &&

* move plainKey to under !privateKeyInput

* update hold modal to display srp and private key message

* fix styling

* fix lint and test

* fix unused locales

* remove redundent check

* update storybook

* fix text alignment

* fix lint

* update snapshot

* fix test

* update coverage

* fix merge conflict

* refactor

* fix variant

* update snapshot

* fix test after merge

* fix test after merge conflict

* fix label text

* update to use label component
2023-05-06 17:04:20 -04:00

247 lines
6.8 KiB
JavaScript

import log from 'loglevel';
import React, { useContext, useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import withModalProps from '../../../../helpers/higher-order-components/with-modal-props';
import Box from '../../../ui/box';
import {
BUTTON_SIZES,
BUTTON_VARIANT,
BannerAlert,
Button,
Text,
} from '../../../component-library';
import AccountModalContainer from '../account-modal-container';
import { toChecksumHexAddress } from '../../../../../shared/modules/hexstring-utils';
import {
MetaMetricsEventCategory,
MetaMetricsEventKeyType,
MetaMetricsEventName,
} from '../../../../../shared/constants/metametrics';
import HoldToRevealModal from '../hold-to-reveal-modal/hold-to-reveal-modal';
import { MetaMetricsContext } from '../../../../contexts/metametrics';
import { useI18nContext } from '../../../../hooks/useI18nContext';
import {
BLOCK_SIZES,
BorderColor,
BorderStyle,
Color,
DISPLAY,
FLEX_DIRECTION,
FONT_WEIGHT,
JustifyContent,
TextVariant,
} from '../../../../helpers/constants/design-system';
import PrivateKeyDisplay from './private-key';
import PasswordInput from './password-input';
const ExportPrivateKeyModal = ({
clearAccountDetails,
hideWarning,
exportAccount,
selectedIdentity,
showAccountDetailModal,
hideModal,
warning = null,
previousModalState,
}) => {
const [password, setPassword] = useState('');
const [privateKey, setPrivateKey] = useState(null);
const [showWarning, setShowWarning] = useState(true);
const [showHoldToReveal, setShowHoldToReveal] = useState(false);
const trackEvent = useContext(MetaMetricsContext);
const t = useI18nContext();
useEffect(() => {
return () => {
clearAccountDetails();
hideWarning();
};
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
const exportAccountAndGetPrivateKey = async (passwordInput, address) => {
try {
const privateKeyRetrieved = await exportAccount(passwordInput, address);
trackEvent(
{
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportRevealed,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
},
{},
);
setPrivateKey(privateKeyRetrieved);
setShowWarning(false);
setShowHoldToReveal(true);
} catch (e) {
trackEvent(
{
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportFailed,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
reason: 'incorrect_password',
},
},
{},
);
log.error(e);
}
};
const { name, address } = selectedIdentity;
if (showHoldToReveal) {
return (
<AccountModalContainer
className="export-private-key-modal"
selectedIdentity={selectedIdentity}
showBackButton={previousModalState === 'ACCOUNT_DETAILS'}
backButtonAction={() => showAccountDetailModal()}
>
<HoldToRevealModal
onLongPressed={() => setShowHoldToReveal(false)}
willHide={false}
holdToRevealType="PrivateKey"
/>
</AccountModalContainer>
);
}
return (
<AccountModalContainer
className="export-private-key-modal"
selectedIdentity={selectedIdentity}
showBackButton={previousModalState === 'ACCOUNT_DETAILS'}
backButtonAction={() => showAccountDetailModal()}
>
<Text
as="span"
marginTop={2}
variant={TextVariant.bodyLgMedium}
fontWeight={FONT_WEIGHT.NORMAL}
>
{name}
</Text>
<Box
className="ellip-address-wrapper"
borderStyle={BorderStyle.solid}
borderColor={BorderColor.borderDefault}
borderWidth={1}
marginTop={2}
padding={[1, 2, 1, 2]}
>
{toChecksumHexAddress(address)}
</Box>
<Box
className="export-private-key-modal__divider"
width={BLOCK_SIZES.FULL}
margin={[5, 0, 3, 0]}
/>
<Text
variant={TextVariant.bodyLgMedium}
margin={[4, 0, 4, 0]}
fontWeight={FONT_WEIGHT.NORMAL}
>
{t('showPrivateKeys')}
</Text>
{privateKey ? (
<PrivateKeyDisplay privateKey={privateKey} />
) : (
<PasswordInput setPassword={setPassword} />
)}
{showWarning && (
<Text color={Color.errorDefault} variant={TextVariant.bodySm}>
{warning}
</Text>
)}
<BannerAlert
padding={[1, 3, 0, 3]}
marginLeft={5}
marginRight={5}
marginTop={4}
severity="danger"
>
{t('privateKeyWarning')}
</BannerAlert>
<Box
display={DISPLAY.FLEX}
flexDirection={FLEX_DIRECTION.ROW}
width={BLOCK_SIZES.FULL}
justifyContent={JustifyContent.spaceBetween}
marginTop={3}
padding={[5, 0, 5, 0]}
>
{!privateKey && (
<Button
type={BUTTON_VARIANT.SECONDARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.HALF}
marginRight={4}
onClick={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportCanceled,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
});
hideModal();
}}
>
{t('cancel')}
</Button>
)}
{privateKey ? (
<Button
type={BUTTON_VARIANT.PRIMARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.FULL}
onClick={() => {
hideModal();
}}
>
{t('done')}
</Button>
) : (
<Button
type={BUTTON_VARIANT.PRIMARY}
size={BUTTON_SIZES.LG}
width={BLOCK_SIZES.HALF}
onClick={() => {
trackEvent({
category: MetaMetricsEventCategory.Keys,
event: MetaMetricsEventName.KeyExportRequested,
properties: {
key_type: MetaMetricsEventKeyType.Pkey,
},
});
exportAccountAndGetPrivateKey(password, address);
}}
disabled={!password}
>
{t('confirm')}
</Button>
)}
</Box>
</AccountModalContainer>
);
};
ExportPrivateKeyModal.propTypes = {
exportAccount: PropTypes.func.isRequired,
selectedIdentity: PropTypes.object.isRequired,
warning: PropTypes.node,
showAccountDetailModal: PropTypes.func.isRequired,
hideModal: PropTypes.func.isRequired,
hideWarning: PropTypes.func.isRequired,
clearAccountDetails: PropTypes.func.isRequired,
previousModalState: PropTypes.string,
};
export default withModalProps(ExportPrivateKeyModal);