|
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)word@domain.com') |
90 | | - expect(result).toBe('http://user%24(calc)r:pass%24(calc)word@domain.com/') |
91 | | - }) |
92 | | - }) |
93 | | - |
94 | | - describe('should handle complex URLs', () => { |
95 | | - it('should handle URL with all components', () => { |
96 | | - const complexUrl = 'https://user:pass@example.com:8080/path/to/resource?param=value&other=test#fragment' |
97 | | - const result = sanitizeUrl(complexUrl) |
98 | | - expect(result).toBe('https://user:pass@example.com: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:pass@example.com/secure') |
116 | | - expect(result).toBe('https://user:pass@example.com/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