diff --git a/.gitignore b/.gitignore index 726cb4c..61d0399 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,7 @@ .DS_Store dist/ coverage/ - +.vscode/ # Logs logs *.log diff --git a/src/index.ts b/src/index.ts index 674ee08..31c0b56 100644 --- a/src/index.ts +++ b/src/index.ts @@ -138,6 +138,29 @@ async function isBlockedByMetamask(href: string) { } } +/** + * Extract hostname and href from the query string. + * + * @returns The suspect hostname and href from the query string. + * @param href - The href value to check. + */ +function getSuspect(href = ''): { + suspectHostname: string; + suspectHref: string; + suspectHrefPlain: string; +} { + try { + const url = new URL(href); + return { + suspectHostname: url.hostname, + suspectHref: url.href, + suspectHrefPlain: href, + }; + } catch (error) { + throw new Error(`Invalid 'href' query parameter`); + } +} + /** * Initialize the phishing warning page streams. */ @@ -154,17 +177,27 @@ function start() { ]); const phishingSafelistStream = mux.createStream('metamask-phishing-safelist'); + const backToSafetyLink = document.getElementById('back-to-safety'); + if (!backToSafetyLink) { + throw new Error('Unable to locate back to safety link'); + } + + backToSafetyLink.addEventListener('click', async () => { + phishingSafelistStream.write({ + jsonrpc: '2.0', + method: 'backToSafetyPhishingWarning', + params: [], + id: createRandomId(), + }); + }); + const { hash } = new URL(window.location.href); const hashContents = hash.slice(1); // drop leading '#' from hash const hashQueryString = new URLSearchParams(hashContents); - const suspectHostname = hashQueryString.get('hostname'); - const suspectHref = hashQueryString.get('href'); - if (!suspectHostname) { - throw new Error("Missing 'hostname' query parameter"); - } else if (!suspectHref) { - throw new Error("Missing 'href' query parameter"); - } + const { suspectHostname, suspectHref, suspectHrefPlain } = getSuspect( + hashQueryString.get('href'), + ); const suspectLink = document.getElementById('suspect-link'); if (!suspectLink) { @@ -178,8 +211,8 @@ function start() { } const newIssueParams = `?title=[Legitimate%20Site%20Blocked]%20${encodeURIComponent( - suspectHostname, - )}&body=${encodeURIComponent(suspectHref)}`; + suspectHrefPlain, + )}&body=${encodeURIComponent(suspectHrefPlain)}`; newIssueLink.addEventListener('click', async () => { const listName = (await isBlockedByMetamask(suspectHref)) @@ -208,18 +241,4 @@ function start() { window.location.href = suspectHref; }); - - const backToSafetyLink = document.getElementById('back-to-safety'); - if (!backToSafetyLink) { - throw new Error('Unable to locate back to safety link'); - } - - backToSafetyLink.addEventListener('click', async () => { - phishingSafelistStream.write({ - jsonrpc: '2.0', - method: 'backToSafetyPhishingWarning', - params: [], - id: createRandomId(), - }); - }); } diff --git a/tests/bypass.spec.ts b/tests/bypass.spec.ts index c3a8314..ea19a59 100644 --- a/tests/bypass.spec.ts +++ b/tests/bypass.spec.ts @@ -11,7 +11,6 @@ test('allows the user to bypass the warning and add the site to the allowlist', }) => { const postMessageLogs = await setupStreamInitialization(page); const querystring = new URLSearchParams({ - hostname: 'test.com', href: 'https://test.com', }); await page.goto(`/#${querystring}`); diff --git a/tests/defaults.spec.ts b/tests/defaults.spec.ts index fafe7a9..19ffd0f 100644 --- a/tests/defaults.spec.ts +++ b/tests/defaults.spec.ts @@ -58,7 +58,6 @@ test('does nothing when the user tries to bypass the warning', async ({ test('redirects when the user clicks "Back to safety"', async ({ page }) => { const postMessageLogs = await setupStreamInitialization(page); const querystring = new URLSearchParams({ - hostname: 'test.com', href: 'https://test.com', }); await page.goto(`/#${querystring}`); diff --git a/tests/failed-lookup.spec.ts b/tests/failed-lookup.spec.ts index a4b8bf2..421ee6c 100644 --- a/tests/failed-lookup.spec.ts +++ b/tests/failed-lookup.spec.ts @@ -7,7 +7,6 @@ test('directs users to eth-phishing-detect to dispute a block, including issue t }) => { await setupDefaultMocks(context, { phishingError: true }); const querystring = new URLSearchParams({ - hostname: 'test.com', href: 'https://test.com', }); await page.goto(`/#${querystring}`); @@ -17,6 +16,6 @@ test('directs users to eth-phishing-detect to dispute a block, including issue t await page.waitForLoadState('networkidle'); await expect(page).toHaveURL( - 'https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20test.com&body=https%3A%2F%2Ftest.com', + 'https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20https%3A%2F%2Ftest.com&body=https%3A%2F%2Ftest.com', ); }); diff --git a/tests/iframe.spec.ts b/tests/iframe.spec.ts index 8bcfb6c..03f0ca9 100644 --- a/tests/iframe.spec.ts +++ b/tests/iframe.spec.ts @@ -21,7 +21,6 @@ function getPageWithIframe(url?: string) { } const validQueryParams = new URLSearchParams({ - hostname: 'test.com', href: 'https://test.com', }); @@ -63,7 +62,7 @@ test('only shows one link, which is to open the same warning in a new tab', asyn ); expect(hrefs).toStrictEqual([ - 'http://localhost:8080/#hostname=test.com&href=https%3A%2F%2Ftest.com', + 'http://localhost:8080/#href=https%3A%2F%2Ftest.com', ]); }); diff --git a/tests/invalid-inputs.spec.ts b/tests/invalid-inputs.spec.ts index a760307..8cc6a5a 100644 --- a/tests/invalid-inputs.spec.ts +++ b/tests/invalid-inputs.spec.ts @@ -6,7 +6,7 @@ test.beforeEach(async ({ context }) => { await setupDefaultMocks(context); }); -test('throws an error about the hostname query parameter being missing', async ({ +test('throws an error about the href query parameter being invalid', async ({ context, page, }) => { @@ -16,29 +16,7 @@ test('throws an error about the hostname query parameter being missing', async ( errorLogs.push(message.text()); } }); - - await page.goto('/'); - - expect(errorLogs.length).toBe(1); - const browserName = context.browser()?.browserType().name(); - expect(errorLogs[0]).toMatch( - browserName === 'firefox' - ? 'Error' // for some reason the message is missing on Firefox - : `Error: Missing 'hostname' query parameter`, - ); -}); - -test('throws an error about the href query parameter being missing', async ({ - context, - page, -}) => { - const errorLogs: string[] = []; - page.on('console', (message) => { - if (message.type() === 'error') { - errorLogs.push(message.text()); - } - }); - const querystring = new URLSearchParams({ hostname: 'example.com' }); + const querystring = new URLSearchParams({}); await page.goto(`/#${querystring}`); @@ -47,7 +25,7 @@ test('throws an error about the href query parameter being missing', async ({ expect(errorLogs[0]).toMatch( browserName === 'firefox' ? 'Error' // for some reason the message is missing on Firefox - : `Error: Missing 'href' query parameter`, + : `Error: Invalid 'href' query parameter`, ); }); @@ -72,7 +50,6 @@ test('does not allow user to bypass warning for invalid protocols', async ({ } }); const querystring = new URLSearchParams({ - hostname: 'evil.com', // eslint-disable-next-line no-script-url href: 'javascript:console.log("test")', }); diff --git a/tests/metamask-block.spec.ts b/tests/metamask-block.spec.ts index 70385b0..9db8560 100644 --- a/tests/metamask-block.spec.ts +++ b/tests/metamask-block.spec.ts @@ -22,7 +22,7 @@ test('directs users to eth-phishing-detect to dispute a block, including issue t await page.waitForLoadState('networkidle'); await expect(page).toHaveURL( - 'https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20test.com&body=https%3A%2F%2Ftest.com', + 'https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20https%3A%2F%2Ftest.com&body=https%3A%2F%2Ftest.com', ); }); @@ -33,10 +33,12 @@ test('correctly matches unicode domains', async ({ context, page }) => { blacklist: ['xn--metamsk-en4c.io'], }, }); + const url = 'https://metamạsk.io'; const querystring = new URLSearchParams({ - hostname: 'test.com', - href: 'https://metamạsk.io', + hostname: url, + href: url, }); + const encoded = encodeURIComponent(url); await page.goto(`/#${querystring}`); await page.getByRole('link', { name: 'report a detection problem' }).click(); @@ -44,6 +46,6 @@ test('correctly matches unicode domains', async ({ context, page }) => { await page.waitForLoadState('networkidle'); await expect(page).toHaveURL( - 'https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20test.com&body=https%3A%2F%2Fmetamạsk.io', + `https://github.com/MetaMask/eth-phishing-detect/issues/new?title=[Legitimate%20Site%20Blocked]%20${encoded}&body=${encoded}`, ); }); diff --git a/tests/phishfort-block.spec.ts b/tests/phishfort-block.spec.ts index 7985e37..cbaa244 100644 --- a/tests/phishfort-block.spec.ts +++ b/tests/phishfort-block.spec.ts @@ -9,7 +9,6 @@ test('directs users to PhishFort to dispute a block, including issue template pa page, }) => { const querystring = new URLSearchParams({ - hostname: 'test.com', href: 'https://test.com', }); await page.goto(`/#${querystring}`); @@ -19,6 +18,6 @@ test('directs users to PhishFort to dispute a block, including issue template pa await page.waitForLoadState('networkidle'); await expect(page).toHaveURL( - 'https://github.com/phishfort/phishfort-lists/issues/new?title=[Legitimate%20Site%20Blocked]%20test.com&body=https%3A%2F%2Ftest.com', + 'https://github.com/phishfort/phishfort-lists/issues/new?title=[Legitimate%20Site%20Blocked]%20https%3A%2F%2Ftest.com&body=https%3A%2F%2Ftest.com', ); });