Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Blockaid / PPOM Failed Request Security Alert #20362

Merged
merged 10 commits into from
Aug 14, 2023
6 changes: 6 additions & 0 deletions app/_locales/en/messages.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion shared/constants/security-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export enum BlockaidReason {
other = 'other',

// Locally defined
notApplicable = 'NotApplicable',
failed = 'Failed',
notApplicable = 'NotApplicable',
}

export enum BlockaidResultType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ exports[`Security Provider Banner Alert should match snapshot 1`] = `
</details>
</div>
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-2 mm-box--align-items-center mm-box--color-text-alternative"
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-3 mm-box--display-flex mm-box--align-items-center mm-box--color-text-alternative"
>
<span
class="mm-box disclosure__summary--icon mm-icon mm-icon--size-sm mm-box--margin-inline-end-1 mm-box--display-inline-block mm-box--color-primary-default"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo
If you approve this request, a third party known for scams might take all your assets.
</p>
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-2 mm-box--align-items-center mm-box--color-text-alternative"
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-3 mm-box--display-flex mm-box--align-items-center mm-box--color-text-alternative"
>
<span
class="mm-box disclosure__summary--icon mm-icon mm-icon--size-sm mm-box--margin-inline-end-1 mm-box--display-inline-block mm-box--color-primary-default"
Expand All @@ -46,6 +46,30 @@ exports[`Blockaid Banner Alert should render 'danger' UI when securityAlertRespo
</div>
`;

exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResponse.result_type is 'Failed 1`] = `
<div
class="box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning box--margin-4 box--padding-3 box--padding-left-2 box--display-flex box--gap-2 box--flex-direction-row box--background-color-warning-muted box--rounded-sm"
>
<span
class="mm-box mm-icon mm-icon--size-lg mm-box--display-inline-block mm-box--color-warning-default"
style="mask-image: url('./images/icons/warning.svg');"
/>
<div>
<h5
class="mm-box mm-text mm-banner-base__title mm-text--body-lg-medium mm-box--color-text-default"
data-testid="mm-banner-base-title"
>
This is a deceptive request
</h5>
<p
class="mm-box mm-text mm-text--body-md mm-box--margin-top-2 mm-box--color-text-default"
>
If you approve this request, a third party known for scams might take all your assets.
</p>
</div>
</div>
`;

exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResponse.result_type is 'Warning 1`] = `
<div
class="box mm-banner-base mm-banner-alert mm-banner-alert--severity-warning box--margin-4 box--padding-3 box--padding-left-2 box--display-flex box--gap-2 box--flex-direction-row box--background-color-warning-muted box--rounded-sm"
Expand All @@ -67,7 +91,7 @@ exports[`Blockaid Banner Alert should render 'warning' UI when securityAlertResp
If you approve this request, a third party known for scams might take all your assets.
</p>
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-2 mm-box--align-items-center mm-box--color-text-alternative"
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-3 mm-box--display-flex mm-box--align-items-center mm-box--color-text-alternative"
>
<span
class="mm-box disclosure__summary--icon mm-icon mm-icon--size-sm mm-box--margin-inline-end-1 mm-box--display-inline-block mm-box--color-primary-default"
Expand Down Expand Up @@ -152,7 +176,7 @@ exports[`Blockaid Banner Alert should render details when provided 1`] = `
</details>
</div>
<p
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-2 mm-box--align-items-center mm-box--color-text-alternative"
class="mm-box mm-text mm-text--body-sm mm-box--margin-top-3 mm-box--display-flex mm-box--align-items-center mm-box--color-text-alternative"
>
<span
class="mm-box disclosure__summary--icon mm-icon mm-icon--size-sm mm-box--margin-inline-end-1 mm-box--display-inline-block mm-box--color-primary-default"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ const REASON_TO_DESCRIPTION_TKEY = Object.freeze({

[BlockaidReason.blurFarming]: 'blockaidDescriptionBlurFarming',

[BlockaidReason.failed]: 'blockaidDescriptionFailed',

[BlockaidReason.seaportFarming]: 'blockaidDescriptionSeaportFarming',

[BlockaidReason.maliciousDomain]: 'blockaidDescriptionMaliciousDomain',
Expand All @@ -36,8 +38,11 @@ const REASON_TO_DESCRIPTION_TKEY = Object.freeze({
[BlockaidReason.other]: 'blockaidDescriptionMightLoseAssets',
});

/** List of suspicious reason(s). Other reasons will be deemed as deceptive. */
const SUSPCIOUS_REASON = [BlockaidReason.rawSignatureFarming];
/** Reason to title translation key mapping. */
const REASON_TO_TITLE_TKEY = Object.freeze({
[BlockaidReason.failed]: 'blockaidTitleMayNotBeSafe',
[BlockaidReason.rawSignatureFarming]: 'blockaidTitleSuspicious',
});

function BlockaidBannerAlert({ securityAlertResponse }) {
const t = useContext(I18nContext);
Expand All @@ -48,10 +53,7 @@ function BlockaidBannerAlert({ securityAlertResponse }) {

const { reason, result_type: resultType, features } = securityAlertResponse;

if (
resultType === BlockaidResultType.Benign ||
resultType === BlockaidResultType.Failed
) {
if (resultType === BlockaidResultType.Benign) {
return null;
}

Expand All @@ -69,21 +71,20 @@ function BlockaidBannerAlert({ securityAlertResponse }) {
</Text>
);

const isFailedResultType = resultType === BlockaidResultType.Failed;

const severity =
resultType === BlockaidResultType.Malicious
? Severity.Danger
: Severity.Warning;

const title =
SUSPCIOUS_REASON.indexOf(reason) > -1
? t('blockaidTitleSuspicious')
: t('blockaidTitleDeceptive');
const title = t(REASON_TO_TITLE_TKEY[reason] || 'blockaidTitleDeceptive');

return (
<SecurityProviderBannerAlert
description={description}
details={details}
provider={SecurityProvider.Blockaid}
provider={isFailedResultType ? null : SecurityProvider.Blockaid}
severity={severity}
title={title}
/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ describe('Blockaid Banner Alert', () => {
expect(container.querySelector('.mm-banner-alert')).toBeNull();
});

it(`should not render when securityAlertResponse.result_type is '${BlockaidResultType.Failed}'`, () => {
it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Failed}`, () => {
const { container } = renderWithLocalization(
<BlockaidBannerAlert
securityAlertResponse={{
Expand All @@ -49,8 +49,24 @@ describe('Blockaid Banner Alert', () => {
}}
/>,
);
const warningBannerAlert = container.querySelector(
'.mm-banner-alert--severity-warning',
);

expect(container.querySelector('.mm-banner-alert')).toBeNull();
expect(warningBannerAlert).toBeInTheDocument();
expect(warningBannerAlert).toMatchSnapshot();
});

it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Warning}`, () => {
const { container } = renderWithLocalization(
<BlockaidBannerAlert securityAlertResponse={mockSecurityAlertResponse} />,
);
const warningBannerAlert = container.querySelector(
'.mm-banner-alert--severity-warning',
);

expect(warningBannerAlert).toBeInTheDocument();
expect(warningBannerAlert).toMatchSnapshot();
});

it(`should render '${Severity.Danger}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Malicious}`, () => {
Expand All @@ -70,27 +86,28 @@ describe('Blockaid Banner Alert', () => {
expect(dangerBannerAlert).toMatchSnapshot();
});

it(`should render '${Severity.Warning}' UI when securityAlertResponse.result_type is '${BlockaidResultType.Warning}`, () => {
const { container } = renderWithLocalization(
it('should render title, "This is a deceptive request"', () => {
const { getByText } = renderWithLocalization(
<BlockaidBannerAlert securityAlertResponse={mockSecurityAlertResponse} />,
);
const warningBannerAlert = container.querySelector(
'.mm-banner-alert--severity-warning',
);

expect(warningBannerAlert).toBeInTheDocument();
expect(warningBannerAlert).toMatchSnapshot();
expect(getByText('This is a deceptive request')).toBeInTheDocument();
});

it('should render title, "This is a deceptive request"', () => {
it(`should render title, "This is a suspicious request", when the reason is "${BlockaidReason.failed}"`, () => {
const { getByText } = renderWithLocalization(
<BlockaidBannerAlert securityAlertResponse={mockSecurityAlertResponse} />,
<BlockaidBannerAlert
securityAlertResponse={{
...mockSecurityAlertResponse,
reason: BlockaidReason.failed,
}}
/>,
);

expect(getByText('This is a deceptive request')).toBeInTheDocument();
expect(getByText('Request may not be safe')).toBeInTheDocument();
});

it('should render title, "This is a suspicious request", when the reason is "raw_signature_farming"', () => {
it(`should render title, "This is a suspicious request", when the reason is "${BlockaidReason.rawSignatureFarming}"`, () => {
const { getByText } = renderWithLocalization(
<BlockaidBannerAlert
securityAlertResponse={{
Expand Down Expand Up @@ -131,6 +148,8 @@ describe('Blockaid Banner Alert', () => {
'If you approve this request, a third party known for scams might take all your assets.',
[BlockaidReason.blurFarming]:
'If you approve this request, someone can steal your assets listed on Blur.',
[BlockaidReason.failed]:
'Because of an error, this request was not verified by the security provider. Proceed with caution.',
[BlockaidReason.maliciousDomain]:
"You're interacting with a malicious domain. If you approve this request, you might lose your assets.",
[BlockaidReason.other]:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import { I18nContext } from '../../../contexts/i18n';
import {
AlignItems,
Color,
Display,
IconColor,
Severity,
Size,
Expand Down Expand Up @@ -45,30 +46,33 @@ function SecurityProviderBannerAlert({
</Disclosure>
)}

<Text
marginTop={2}
alignItems={AlignItems.center}
color={Color.textAlternative}
variant={TextVariant.bodySm}
>
<Icon
className="disclosure__summary--icon"
color={IconColor.primaryDefault}
name={IconName.SecurityTick}
size={IconSize.Sm}
marginInlineEnd={1}
/>
{t('securityProviderAdviceBy', [
<ButtonLink
key={`security-provider-button-link-${provider}`}
size={Size.inherit}
href={SECURITY_PROVIDER_CONFIG[provider].url}
externalLink
>
{t(SECURITY_PROVIDER_CONFIG[provider].tKeyName)}
</ButtonLink>,
])}
</Text>
{provider && (
<Text
marginTop={3}
display={Display.Flex}
alignItems={AlignItems.center}
color={Color.textAlternative}
variant={TextVariant.bodySm}
>
<Icon
className="disclosure__summary--icon"
color={IconColor.primaryDefault}
name={IconName.SecurityTick}
size={IconSize.Sm}
marginInlineEnd={1}
/>
{t('securityProviderAdviceBy', [
<ButtonLink
key={`security-provider-button-link-${provider}`}
size={Size.inherit}
href={SECURITY_PROVIDER_CONFIG[provider].url}
externalLink
>
{t(SECURITY_PROVIDER_CONFIG[provider].tKeyName)}
</ButtonLink>,
])}
</Text>
)}
</BannerAlert>
);
}
Expand All @@ -78,9 +82,6 @@ SecurityProviderBannerAlert.propTypes = {
description: PropTypes.oneOfType([PropTypes.string, PropTypes.element])
.isRequired,

/** Name of the security provider */
provider: PropTypes.oneOfType(Object.values(SecurityProvider)).isRequired,

/** Severity level */
severity: PropTypes.oneOfType([Severity.Danger, Severity.Warning]).isRequired,

Expand All @@ -93,6 +94,9 @@ SecurityProviderBannerAlert.propTypes = {

/** Additional details to be displayed under the description */
details: PropTypes.oneOfType([PropTypes.string, PropTypes.element]),

/** Name of the security provider */
provider: PropTypes.oneOfType(Object.values(SecurityProvider)),
};

export default SecurityProviderBannerAlert;
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,10 @@ export default {
control: {
type: 'select',
},
options: [Object.values(SecurityProvider)],
options: ['none', ...Object.values(SecurityProvider)],
mapping: {
none: null,
},
},
severity: {
control: {
Expand Down
Loading