1
0
mirror of https://github.com/kremalicious/metamask-extension.git synced 2024-11-22 09:57:02 +01:00

Replace ActionableMessage components with BannerAlerts in SIWE Sign-in with Ethereum page (#18207)

* siwe: re-enable warning UI for mismatched domains
- unblocks mismatched domain support
- we may re-add error handling here #18184
- reverts logic from #16616

* siwe: fix mismatch domain warning msg UI

* lint: rm whitespace EOL

* siwe: rm unit test

* lint: fix whitespace

* Icon: support .mm-icon
- apply to SIWE actionable-message
- .mm-icon is a <span>

* lint: fix newline

* Revert "siwe: rm unit test"

This reverts commit c80a4a2e661609c46c76d1e43e05909b6db3f0f5.

* ActionableMessage: add deprecation

* siwe: replace actionable-msg w/ banner-alert

* ActionableMessage: add param for lint

* revert .mm_icon ActionableMessage support

* siwe: create tests

* siwe: fix typo in tests

* siwe: fix - do not allow nested <p> elements

* Update ui/components/app/signature-request-siwe/signature-request-siwe.js

Co-authored-by: George Marshall <george.marshall@consensys.net>

* Update ui/components/app/signature-request-siwe/signature-request-siwe.js

Co-authored-by: George Marshall <george.marshall@consensys.net>

* eslint fix

---------

Co-authored-by: legobeat <109787230+legobeat@users.noreply.github.com>
Co-authored-by: George Marshall <george.marshall@consensys.net>
This commit is contained in:
Ariella Vu 2023-03-21 09:49:04 -07:00 committed by GitHub
parent a04fa20f96
commit 5e3770eb13
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 406 additions and 51 deletions

View File

@ -0,0 +1,245 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`SignatureRequestSIWE (Sign in with Ethereum) should match snapshot 1`] = `
<div>
<div
class="signature-request-siwe"
>
<div
class="signature-request-siwe-header"
>
<div
class="box permissions-connect-header box--flex-direction-column box--justify-content-center box--display-flex"
>
<div
class="permissions-connect-header__icon"
>
<div
class="site-origin"
>
<div
class="chip chip--with-left-icon chip--border-color-border-muted chip--background-color-undefined"
>
<div
class="chip__left-icon"
>
<div
class=""
>
<img
alt="icon"
src="https://example-dapp.website/favicon-32x32.png"
style="height: 24px; width: 24px;"
/>
</div>
</div>
<span
class="box box--margin-top-1 box--margin-bottom-1 box--flex-direction-row typography chip__label typography--h6 typography--weight-normal typography--style-normal typography--color-text-alternative"
>
https://example-dapp.website
</span>
</div>
</div>
</div>
<div
class="permissions-connect-header__title"
>
Sign-in request
</div>
<div
class="permissions-connect-header__subtitle"
>
This site is requesting to sign in with
</div>
</div>
<div
class="account-list-item signature-request-siwe-header__account-list-item"
data-testid="account-list-item"
>
<div
class="account-list-item__top-row"
>
<div
class=""
>
<div
class="identicon account-list-item__identicon"
style="height: 18px; width: 18px; border-radius: 9px;"
>
<div
style="border-radius: 50px; overflow: hidden; padding: 0px; margin: 0px; width: 18px; height: 18px; display: inline-block; background: rgb(250, 58, 0);"
>
<svg
height="18"
width="18"
x="0"
y="0"
>
<rect
fill="#18CDF2"
height="18"
transform="translate(-0.5897213458840913 -1.8586597890715306) rotate(328.9 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#035E56"
height="18"
transform="translate(-10.292884711218024 5.9582598028585885) rotate(176.2 9 9)"
width="18"
x="0"
y="0"
/>
<rect
fill="#F26602"
height="18"
transform="translate(9.375661135250958 -7.990391094185859) rotate(468.9 9 9)"
width="18"
x="0"
y="0"
/>
</svg>
</div>
</div>
</div>
<div
class="account-list-item__account-name"
>
Test Account
</div>
</div>
</div>
</div>
<div
class="box signature-request-siwe-message box--flex-direction-row"
>
<div
class="box box--flex-direction-column"
>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
Message:
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
Click to sign in and accept the Terms of Service: https://community.metamask.io/tos
</h6>
</div>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
URI:
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
http://localhost:8080
</h6>
</div>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
Version:
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
1
</h6>
</div>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
Chain ID:
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
1
</h6>
</div>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
Nonce:
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
STMt6KQMwwdOXE306
</h6>
</div>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
Issued At:
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
2023-03-18T21:40:40.823Z
</h6>
</div>
<div
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row"
>
<h4
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography typography--h4 typography--weight-normal typography--style-normal typography--color-text-default"
>
Resources: 2
</h4>
<h6
class="box box--margin-top-2 box--margin-bottom-2 box--flex-direction-row typography signature-request-siwe-message__sub-text typography--h6 typography--weight-normal typography--style-normal typography--color-text-default"
>
ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu
https://example.com/my-web2-claim.json
</h6>
</div>
</div>
</div>
<div
class="page-container__footer signature-request-siwe__page-container-footer"
>
<footer>
<button
class="button btn--rounded btn-secondary page-container__footer-button page-container__footer-button__cancel"
data-testid="page-container-footer-cancel"
role="button"
tabindex="0"
>
Cancel
</button>
<button
class="button btn--rounded btn-primary page-container__footer-button"
data-testid="page-container-footer-next"
role="button"
tabindex="0"
>
Sign-In
</button>
</footer>
</div>
</div>
</div>
`;

