2022-08-03 16:56:11 +02:00
|
|
|
import React, { useCallback, useContext, useState } from 'react';
|
|
|
|
import PropTypes from 'prop-types';
|
2023-06-08 13:02:08 +02:00
|
|
|
import { useSelector, useDispatch } from 'react-redux';
|
|
|
|
import { useHistory } from 'react-router-dom';
|
2022-08-03 16:56:11 +02:00
|
|
|
import log from 'loglevel';
|
2023-04-25 10:25:58 +02:00
|
|
|
import { isValidSIWEOrigin } from '@metamask/controller-utils';
|
2023-06-20 15:37:09 +02:00
|
|
|
import { ethErrors, serializeError } from 'eth-rpc-errors';
|
2023-07-20 00:32:35 +02:00
|
|
|
import { BannerAlert, Text } from '../../component-library';
|
2022-08-03 16:56:11 +02:00
|
|
|
import Popover from '../../ui/popover';
|
|
|
|
import Checkbox from '../../ui/check-box';
|
2023-06-08 13:02:08 +02:00
|
|
|
import Button from '../../ui/button';
|
2022-08-03 16:56:11 +02:00
|
|
|
import { I18nContext } from '../../../contexts/i18n';
|
|
|
|
import { PageContainerFooter } from '../../ui/page-container';
|
2023-04-15 02:10:27 +02:00
|
|
|
import { isAddressLedger } from '../../../ducks/metamask/metamask';
|
2022-08-03 16:56:11 +02:00
|
|
|
import {
|
|
|
|
accountsWithSendEtherInfoSelector,
|
|
|
|
getSubjectMetadata,
|
2023-06-08 13:02:08 +02:00
|
|
|
getTotalUnapprovedMessagesCount,
|
|
|
|
unconfirmedMessagesHashSelector,
|
2022-08-03 16:56:11 +02:00
|
|
|
} from '../../../selectors';
|
2023-06-08 13:02:08 +02:00
|
|
|
import { getAccountByAddress, valuesFor } from '../../../helpers/utils/util';
|
2023-06-23 20:08:22 +02:00
|
|
|
import { isSuspiciousResponse } from '../../../../shared/modules/security-provider.utils';
|
2022-08-03 16:56:11 +02:00
|
|
|
import { formatMessageParams } from '../../../../shared/modules/siwe';
|
2023-06-08 13:02:08 +02:00
|
|
|
import { clearConfirmTransaction } from '../../../ducks/confirm-transaction/confirm-transaction.duck';
|
2023-06-06 15:53:28 +02:00
|
|
|
|
2023-03-21 17:49:04 +01:00
|
|
|
import {
|
|
|
|
SEVERITIES,
|
|
|
|
TextVariant,
|
|
|
|
} from '../../../helpers/constants/design-system';
|
2023-06-20 15:37:09 +02:00
|
|
|
import {
|
|
|
|
resolvePendingApproval,
|
|
|
|
rejectPendingApproval,
|
|
|
|
rejectAllMessages,
|
|
|
|
completedTx,
|
|
|
|
showModal,
|
|
|
|
} from '../../../store/actions';
|
2022-10-04 23:33:51 +02:00
|
|
|
|
2023-02-23 12:38:09 +01:00
|
|
|
import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message';
|
2023-06-08 13:02:08 +02:00
|
|
|
import ConfirmPageContainerNavigation from '../confirm-page-container/confirm-page-container-navigation';
|
|
|
|
import { getMostRecentOverviewPage } from '../../../ducks/history/history';
|
2023-04-15 02:10:27 +02:00
|
|
|
import LedgerInstructionField from '../ledger-instruction-field';
|
2023-06-06 15:53:28 +02:00
|
|
|
|
|
|
|
import SignatureRequestHeader from '../signature-request-header';
|
2022-08-03 16:56:11 +02:00
|
|
|
import Header from './signature-request-siwe-header';
|
|
|
|
import Message from './signature-request-siwe-message';
|
|
|
|
|
2023-06-20 15:37:09 +02:00
|
|
|
export default function SignatureRequestSIWE({ txData }) {
|
2023-06-08 13:02:08 +02:00
|
|
|
const dispatch = useDispatch();
|
|
|
|
const history = useHistory();
|
2023-06-06 15:53:28 +02:00
|
|
|
const t = useContext(I18nContext);
|
2022-08-03 16:56:11 +02:00
|
|
|
const allAccounts = useSelector(accountsWithSendEtherInfoSelector);
|
|
|
|
const subjectMetadata = useSelector(getSubjectMetadata);
|
|
|
|
|
2023-06-08 13:02:08 +02:00
|
|
|
const messagesCount = useSelector(getTotalUnapprovedMessagesCount);
|
|
|
|
const messagesList = useSelector(unconfirmedMessagesHashSelector);
|
|
|
|
const mostRecentOverviewPage = useSelector(getMostRecentOverviewPage);
|
|
|
|
|
2022-08-03 16:56:11 +02:00
|
|
|
const {
|
|
|
|
msgParams: {
|
|
|
|
from,
|
|
|
|
origin,
|
|
|
|
siwe: { parsedMessage },
|
|
|
|
},
|
2023-06-20 15:37:09 +02:00
|
|
|
id,
|
2022-08-03 16:56:11 +02:00
|
|
|
} = txData;
|
|
|
|
|
2023-04-15 02:10:27 +02:00
|
|
|
const isLedgerWallet = useSelector((state) => isAddressLedger(state, from));
|
|
|
|
|
2022-08-03 16:56:11 +02:00
|
|
|
const fromAccount = getAccountByAddress(allAccounts, from);
|
|
|
|
const targetSubjectMetadata = subjectMetadata[origin];
|
|
|
|
|
|
|
|
const isMatchingAddress =
|
|
|
|
from.toLowerCase() === parsedMessage.address.toLowerCase();
|
|
|
|
|
2023-04-25 10:25:58 +02:00
|
|
|
const isSIWEDomainValid = isValidSIWEOrigin(txData.msgParams);
|
2022-08-03 16:56:11 +02:00
|
|
|
|
|
|
|
const [isShowingDomainWarning, setIsShowingDomainWarning] = useState(false);
|
2023-04-21 21:36:27 +02:00
|
|
|
const [hasAgreedToDomainWarning, setHasAgreedToDomainWarning] =
|
|
|
|
useState(false);
|
|
|
|
|
2023-06-23 20:08:22 +02:00
|
|
|
const showSecurityProviderBanner = isSuspiciousResponse(
|
|
|
|
txData?.securityProviderResponse,
|
|
|
|
);
|
2022-08-03 16:56:11 +02:00
|
|
|
|
2023-06-20 15:37:09 +02:00
|
|
|
const onSign = useCallback(async () => {
|
|
|
|
try {
|
|
|
|
await dispatch(resolvePendingApproval(id, null));
|
|
|
|
dispatch(completedTx(id));
|
|
|
|
} catch (e) {
|
|
|
|
log.error(e);
|
|
|
|
}
|
|
|
|
}, [id, dispatch]);
|
|
|
|
|
|
|
|
const onCancel = useCallback(async () => {
|
|
|
|
try {
|
|
|
|
await dispatch(
|
|
|
|
rejectPendingApproval(
|
|
|
|
id,
|
|
|
|
serializeError(ethErrors.provider.userRejectedRequest()),
|
|
|
|
),
|
|
|
|
);
|
|
|
|
} catch (e) {
|
|
|
|
log.error(e);
|
|
|
|
}
|
|
|
|
}, []);
|
2022-08-03 16:56:11 +02:00
|
|
|
|
2023-06-08 13:02:08 +02:00
|
|
|
const handleCancelAll = () => {
|
|
|
|
const unapprovedTxCount = messagesCount;
|
|
|
|
|
|
|
|
dispatch(
|
|
|
|
showModal({
|
|
|
|
name: 'REJECT_TRANSACTIONS',
|
|
|
|
unapprovedTxCount,
|
|
|
|
onSubmit: async () => {
|
2023-06-20 15:37:09 +02:00
|
|
|
await dispatch(rejectAllMessages(valuesFor(messagesList)));
|
2023-06-08 13:02:08 +02:00
|
|
|
dispatch(clearConfirmTransaction());
|
|
|
|
history.push(mostRecentOverviewPage);
|
|
|
|
},
|
|
|
|
}),
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
const rejectNText = t('rejectRequestsN', [messagesCount]);
|
|
|
|
|
2022-08-03 16:56:11 +02:00
|
|
|
return (
|
|
|
|
<div className="signature-request-siwe">
|
2023-06-08 13:02:08 +02:00
|
|
|
<div className="request-signature__navigation">
|
|
|
|
<ConfirmPageContainerNavigation />
|
|
|
|
</div>
|
2023-06-06 15:53:28 +02:00
|
|
|
<SignatureRequestHeader txData={txData} />
|
2022-08-03 16:56:11 +02:00
|
|
|
<Header
|
|
|
|
fromAccount={fromAccount}
|
2023-03-13 18:40:43 +01:00
|
|
|
domain={origin}
|
2022-08-03 16:56:11 +02:00
|
|
|
isSIWEDomainValid={isSIWEDomainValid}
|
|
|
|
subjectMetadata={targetSubjectMetadata}
|
|
|
|
/>
|
2023-04-21 21:36:27 +02:00
|
|
|
|
|
|
|
{showSecurityProviderBanner && (
|
2023-02-23 12:38:09 +01:00
|
|
|
<SecurityProviderBannerMessage
|
|
|
|
securityProviderResponse={txData.securityProviderResponse}
|
|
|
|
/>
|
2023-04-21 21:36:27 +02:00
|
|
|
)}
|
|
|
|
|
2022-08-03 16:56:11 +02:00
|
|
|
<Message data={formatMessageParams(parsedMessage, t)} />
|
|
|
|
{!isMatchingAddress && (
|
2023-03-21 17:49:04 +01:00
|
|
|
<BannerAlert
|
|
|
|
severity={SEVERITIES.WARNING}
|
|
|
|
marginLeft={4}
|
|
|
|
marginRight={4}
|
|
|
|
marginBottom={4}
|
|
|
|
>
|
|
|
|
{t('SIWEAddressInvalid', [
|
2022-08-03 16:56:11 +02:00
|
|
|
parsedMessage.address,
|
|
|
|
fromAccount.address,
|
|
|
|
])}
|
2023-03-21 17:49:04 +01:00
|
|
|
</BannerAlert>
|
2022-08-03 16:56:11 +02:00
|
|
|
)}
|
2023-04-15 02:10:27 +02:00
|
|
|
|
|
|
|
{isLedgerWallet && (
|
|
|
|
<div className="confirm-approve-content__ledger-instruction-wrapper">
|
|
|
|
<LedgerInstructionField showDataInstruction />
|
|
|
|
</div>
|
|
|
|
)}
|
|
|
|
|
2022-08-03 16:56:11 +02:00
|
|
|
{!isSIWEDomainValid && (
|
2023-03-21 17:49:04 +01:00
|
|
|
<BannerAlert
|
|
|
|
severity={SEVERITIES.DANGER}
|
|
|
|
marginLeft={4}
|
|
|
|
marginRight={4}
|
|
|
|
marginBottom={4}
|
|
|
|
>
|
|
|
|
<Text variant={TextVariant.bodyMdBold}>
|
|
|
|
{t('SIWEDomainInvalidTitle')}
|
|
|
|
</Text>{' '}
|
|
|
|
<Text>{t('SIWEDomainInvalidText')}</Text>
|
|
|
|
</BannerAlert>
|
2022-08-03 16:56:11 +02:00
|
|
|
)}
|
|
|
|
<PageContainerFooter
|
|
|
|
footerClassName="signature-request-siwe__page-container-footer"
|
|
|
|
onCancel={onCancel}
|
|
|
|
onSubmit={
|
|
|
|
isSIWEDomainValid ? onSign : () => setIsShowingDomainWarning(true)
|
|
|
|
}
|
|
|
|
cancelText={t('cancel')}
|
|
|
|
submitText={t('signin')}
|
2022-10-04 23:33:51 +02:00
|
|
|
submitButtonType={isSIWEDomainValid ? 'primary' : 'danger-primary'}
|
2022-08-03 16:56:11 +02:00
|
|
|
/>
|
2023-06-08 13:02:08 +02:00
|
|
|
{messagesCount > 1 ? (
|
|
|
|
<Button
|
|
|
|
type="link"
|
|
|
|
className="request-signature__container__reject"
|
|
|
|
onClick={(e) => {
|
|
|
|
e.preventDefault();
|
|
|
|
handleCancelAll();
|
|
|
|
}}
|
|
|
|
>
|
|
|
|
{rejectNText}
|
|
|
|
</Button>
|
|
|
|
) : null}
|
2022-08-03 16:56:11 +02:00
|
|
|
{isShowingDomainWarning && (
|
|
|
|
<Popover
|
|
|
|
onClose={() => setIsShowingDomainWarning(false)}
|
|
|
|
title={t('SIWEWarningTitle')}
|
|
|
|
subtitle={t('SIWEWarningSubtitle')}
|
|
|
|
className="signature-request-siwe__warning-popover"
|
|
|
|
footerClassName="signature-request-siwe__warning-popover__footer"
|
|
|
|
footer={
|
|
|
|
<PageContainerFooter
|
|
|
|
footerClassName="signature-request-siwe__warning-popover__footer__warning-footer"
|
|
|
|
onCancel={() => setIsShowingDomainWarning(false)}
|
|
|
|
cancelText={t('cancel')}
|
|
|
|
cancelButtonType="default"
|
|
|
|
onSubmit={onSign}
|
|
|
|
submitText={t('confirm')}
|
|
|
|
submitButtonType="danger-primary"
|
2023-04-21 21:36:27 +02:00
|
|
|
disabled={!hasAgreedToDomainWarning}
|
2022-08-03 16:56:11 +02:00
|
|
|
/>
|
|
|
|
}
|
|
|
|
>
|
|
|
|
<div className="signature-request-siwe__warning-popover__checkbox-wrapper">
|
|
|
|
<Checkbox
|
|
|
|
id="signature-request-siwe_domain-checkbox"
|
2023-04-21 21:36:27 +02:00
|
|
|
checked={hasAgreedToDomainWarning}
|
2022-08-03 16:56:11 +02:00
|
|
|
className="signature-request-siwe__warning-popover__checkbox-wrapper__checkbox"
|
2023-04-21 21:36:27 +02:00
|
|
|
onClick={() => setHasAgreedToDomainWarning((checked) => !checked)}
|
2022-08-03 16:56:11 +02:00
|
|
|
/>
|
|
|
|
<label
|
|
|
|
className="signature-request-siwe__warning-popover__checkbox-wrapper__label"
|
|
|
|
htmlFor="signature-request-siwe_domain-checkbox"
|
|
|
|
>
|
|
|
|
{t('SIWEDomainWarningBody', [parsedMessage.domain])}
|
|
|
|
</label>
|
|
|
|
</div>
|
|
|
|
</Popover>
|
|
|
|
)}
|
|
|
|
</div>
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
SignatureRequestSIWE.propTypes = {
|
|
|
|
/**
|
|
|
|
* The display content of transaction data
|
|
|
|
*/
|
|
|
|
txData: PropTypes.object.isRequired,
|
|
|
|
};
|