-
Notifications
You must be signed in to change notification settings - Fork 313
Expand file tree
/
Copy pathconstants.test.ts
More file actions
101 lines (83 loc) · 3.16 KB
/
Copy pathconstants.test.ts
File metadata and controls
101 lines (83 loc) · 3.16 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
import { expect, test, describe } from 'vitest';
import { UNPERMITTED_SCHEMES, isPermittedRedirectUrl } from './constants';
describe('UNPERMITTED_SCHEMES', () => {
// Dangerous schemes that must be blocked
test.each([
'javascript:',
'JavaScript:',
'JAVASCRIPT:',
'data:',
'Data:',
'DATA:',
'vbscript:',
'VBScript:',
'VBSCRIPT:',
])('blocks %s', (scheme) => {
expect(UNPERMITTED_SCHEMES.test(scheme)).toBe(true);
});
// Full URL strings (used in /oauth/complete page)
test.each([
'javascript:alert(1)',
'data:text/html,<script>alert(1)</script>',
'vbscript:MsgBox("xss")',
])('blocks full URL string: %s', (url) => {
expect(UNPERMITTED_SCHEMES.test(url)).toBe(true);
});
// Permitted schemes that must not be blocked
test.each([
'http:',
'https:',
'vscode:',
'cursor:',
'claude:',
'vscode://callback',
'cursor://callback?code=abc',
'http://localhost:8080/callback',
'https://example.com/callback',
])('permits %s', (url) => {
expect(UNPERMITTED_SCHEMES.test(url)).toBe(false);
});
});
describe('isPermittedRedirectUrl', () => {
// --- Permitted URLs ---
test('permits https URLs', () => {
expect(isPermittedRedirectUrl('https://example.com/callback')).toBe(true);
});
test('permits http URLs', () => {
expect(isPermittedRedirectUrl('http://localhost:8080/callback')).toBe(true);
});
test('permits /oauth/complete relative paths', () => {
expect(isPermittedRedirectUrl('/oauth/complete?url=vscode%3A%2F%2Fcallback')).toBe(true);
});
test('permits /oauth/complete with encoded custom scheme', () => {
expect(isPermittedRedirectUrl('/oauth/complete?url=cursor%3A%2F%2Fcallback%3Fcode%3Dabc')).toBe(true);
});
test('permits https URL with query params and fragment', () => {
expect(isPermittedRedirectUrl('https://example.com/callback?code=abc&state=xyz#fragment')).toBe(true);
});
// --- Blocked URLs ---
test('blocks javascript: URLs', () => {
expect(isPermittedRedirectUrl('javascript:alert(1)')).toBe(false);
});
test('blocks data: URLs', () => {
expect(isPermittedRedirectUrl('data:text/html,<script>alert(1)</script>')).toBe(false);
});
test('blocks vbscript: URLs', () => {
expect(isPermittedRedirectUrl('vbscript:MsgBox("xss")')).toBe(false);
});
test('blocks javascript: with mixed case', () => {
expect(isPermittedRedirectUrl('JavaScript:alert(1)')).toBe(false);
});
test('blocks custom scheme URLs not wrapped in /oauth/complete', () => {
expect(isPermittedRedirectUrl('vscode://callback?code=abc')).toBe(false);
});
test('blocks malformed URLs', () => {
expect(isPermittedRedirectUrl('not a url at all')).toBe(false);
});
test('blocks empty string', () => {
expect(isPermittedRedirectUrl('')).toBe(false);
});
test('blocks relative paths that do not start with /oauth/complete', () => {
expect(isPermittedRedirectUrl('/some/other/path')).toBe(false);
});
});