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

New design for phishing warning page #52

Merged
53 changes: 19 additions & 34 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,16 +71,7 @@ describe('Phishing warning page', () => {

it('should render page', async () => {
const container = window.document.getElementsByTagName('body')[0];
expect(
queryByText(container, 'MetaMask Phishing Detection'),
).not.toBeNull();
});

it('should have correct default "New issue" link', () => {
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
const newIssueLink = window.document.getElementById('new-issue-link');
expect(newIssueLink?.getAttribute('href')).toBe(
'https://github.com/metamask/eth-phishing-detect/issues/new',
);
expect(queryByText(container, 'Deceptive site ahead')).not.toBeNull();
});

it('should correctly construct "New issue" link', async () => {
Expand Down Expand Up @@ -120,30 +111,6 @@ describe('Phishing warning page', () => {
'should add site to safelist when the user continues at their own risk',
);

it.todo(
'should redirect to the site after the user continues at their own risk',
);

it('should show a different message if the URL contains an unsupported protocol', async () => {
window.document.location.href = getUrl(
'example.com',
// eslint-disable-next-line no-script-url
'javascript:alert("example")',
);

await import('./index');
// non-null assertion used because TypeScript doesn't know the event handler was run
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
onDomContentLoad!(new Event('DOMContentLoaded'));

const redirectWarningMessage = window.document.getElementById(
'redirect-warning-message',
);
expect(redirectWarningMessage?.innerText).toBe(
"This URL does not use a supported protocol so we won't give you the option to skip this warning.",
);
});

it('should throw an error if the hostname is missing', async () => {
window.document.location.href = getUrl(undefined, 'https://example.com');

Expand Down Expand Up @@ -199,4 +166,22 @@ describe('Phishing warning page', () => {
'Unable to locate unsafe continue link',
);
});

it('should redirect when continue to the site is clicked', async () => {
window.document.location.href = getUrl(
'example.com',
'https://example.com',
);

await import('./index');
// non-null assertion used because TypeScript doesn't know the event handler was run
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
onDomContentLoad!(new Event('DOMContentLoaded'));

const continueLink = document.getElementById('unsafe-continue');

continueLink?.click();

expect(global.window.location.href).toContain('example.com');
});
});
10 changes: 0 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,16 +137,6 @@ function start() {
throw new Error('Unable to locate unsafe continue link');
}

if (isValidSuspectHref(suspectHref) === false) {
Gudahtt marked this conversation as resolved.
Show resolved Hide resolved
const redirectWarningMessage = document.getElementById(
'redirect-warning-message',
);
if (redirectWarningMessage) {
redirectWarningMessage.innerHTML = `<br />`;
redirectWarningMessage.innerText = `This URL does not use a supported protocol so we won't give you the option to skip this warning.`;
}
}

continueLink.addEventListener('click', async () => {
if (isValidSuspectHref(suspectHref) === false) {
console.log(`Disallowed Protocol, cannot continue.`);
Expand Down
145 changes: 106 additions & 39 deletions static/index.css
Original file line number Diff line number Diff line change
Expand Up @@ -25,74 +25,141 @@
box-sizing: border-box;
}

html {
height: 100%;
}

body {
background-color: var(--color-error-alternative);
height: 100%;
display: flex;
justify-content: center;
align-items: center;
width: 100vw;
height: 100vh;
justify-content: center;
font-family: var(--typography-s-body-md-font-family);
font-weight: var(--typography-s-body-md-font-weight);
font-size: var(--typography-s-body-md-font-size);
line-height: var(--typography-s-body-md-line-height);
letter-spacing: var(--typography-s-body-md-letter-spacing);
color: var(--color-error-inverse);
}

@media screen and (min-width: 768px) {
body {
font-family: var(--typography-l-body-md-font-family);
font-weight: var(--typography-l-body-md-font-weight);
font-size: var(--typography-l-body-md-font-size);
line-height: var(--typography-l-body-md-line-height);
letter-spacing: var(--typography-l-body-md-letter-spacing);
}
}

background-color: var(--color-error-default);
font-family: Euclid, Roboto, Helvetica, Arial, sans-serif;
.heading-lg {
font-family: var(--typography-s-heading-lg-font-family);
font-weight: var(--typography-s-heading-lg-font-weight);
font-size: var(--typography-s-heading-lg-font-size);
line-height: var(--typography-s-heading-lg-line-height);
letter-spacing: var(--typography-s-heading-lg-letter-spacing);
}

p {
margin: 2em;
@media screen and (min-width: 768px) {
.heading-lg {
font-family: var(--typography-l-heading-lg-font-family);
font-weight: var(--typography-l-heading-lg-font-weight);
font-size: var(--typography-l-heading-lg-font-size);
line-height: var(--typography-l-heading-lg-line-height);
letter-spacing: var(--typography-l-heading-lg-letter-spacing);
}
}

p a {
a {
text-decoration: underline;
color: var(--color-error-inverse);
cursor: pointer;
}

ul {
padding-left: 32px;
}

.button-secondary {
color: var(--color-primary-default);
background: var(--color-background-default);
border: 1px solid var(--color-primary-default);
padding-right: 16px;
padding-left: 16px;
border-radius: 9999px;
height: 48px;
display: flex;
align-items: center;
margin-top: 48px;
font-family: var(--typography-s-body-md-font-family);
font-weight: var(--typography-s-body-md-font-weight);
font-size: var(--typography-s-body-md-font-size);
line-height: var(--typography-s-body-md-line-height);
letter-spacing: var(--typography-s-body-md-letter-spacing);
cursor: pointer;
margin-left: auto;
}

@media screen and (min-width: 768px) {
.button-secondary {
font-family: var(--typography-l-body-md-font-family);
font-weight: var(--typography-l-body-md-font-weight);
font-size: var(--typography-l-body-md-font-size);
line-height: var(--typography-l-body-md-line-height);
letter-spacing: var(--typography-l-body-md-letter-spacing);
}
}

.button-secondary:hover {
color: var(--color-primary-inverse);
background-color: var(--color-primary-default);
box-shadow: var(--component-button-primary-shadow);
}

.button-secondary:active {
color: var(--color-primary-inverse);
background-color: var(--color-primary-alternative);
border-color: var(--color-primary-alternative);
}

.content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 80%;
background-color: var(--color-background-default);
box-shadow: 0 0 15px var(--brand-colors-grey-grey500);
max-width: 700px;
padding: 24px;
}

.content__header {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 100%;
color: var(--color-error-default);
border-bottom: 1px solid var(--color-border-default);
padding: 2em;
margin-bottom: 16px;
}

.content__header h1 {
font-size: 1.5rem;
font-weight: normal;
}

.content__header h1 svg {
margin-right: 0.25em;
fill: var(--color-error-default);
width: 1em;
height: 1em;
vertical-align: middle;
}

.content__header img {
margin-bottom: 3em;
width: 130px;
font-family: var(--typography-s-heading-lg-font-family);
font-weight: var(--typography-s-heading-lg-font-weight);
font-size: var(--typography-s-heading-lg-font-size);
line-height: var(--typography-s-heading-lg-line-height);
letter-spacing: var(--typography-s-heading-lg-letter-spacing);
}

.content__body {
background-color: var(--color-background-alternative);
font-size: 1rem;
color: var(--color-text-default);
@media screen and (min-width: 768px) {
.content__header h1 {
font-family: var(--typography-l-heading-lg-font-family);
font-weight: var(--typography-l-heading-lg-font-weight);
font-size: var(--typography-l-heading-lg-font-size);
line-height: var(--typography-l-heading-lg-line-height);
letter-spacing: var(--typography-l-heading-lg-letter-spacing);
}
}

.content__framed-body {
background-color: var(--color-background-alternative);
font-size: 1rem;
color: var(--color-text-default);
.content__header svg {
fill: var(--color-error-inverse);
width: 64px;
height: 64px;
margin-bottom: 24px;
}
84 changes: 30 additions & 54 deletions static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,17 @@
document.getElementById('antiClickjack').innerHTML =
'#content__framed-body { display: none !important; }';
}

window.onload = function() {
document.getElementById("suspect-link").innerText = document.referrer;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: Could you move this code to the start function in src/index.ts? That is where all of our other "page initialization" code is.

if((window.location.href).includes('eth-phishing-detect')){
document.getElementById("detection-repo").innerText = 'Ethereum Phishing Detector';
}
if((window.location.href).includes('phishfort-lists')){
document.getElementById("detection-repo").innerText = 'PhishFort';
}

}
</script>
<title>MetaMask Phishing Detection</title>
<script
Expand Down Expand Up @@ -46,67 +57,32 @@
<body>
<div class="content">
<div class="content__header">
<img src="./metamask-fox.svg" alt="MetaMask Logo" />
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Pro 6.2.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) Copyright 2022 Fonticons, Inc. -->
<path d="M256 32c14.2 0 27.3 7.5 34.5 19.8l216 368c7.3 12.4 7.3 27.7 .2 40.1S486.3 480 472 480H40c-14.3 0-27.6-7.7-34.7-20.1s-7-27.8 .2-40.1l216-368C228.7 39.5 241.8 32 256 32zm0 128c-13.3 0-24 10.7-24 24V296c0 13.3 10.7 24 24 24s24-10.7 24-24V184c0-13.3-10.7-24-24-24zm32 224c0-17.7-14.3-32-32-32s-32 14.3-32 32s14.3 32 32 32s32-14.3 32-32z"/>
</svg>
<h1>
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" preserveAspectRatio="xMidYMid meet"><!-- Font Awesome Pro 5.15.4 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license (Commercial License) --><path d="M504 256c0 136.997-111.043 248-248 248S8 392.997 8 256C8 119.083 119.043 8 256 8s248 111.083 248 248zm-248 50c-25.405 0-46 20.595-46 46s20.595 46 46 46 46-20.595 46-46-20.595-46-46-46zm-43.673-165.346l7.418 136c.347 6.364 5.609 11.346 11.982 11.346h48.546c6.373 0 11.635-4.982 11.982-11.346l7.418-136c.375-6.874-5.098-12.654-11.982-12.654h-63.383c-6.884 0-12.356 5.78-11.981 12.654z"/></svg>
MetaMask Phishing Detection
Deceptive site ahead
</h1>
</div>
<div id="content__body" class="content__body">
<p>
This domain is currently on the MetaMask domain warning list. This
means that based on information available to us, MetaMask believes
this domain could currently compromise your security and, as an added
safety feature, MetaMask has restricted access to the site. To
override this, please read the rest of this warning for instructions
on how to continue at your own risk.
</p>
<p>
There are many reasons sites can appear on our warning list, and our
warning list compiles from other widely used industry lists. Such
reasons can include known fraud or security risks, such as domains
that test positive on the
<a href="https://github.com/metamask/eth-phishing-detect"
>Ethereum Phishing Detector</a
>. Domains on these warning lists may include outright malicious
websites and legitimate websites that have been compromised by a
malicious actor.
</p>
<p>
To read more about this site
<a id="csdbLink" href="https://cryptoscamdb.org/search"
>please search for the domain on CryptoScamDB</a
>.
</p>
<p>
Note that this warning list is compiled on a voluntary basis. This
list may be inaccurate or incomplete. Just because a domain does not
appear on this list is not an implicit guarantee of that domain's
safety. As always, your transactions are your own responsibility. <span id="redirect-warning-message">If
you wish to interact with any domain on our warning list, you can do
so by <a id="unsafe-continue">continuing at your own risk</a>.</span>
MetaMask flagged the site you're trying to visit as potentially deceptive. Attackers may trick you into doing something dangerous. <a id="csdbLink" rel="noopener" href='https://cryptoscamdb.org/search' target='_blank'>Learn more</a>
</p>
<p>
If you think this domain is incorrectly flagged or if a blocked
legitimate website has resolved its security issues,
<a
id="new-issue-link"
href="https://github.com/metamask/eth-phishing-detect/issues/new"
>please file an issue</a
>.
</p>
</div>
<div id="content__framed-body" class="content__framed-body">
<p>
This domain is currently on the MetaMask domain warning list. This
means that based on information available to us, MetaMask believes
this domain could currently compromise your security and, as an added
safety feature, MetaMask has restricted access to the site.
</p>
<p>
<a id="open-self-in-new-tab" target="_blank">Open this warning in a new tab</a> for more information
on why this domain is blocked, and how to continue at your own risk.
</br>
<p>Potential threats on <span id="suspect-link"></span> include:
<ul>
<li>Fake versions of MetaMask</li>
<li>Secret Recovery Phrase or password theft</li>
<li>Malicious transactions resulting in stolen assets </li>
</ul>
</p>
</br>
<p>Advisory provided by <span id="detection-repo"></span>.</p>
</br>
</br>
<p>If we're flagging a legitimate website, please <a id="new-issue-link" rel="noopener" target='_blank' href="https://github.com/metamask/eth-phishing-detect/issues/new">report a detection problem.</a></p>
<p>If you understand the risks and still want to proceed, you can <a id="unsafe-continue">continue to the site.</a></p>
<button class="button-secondary" type="submit" onclick="window.close()">Back to safety</button>
</div>
</div>
</body>
Expand Down