View File

@ -20,27 +20,6 @@
border-radius: 8px; border-radius: 8px;
box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.08); box-shadow: 0 0 7px 0 rgba(0, 0, 0, 0.08);
} }
/** @todo replace ActionableMessage or remove overwritten code. */
.signature-request-siwe__actionable-message {
margin: 0 16px;
flex-direction: row;
align-items: initial;
.icon {
position: absolute;
left: 17px;
top: 13px;
}
.actionable-message__message {
padding-left: 16px;
}
&.actionable-message--with-icon {
padding-left: 16px;
}
}
} }
.signature-request-siwe__warning-popover { .signature-request-siwe__warning-popover {

View File

@ -2,7 +2,7 @@ import React, { useCallback, useContext, useState } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { useSelector } from 'react-redux'; import { useSelector } from 'react-redux';
import log from 'loglevel'; import log from 'loglevel';
import ActionableMessage from '../../ui/actionable-message'; import { BannerAlert, Text } from '../../component-library';
import Popover from '../../ui/popover'; import Popover from '../../ui/popover';
import Checkbox from '../../ui/check-box'; import Checkbox from '../../ui/check-box';
import { I18nContext } from '../../../contexts/i18n'; import { I18nContext } from '../../../contexts/i18n';
@ -13,8 +13,10 @@ import {
} from '../../../selectors'; } from '../../../selectors';
import { getAccountByAddress } from '../../../helpers/utils/util'; import { getAccountByAddress } from '../../../helpers/utils/util';
import { formatMessageParams } from '../../../../shared/modules/siwe'; import { formatMessageParams } from '../../../../shared/modules/siwe';
import { Icon } from '../../component-library/icon/icon'; import {
import { IconColor } from '../../../helpers/constants/design-system'; SEVERITIES,
TextVariant,
} from '../../../helpers/constants/design-system';
import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message'; import SecurityProviderBannerMessage from '../security-provider-banner-message/security-provider-banner-message';
import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../security-provider-banner-message/security-provider-banner-message.constants'; import { SECURITY_PROVIDER_MESSAGE_SEVERITIES } from '../security-provider-banner-message/security-provider-banner-message.constants';
@ -101,38 +103,30 @@ export default function SignatureRequestSIWE({
) : null} ) : null}
<Message data={formatMessageParams(parsedMessage, t)} /> <Message data={formatMessageParams(parsedMessage, t)} />
{!isMatchingAddress && ( {!isMatchingAddress && (
<ActionableMessage <BannerAlert
className="signature-request-siwe__actionable-message" severity={SEVERITIES.WARNING}
type="warning" marginLeft={4}
message={t('SIWEAddressInvalid', [ marginRight={4}
marginBottom={4}
>
{t('SIWEAddressInvalid', [
parsedMessage.address, parsedMessage.address,
fromAccount.address, fromAccount.address,
])} ])}
iconFillColor="var(--color-warning-default)" </BannerAlert>
useIcon
withRightButton
icon={<Icon name="danger" color={IconColor.warningDefault} />}
/>
)} )}
{!isSIWEDomainValid && ( {!isSIWEDomainValid && (
<ActionableMessage <BannerAlert
className="signature-request-siwe__actionable-message" severity={SEVERITIES.DANGER}
type="danger" marginLeft={4}
message={ marginRight={4}
<> marginBottom={4}
<p >
className="typography--weight-bold" <Text variant={TextVariant.bodyMdBold}>
style={{ display: 'inline' }} {t('SIWEDomainInvalidTitle')}
> </Text>{' '}
{t('SIWEDomainInvalidTitle')} <Text>{t('SIWEDomainInvalidText')}</Text>
</p>{' '} </BannerAlert>
{t('SIWEDomainInvalidText')}
</>
}
iconFillColor="var(--color-error-default)"
useIcon
icon={<Icon name="danger" color={IconColor.errorDefault} />}
/>
)} )}
<PageContainerFooter <PageContainerFooter
footerClassName="signature-request-siwe__page-container-footer" footerClassName="signature-request-siwe__page-container-footer"

View File

