|
1 | 1 | import { describe, it, expect } from 'vitest'
|
2 |
| -import { sanitizeUrl } from './utils' |
3 | 2 |
|
4 |
| -describe('sanitizeUrl', () => { |
5 |
| - describe('should allow valid URLs', () => { |
6 |
| - const testCases = [ |
7 |
| - { input: 'http://example.com', expected: 'http://example.com/' }, |
8 |
| - { input: 'https://www.google.com', expected: 'https://www.google.com/' }, |
9 |
| - { input: 'http://test.com/path/to/resource', expected: 'http://test.com/path/to/resource' }, |
10 |
| - { input: 'https://api.github.com/users/octocat', expected: 'https://api.github.com/users/octocat' }, |
11 |
| - { |
12 |
| - input: 'https://subdomain.example.com/page?param=value#section', |
13 |
| - expected: 'https://subdomain.example.com/page?param=value#section', |
14 |
| - }, |
15 |
| - { input: 'http://localhost:3000', expected: 'http://localhost:3000/' }, |
16 |
| - { input: 'https://127.0.0.1:8080', expected: 'https://127.0.0.1:8080/' }, |
17 |
| - ] |
18 |
| - |
19 |
| - testCases.forEach(({ input, expected }) => { |
20 |
| - it(`should sanitize: ${input}`, () => { |
21 |
| - const result = sanitizeUrl(input) |
22 |
| - expect(result).toBe(expected) |
23 |
| - }) |
24 |
| - }) |
25 |
| - }) |
26 |
| - |
27 |
| - describe('should reject invalid protocols', () => { |
28 |
| - const invalidProtocolUrls = [ |
29 |
| - 'ftp://example.com/test', |
30 |
| - 'ssh://test.com/whoami', |
31 |
| - 'telnet://malicious.com/dir', |
32 |
| - 'file:///C:/Windows/System32/calc.exe', |
33 |
| - 'file://localhost/etc/passwd', |
34 |
| - 'file://c:/windows/system32/calc.exe', |
35 |
| - 'javascript:alert("XSS")', |
36 |
| - 'javascript:eval("malicious code")', |
37 |
| - 'javascript:$(calc.exe)?response_type=code.....', |
38 |
| - 'javascript:$(cmd /c whoami > c:\\temp\\pwned.txt)', |
39 |
| - 'data:text/html,<script>alert("XSS")</script>', |
40 |
| - ] |
41 |
| - |
42 |
| - invalidProtocolUrls.forEach((url) => { |
43 |
| - it(`should reject: ${url}`, () => { |
44 |
| - expect(() => sanitizeUrl(url)).toThrow('Invalid url to pass to open()') |
45 |
| - }) |
46 |
| - }) |
47 |
| - }) |
48 |
| - |
49 |
| - describe('should reject malicious hosts', () => { |
50 |
| - const invalidProtocolUrls = [ |
51 |
| - 'https://www.$(calc.exe).com/foo', |
52 |
| - 'https://www.example.com:$(calc.exe)/foo', |
53 |
| - ] |
54 |
| - |
55 |
| - invalidProtocolUrls.forEach((url) => { |
56 |
| - it(`should reject: ${url}`, () => { |
57 |
| - expect(() => sanitizeUrl(url)).toThrow('Invalid url to pass to open()') |
58 |
| - }) |
59 |
| - }) |
60 |
| - }) |
61 |
| - |
62 |
| - describe('should properly encode URL components', () => { |
63 |
| - it('should reject URLs with spaces in hostname', () => { |
64 |
| - // URLs with spaces in hostname are invalid |
65 |
| - expect(() => sanitizeUrl('https://exam ple.com')).toThrow() |
66 |
| - }) |
67 |
| - |
68 |
| - it('should encode special characters in pathname', () => { |
69 |
| - const result = sanitizeUrl('https://example.com/path with spaces') |
70 |
| - expect(result).toBe('https://example.com/path%2520with%2520spaces') |
71 |
| - }) |
72 |
| - |
73 |
| - it('should encode query parameters', () => { |
74 |
| - const result = sanitizeUrl('https://example.com?key=value with spaces&another=test') |
75 |
| - expect(result).toBe('https://example.com/?key=value%20with%20spaces&another=test') |
76 |
| - }) |
77 |
| - |
78 |
| - it('should encode hash fragments', () => { |
79 |
| - const result = sanitizeUrl('https://example.com#section with spaces') |
80 |
| - expect(result).toBe('https://example.com/#section%2520with%2520spaces') |
81 |
| - }) |
82 |
| - |
83 |
| - it('should handle empty query parameter values', () => { |
84 |
| - const result = sanitizeUrl('https://example.com?empty&hasvalue=test') |
85 |
| - expect(result).toBe('https://example.com/?empty&hasvalue=test') |
86 |
| - }) |
87 |
| - |
88 |
| - it('should encode basic auth', () => { |
89 |
| - const result = sanitizeUrl('http://user$(calc)r:pass$(calc)[email protected]') |
90 |
| - expect(result).toBe('http://user%24(calc)r:pass%24(calc)[email protected]/') |
91 |
| - }) |
92 |
| - }) |
93 |
| - |
94 |
| - describe('should handle complex URLs', () => { |
95 |
| - it('should handle URL with all components', () => { |
96 |
| - const complexUrl = 'https://user:[email protected]:8080/path/to/resource?param=value&other=test#fragment' |
97 |
| - const result = sanitizeUrl(complexUrl) |
98 |
| - expect(result).toBe('https://user:[email protected]:8080/path/to/resource?param=value&other=test#fragment') |
99 |
| - }) |
100 |
| - |
101 |
| - it('should preserve valid URL structure', () => { |
102 |
| - const url = 'https://api.example.com/v1/users?limit=10&offset=0#results' |
103 |
| - const result = sanitizeUrl(url) |
104 |
| - expect(result).toBe('https://api.example.com/v1/users?limit=10&offset=0#results') |
105 |
| - }) |
106 |
| - }) |
107 |
| - |
108 |
| - describe('should handle edge cases', () => { |
109 |
| - it('should handle URLs with port numbers', () => { |
110 |
| - const result = sanitizeUrl('http://localhost:3000/api') |
111 |
| - expect(result).toBe('http://localhost:3000/api') |
112 |
| - }) |
113 |
| - |
114 |
| - it('should handle URLs with authentication info', () => { |
115 |
| - const result = sanitizeUrl('https://user:[email protected]/secure') |
116 |
| - expect(result).toBe('https://user:[email protected]/secure') |
117 |
| - }) |
118 |
| - |
119 |
| - it('should handle minimal URLs', () => { |
120 |
| - const result = sanitizeUrl('http://a.com') |
121 |
| - expect(result).toBe('http://a.com/') |
122 |
| - }) |
123 |
| - }) |
124 |
| - |
125 |
| - describe('malformed or suspicious URLs', () => { |
126 |
| - it('should handle URLs with suspicious query parameters', () => { |
127 |
| - // These should be encoded properly, not blocked |
128 |
| - const result = sanitizeUrl('https://example.com?param=$(calc.exe)') |
129 |
| - expect(result).toBe('https://example.com/?param=%24(calc.exe)') |
130 |
| - }) |
131 |
| - |
132 |
| - it('should handle URLs with suspicious fragments', () => { |
133 |
| - const result = sanitizeUrl('https://example.com#$(calc)') |
134 |
| - expect(result).toBe('https://example.com/#%24(calc)') |
135 |
| - }) |
136 |
| - |
137 |
| - it('should handle URLs with command injection attempts in path', () => { |
138 |
| - const result = sanitizeUrl('https://example.com/$(calc.exe)') |
139 |
| - expect(result).toBe('https://example.com/%24(calc.exe)') |
140 |
| - }) |
141 |
| - |
142 |
| - it('should handle specific malicious URL with calc.exe in path', () => { |
143 |
| - const result = sanitizeUrl('http://www.a.com/$(calc.exe)') |
144 |
| - expect(result).toBe('http://www.a.com/%24(calc.exe)') |
145 |
| - }) |
146 |
| - }) |
147 |
| -}) |
| 3 | +// All sanitizeUrl tests have been moved to the strict-url-sanitise package |
0 commit comments