Skip to content

Commit

Permalink
Dynamically lookup the source of a block
Browse files Browse the repository at this point in the history
When a user chooses to dispute a block, we now dynamically lookup the
source of the block instead of getting the dispute URL from the query
parameters. This is in preparation for an extension update that will
necessitate dropping the `newIssueUrl` query parameter we had
previously been relying on.

This is a temporary measure. A future update will restore the source
for each block. At that time we can revert this change.

This should be comparing in exactly the same way as the extension.
The configuration is fetched dynamically so it may be slightly more
up-to-date than what the extension is using.
  • Loading branch information
Gudahtt committed Feb 16, 2023
1 parent c267dbb commit 88f88c1
Show file tree
Hide file tree
Showing 6 changed files with 78 additions and 53 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,12 @@
"dependencies": {
"@metamask/design-tokens": "^1.6.0",
"@metamask/post-message-stream": "^6.0.0",
"@types/punycode": "^2.1.0",
"eth-phishing-detect": "^1.2.0",
"globalthis": "1.0.1",
"obj-multiplex": "^1.0.0",
"pump": "^3.0.0",
"punycode": "^2.1.1",
"ses": "^0.18.1"
},
"devDependencies": {
Expand Down
43 changes: 1 addition & 42 deletions src/index.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,55 +134,14 @@ describe('Phishing warning page', () => {
expect(suspectLink?.innerText).toBe('https://example.com');
});

it('should default to crediting both projects', async () => {
it('should default both projects', async () => {
const detectionRepo = window.document.getElementById('detection-repo');

expect(detectionRepo?.innerHTML).toBe(
'Ethereum Phishing Detector and PhishFort',
);
});

it('should credit Ethereum Phishing Detector when the source is not provided', async () => {
window.document.location.href = getUrl(
'example.com',
'https://example.com',
);
// 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 detectionRepo = window.document.getElementById('detection-repo');

expect(detectionRepo?.innerText).toBe('Ethereum Phishing Detector');
});

it('should credit Ethereum Phishing Detector when the block source is MetaMask', async () => {
window.document.location.href = getUrl(
'example.com',
'https://example.com',
'https://github.com/metamask/eth-phishing-detect/issues/new',
);
// 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 detectionRepo = window.document.getElementById('detection-repo');

expect(detectionRepo?.innerText).toBe('Ethereum Phishing Detector');
});

it('should credit PhishFort when the block source is PhishFort', async () => {
window.document.location.href = getUrl(
'example.com',
'https://example.com',
'https://github.com/phishfort/phishfort-lists/issues/new',
);
// 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 detectionRepo = window.document.getElementById('detection-repo');

expect(detectionRepo?.innerText).toBe('PhishFort');
});

it.todo(
'should add site to safelist when the user continues at their own risk',
);
Expand Down
63 changes: 53 additions & 10 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import pump from 'pump';
import { toASCII } from 'punycode/';
import PhishingDetector from 'eth-phishing-detect/src/detector';
import { WindowPostMessageStream } from '@metamask/post-message-stream';
import ObjectMultiplex from 'obj-multiplex';

Expand Down Expand Up @@ -91,6 +93,51 @@ function isValidSuspectHref(href: string) {
return disallowedProtocols.indexOf(parsedSuspectHref.protocol) < 0;
}

const newIssueUrls = {
metamask: 'https://github.com/MetaMask/eth-phishing-detect/issues/new',
phishfort: 'https://github.com/phishfort/phishfort-lists/issues/new',
};

const metamaskConfigUrl =
'https://raw.githubusercontent.com/MetaMask/eth-phishing-detect/master/src/config.json';

/**
* Determines whether the given URL was blocked by our phishing configuration or not.
*
* @param href - The blocked URL.
* @returns `true` if this URL is blocked by our phishing configuration, `false` otherwise.
*/
async function isBlockedByMetamask(href: string) {
try {
const response = await fetch(metamaskConfigUrl, { cache: 'no-cache' });
if (!response.ok) {
throw new Error(`Received non-200 response: ${response.status}`);
}
const config = await response.json();
const detector = new PhishingDetector([
{
allowlist: config.whitelist,
blocklist: config.blacklist,
fuzzylist: config.fuzzylist,
tolerance: config.tolerance,
name: 'MetaMask',
version: config.version,
},
]);
const { hostname } = new URL(href);

const punycodeHostname = toASCII(hostname);
const phishingTestResponse = detector.check(punycodeHostname);
console.debug('Phishing config test results:', phishingTestResponse);

return phishingTestResponse.result;
} catch (error) {
console.error(error);
// default to assuming that it is blocked by our configuration
return true;
}
}

/**
* Initialize the phishing warning page streams.
*/
Expand Down Expand Up @@ -135,20 +182,16 @@ function start() {
throw new Error('Unable to locate detection repo span');
}

const newIssueUrl =
hashQueryString.get('newIssueUrl') ||
`https://github.com/MetaMask/eth-phishing-detect/issues/new`;
const newIssueParams = `?title=[Legitimate%20Site%20Blocked]%20${encodeURIComponent(
suspectHostname,
)}&body=${encodeURIComponent(suspectHref)}`;
newIssueLink.setAttribute('href', `${newIssueUrl}${newIssueParams}`);

const blockedByMetamask = newIssueUrl.includes('eth-phishing-detect');
if (blockedByMetamask) {
detectionRepo.innerText = 'Ethereum Phishing Detector';
} else {
detectionRepo.innerText = 'PhishFort';
}
newIssueLink.addEventListener('click', async () => {
const listName = (await isBlockedByMetamask(suspectHref))
? 'metamask'
: 'phishfort';
window.location.href = `${newIssueUrls[listName]}${newIssueParams}`;
});

const continueLink = document.getElementById('unsafe-continue');
if (!continueLink) {
Expand Down
2 changes: 1 addition & 1 deletion static/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ <h1>
<p>Advisory provided by <span id="detection-repo">Ethereum Phishing Detector and PhishFort</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 we're flagging a legitimate website, please <a id="new-issue-link" href="#">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>
Expand Down
1 change: 1 addition & 0 deletions types/eth-phishing-detect/src/detector.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
declare module 'eth-phishing-detect/src/detector';
19 changes: 19 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2108,6 +2108,7 @@ __metadata:
"@types/jest": ^26.0.13
"@types/node": ^17.0.23
"@types/pump": ^1.1.1
"@types/punycode": ^2.1.0
"@types/readable-stream": ^2.3.13
"@typescript-eslint/eslint-plugin": ^4.33.0
"@typescript-eslint/parser": ^4.33.0
Expand All @@ -2120,6 +2121,7 @@ __metadata:
eslint-plugin-jsdoc: ^36.1.0
eslint-plugin-node: ^11.1.0
eslint-plugin-prettier: ^3.4.1
eth-phishing-detect: ^1.2.0
exorcist: ^2.0.0
fs-extra: ^10.1.0
globalthis: 1.0.1
Expand All @@ -2130,6 +2132,7 @@ __metadata:
prettier: ^2.6.2
prettier-plugin-packagejson: ^2.2.17
pump: ^3.0.0
punycode: ^2.1.1
ses: ^0.18.1
terser: ^5.13.1
ts-jest: ^28.0.1
Expand Down Expand Up @@ -2600,6 +2603,13 @@ __metadata:
languageName: node
linkType: hard

"@types/punycode@npm:^2.1.0":
version: 2.1.0
resolution: "@types/punycode@npm:2.1.0"
checksum: 6835698becab395eb9ac186970fd7879aeb522ea72d516ef9d681d787989653fcc2439ecc07d48280e1ca11862773b806efeec3fdbd1207528829a83b65d4275
languageName: node
linkType: hard

"@types/readable-stream@npm:^2.3.13":
version: 2.3.13
resolution: "@types/readable-stream@npm:2.3.13"
Expand Down Expand Up @@ -5030,6 +5040,15 @@ __metadata:
languageName: node
linkType: hard

"eth-phishing-detect@npm:^1.2.0":
version: 1.2.0
resolution: "eth-phishing-detect@npm:1.2.0"
dependencies:
fast-levenshtein: ^2.0.6
checksum: 66a6a7c249ec8494e0360663596ce980ca75747cd202c47732eca0bfc7a97c6debbae359842e4f3e4ac7e6c44ab1f7f091c3aa7baa330449d3c1b7cc58608b71
languageName: node
linkType: hard

"events@npm:^3.0.0":
version: 3.3.0
resolution: "events@npm:3.3.0"
Expand Down

0 comments on commit 88f88c1

Please sign in to comment.