Skip to content

Commit

Permalink
Merge pull request from GHSA-h4w9-6x78-8vrj
Browse files Browse the repository at this point in the history
Signed-off-by: Michael Crenshaw <michael@crenshaw.dev>
  • Loading branch information
crenshaw-dev committed Jun 21, 2022
1 parent 3fab7de commit 4fd50ce
Show file tree
Hide file tree
Showing 2 changed files with 53 additions and 2 deletions.
20 changes: 20 additions & 0 deletions ui/src/app/applications/components/application-urls.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import {ExternalLink, InvalidExternalLinkError} from './application-urls';

test('rejects malicious URLs', () => {
expect(() => {
const _ = new ExternalLink('javascript:alert("hi")');
}).toThrowError(InvalidExternalLinkError);
expect(() => {
const _ = new ExternalLink('data:text/html;<h1>hi</h1>');
}).toThrowError(InvalidExternalLinkError);
});

test('allows absolute URLs', () => {
expect(new ExternalLink('https://localhost:8080/applications').ref).toEqual('https://localhost:8080/applications');
});

test('allows relative URLs', () => {
// @ts-ignore
window.location = new URL('https://localhost:8080/applications');
expect(new ExternalLink('/applications').ref).toEqual('/applications');
});
35 changes: 33 additions & 2 deletions ui/src/app/applications/components/application-urls.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
import {DropDownMenu} from 'argo-ui';
import * as React from 'react';

class ExternalLink {
export class InvalidExternalLinkError extends Error {
constructor(message: string) {
super(message);
Object.setPrototypeOf(this, InvalidExternalLinkError.prototype);
this.name = 'InvalidExternalLinkError';
}
}

export class ExternalLink {
public title: string;
public ref: string;

Expand All @@ -14,13 +22,36 @@ class ExternalLink {
this.title = url;
this.ref = url;
}
if (!ExternalLink.isValidURL(this.ref)) {
throw new InvalidExternalLinkError('Invalid URL');
}
}

private static isValidURL(url: string): boolean {
try {
const parsedUrl = new URL(url);
return parsedUrl.protocol !== 'javascript:' && parsedUrl.protocol !== 'data:';
} catch (TypeError) {
try {
// Try parsing as a relative URL.
const parsedUrl = new URL(url, window.location.origin);
return parsedUrl.protocol !== 'javascript:' && parsedUrl.protocol !== 'data:';
} catch (TypeError) {
return false;
}
}
}
}

export const ApplicationURLs = ({urls}: {urls: string[]}) => {
const externalLinks: ExternalLink[] = [];
for (const url of urls || []) {
externalLinks.push(new ExternalLink(url));
try {
const externalLink = new ExternalLink(url);
externalLinks.push(externalLink);
} catch (InvalidExternalLinkError) {
continue;
}
}

// sorted alphabetically & links with titles first
Expand Down

0 comments on commit 4fd50ce

Please sign in to comment.