Skip to content

Commit

Permalink
Validate list of emails in validateLink function (#2750)
Browse files Browse the repository at this point in the history
This improves the hostname validation when using a list of emails rather
than a single email.
  • Loading branch information
Mrtenz authored Sep 23, 2024
1 parent 490e547 commit 178fc21
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 5 deletions.
4 changes: 2 additions & 2 deletions packages/snaps-utils/coverage.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"branches": 99.73,
"functions": 98.9,
"lines": 99.43,
"statements": 96.33
"lines": 99.44,
"statements": 96.34
}
62 changes: 62 additions & 0 deletions packages/snaps-utils/src/ui.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,30 @@ describe('validateLink', () => {
expect(fn).toHaveBeenCalledWith('bar.com');
});

it('passes for a valid list of emails', () => {
const fn = jest.fn().mockReturnValue(false);

expect(() =>
validateLink('mailto:[email protected],[email protected],[email protected]', fn),
).not.toThrow();

expect(fn).toHaveBeenCalledTimes(3);
expect(fn).toHaveBeenCalledWith('bar.com');
expect(fn).toHaveBeenCalledWith('baz.com');
expect(fn).toHaveBeenCalledWith('qux.com');
});

it('passes for a valid email with a parameter', () => {
const fn = jest.fn().mockReturnValue(false);

expect(() =>
validateLink('mailto:[email protected]?subject=Subject', fn),
).not.toThrow();

expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith('bar.com');
});

it('throws an error for an invalid protocol', () => {
const fn = jest.fn().mockReturnValue(false);

Expand Down Expand Up @@ -595,6 +619,44 @@ describe('validateLink', () => {
expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith('test.metamask-phishing.io');
});

it('throws an error for a phishing email when using multiple emails', () => {
const fn = jest.fn().mockImplementation((email) => {
if (email === 'test.metamask-phishing.io') {
return true;
}

return false;
});

expect(() =>
validateLink('mailto:[email protected],[email protected]', fn),
).toThrow('Invalid URL: The specified URL is not allowed.');

expect(fn).toHaveBeenCalledTimes(1);
expect(fn).toHaveBeenCalledWith('test.metamask-phishing.io');
});

it('throws an error for a phishing email when using parameters', () => {
const fn = jest.fn().mockImplementation((email) => {
if (email === 'test.metamask-phishing.io') {
return true;
}

return false;
});

expect(() =>
validateLink(
'mailto:[email protected],[email protected]?subject=Subject',
fn,
),
).toThrow('Invalid URL: The specified URL is not allowed.');

expect(fn).toHaveBeenCalledTimes(2);
expect(fn).toHaveBeenCalledWith('bar.com');
expect(fn).toHaveBeenCalledWith('test.metamask-phishing.io');
});
});

describe('validateTextLinks', () => {
Expand Down
19 changes: 16 additions & 3 deletions packages/snaps-utils/src/ui.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -342,10 +342,23 @@ export function validateLink(
`Protocol must be one of: ${ALLOWED_PROTOCOLS.join(', ')}.`,
);

const hostname =
url.protocol === 'mailto:' ? url.pathname.split('@')[1] : url.hostname;
if (url.protocol === 'mailto:') {
const emails = url.pathname.split(',');
for (const email of emails) {
const hostname = email.split('@')[1];
assert(
!isOnPhishingList(hostname),
'The specified URL is not allowed.',
);
}

assert(!isOnPhishingList(hostname), 'The specified URL is not allowed.');
return;
}

assert(
!isOnPhishingList(url.hostname),
'The specified URL is not allowed.',
);
} catch (error) {
throw new Error(
`Invalid URL: ${
Expand Down

0 comments on commit 178fc21

Please sign in to comment.