Skip to content

Commit

Permalink
fix: href link should not starts with javascript scheme (#276)
Browse files Browse the repository at this point in the history
  • Loading branch information
bang9 authored Jun 13, 2024
1 parent 24cf3e0 commit 04d8881
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 4 deletions.
19 changes: 19 additions & 0 deletions src/__tests__/utils/index.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { asSafeURL } from '../../utils';

describe('asSafeURL', () => {
test('should return the same URL if it is already safe', () => {
expect(asSafeURL('http://example.com')).toBe('http://example.com');
expect(asSafeURL('https://example.com')).toBe('https://example.com');
expect(asSafeURL('mailto:[email protected]')).toBe('mailto:[email protected]');
});

test('should return a safe URL if it is not safe', () => {
expect(asSafeURL('javascript:alert(1)')).toBe('#');
expect(asSafeURL('javascript%3Aalert%281%29')).toBe('#');
expect(asSafeURL('data:text/html;base64,ABCDE==')).toBe('#');
});

test('should append a https:// protocol to the URL if it is missing', () => {
expect(asSafeURL('example.com')).toBe('https://example.com');
});
});
6 changes: 3 additions & 3 deletions src/components/TokensBody.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import BotMessageBottom from './BotMessageBottom';
import SourceContainer, { Source } from './SourceContainer';
import { CodeBlock } from './ui/CodeBlock';
import { useConstantState } from '../context/ConstantContext';
import { replaceWithRegex, Token, TokenType } from '../utils';
import { asSafeURL, replaceWithRegex, Token, TokenType } from '../utils';

const urlRegex =
/(?:https?:\/\/|www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.(xn--)?[a-z]{2,20}\b([-a-zA-Z0-9@:%_+[\],.~#?&/=]*[-a-zA-Z0-9@:%_+~#?&/=])*/g;
Expand Down Expand Up @@ -105,7 +105,7 @@ export default function TokensBody({ tokens, sources }: TokensBodyProps) {
<a
key={`${match}-${index}`}
className="sendbird-word__url"
href={groups[2]}
href={asSafeURL(groups[2])}
target="_blank"
rel="noreferrer"
>
Expand All @@ -121,7 +121,7 @@ export default function TokensBody({ tokens, sources }: TokensBodyProps) {
<a
key={`${match}-${index}`}
className="sendbird-word__url"
href={match}
href={asSafeURL(match)}
target="_blank"
rel="noreferrer"
>
Expand Down
19 changes: 19 additions & 0 deletions src/utils/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -350,3 +350,22 @@ export function isWordpress() {
// @ts-expect-error
return typeof window !== 'undefined' && !!window['wp'];
}

export function asSafeURL(url: string) {
let safeURL = decodeURIComponent(url);

try {
const { protocol } = new URL(safeURL);
if (['https:', 'http:'].some((it) => it === protocol.toLowerCase())) {
return safeURL;
} else {
return '#';
}
} catch (error) {
if (!safeURL.startsWith('http://') && !safeURL.startsWith('https://')) {
safeURL = 'https://' + safeURL;
}
}

return safeURL;
}
3 changes: 2 additions & 1 deletion vitest.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { defineConfig } from 'vitest/config';

export default defineConfig({
test: {
globals: true,
environment: 'jsdom', // Use jsdom environment for browser-like testing
include: ['test/**/*.test.ts'], // Specify the test files pattern
include: ['src/**/*.test.ts'], // Specify the test files pattern
},
});

0 comments on commit 04d8881

Please sign in to comment.