@ -0,0 +1,113 @@
import React from 'react';
import { cloneDeep } from 'lodash';
import { MESSAGE_TYPE } from '../../../../shared/constants/app';
import mockState from '../../../../test/data/mock-state.json';
import { renderWithProvider } from '../../../../test/lib/render-helpers';
import configureStore from '../../../store/store';
import SignatureRequestSIWE from '.';
const MOCK_ORIGIN = 'https://example-dapp.website';
const MOCK_ADDRESS = '0x0dcd5d886577d5081b0c52e242ef29e70be3e7bc';
const mockStoreInitialState = {
metamask: {
...mockState.metamask,
subjectMetadata: {
[MOCK_ORIGIN]: {
iconUrl: 'https://example-dapp.website/favicon-32x32.png',
name: 'Example Test Dapp',
},
},
},
};
const mockProps = {
cancelPersonalMessage: jest.fn(),
signPersonalMessage: jest.fn(),
txData: {
msgParams: {
from: MOCK_ADDRESS,
data: '0x6c6f63616c686f73743a383038302077616e747320796f7520746f207369676e20696e207769746820796f757220457468657265756d206163636f756e743a0a3078466232433135303034333433393034653566343038323537386334653865313131303563463765330a0a436c69636b20746f207369676e20696e20616e642061636365707420746865205465726d73206f6620536572766963653a2068747470733a2f2f636f6d6d756e6974792e6d6574616d61736b2e696f2f746f730a0a5552493a20687474703a2f2f6c6f63616c686f73743a383038300a56657273696f6e3a20310a436861696e2049443a20310a4e6f6e63653a2053544d74364b514d7777644f58453330360a4973737565642041743a20323032322d30332d31385432313a34303a34302e3832335a0a5265736f75726365733a0a2d20697066733a2f2f516d653773733341525667787636725871565069696b4d4a3875324e4c676d67737a673133705972444b456f69750a2d2068747470733a2f2f6578616d706c652e636f6d2f6d792d776562322d636c61696d2e6a736f6e',
origin: MOCK_ORIGIN,
siwe: {
isSIWEMessage: true,
parsedMessage: {
domain: 'example-dapp.website',
address: MOCK_ADDRESS,
statement:
'Click to sign in and accept the Terms of Service: https://community.metamask.io/tos',
uri: 'http://localhost:8080',
version: '1',
nonce: 'STMt6KQMwwdOXE306',
chainId: 1,
issuedAt: '2023-03-18T21:40:40.823Z',
resources: [
'ipfs://Qme7ss3ARVgxv6rXqVPiikMJ8u2NLgmgszg13pYrDKEoiu',
'https://example.com/my-web2-claim.json',
],
},
},
},
type: MESSAGE_TYPE.PERSONAL_SIGN,
},
};
const render = (txData = mockProps.txData) => {
const store = configureStore(mockStoreInitialState);
return renderWithProvider(
<SignatureRequestSIWE {...mockProps} txData={txData} />,
store,
);
};
describe('SignatureRequestSIWE (Sign in with Ethereum)', () => {
it('should match snapshot', () => {
const { container } = render();
expect(container).toMatchSnapshot();
});
it('should render', async () => {
const { container, findByText } = render();
const bannerAlert = container.querySelector('.mm-banner-alert');
expect(bannerAlert).not.toBeTruthy();
expect(await findByText('Sign-in request')).toBeInTheDocument();
});
it('should render SiteOrigin', () => {
const { container } = render();
const siteOriginElem = container.querySelector('.site-origin');
expect(siteOriginElem).toHaveTextContent(MOCK_ORIGIN);
});
it('should render BannerAlert when addresses do not match', () => {
const store = configureStore(mockStoreInitialState);
const txData = cloneDeep(mockProps.txData);
txData.msgParams.siwe.parsedMessage.address = '0x12345';
const { container } = renderWithProvider(
<SignatureRequestSIWE {...mockProps} txData={txData} />,
store,
);
const bannerAlert = container.querySelector('.mm-banner-alert');
expect(bannerAlert).toBeTruthy();
expect(bannerAlert).toHaveTextContent('does not match the address');
});
it('should render BannerAlert when domains do not match', () => {
const store = configureStore(mockStoreInitialState);
const txData = cloneDeep(mockProps.txData);
txData.msgParams.siwe.parsedMessage.domain = 'potentially-malicious.com';
const { container } = renderWithProvider(
<SignatureRequestSIWE {...mockProps} txData={txData} />,
store,
);
const bannerAlert = container.querySelector('.mm-banner-alert');
expect(bannerAlert).toBeTruthy();
expect(bannerAlert).toHaveTextContent('Deceptive site request.');
});
});

View File

@ -16,6 +16,30 @@ export const typeHash = {
default: '', default: '',
}; };
/**
* @deprecated `<ActionableMessage />` has been deprecated in favour of the `<BannerAlert />`
* component in ./ui/components/component-library/banner-alert/banner-alert.js.
* See storybook documentation for Text here:
* {@see {@link https://metamask.github.io/metamask-storybook/?path=/docs/components-componentlibrary-banneralert--default-story#banneralert}}
*
* Help to replace `ActionableMessage` with `BannerAlert` by submitting a PR
* @param options
* @param options.message
* @param options.primaryAction
* @param options.primaryActionV2
* @param options.secondaryAction
* @param options.className
* @param options.infoTooltipText
* @param options.withRightButton
* @param options.type
* @param options.useIcon
* @param options.icon
* @param options.iconFillColor
* @param options.roundedButtons
* @param options.dataTestId
* @param options.autoHideTime
* @param options.onAutoHide
*/
export default function ActionableMessage({ export default function ActionableMessage({
message = '', message = '',
primaryAction = null, primaryAction = null,