Skip to content

Commit efecf68

Browse files
committed
Don't export isGithubUrl
1 parent d68226f commit efecf68

File tree

2 files changed

+33
-75
lines changed

2 files changed

+33
-75
lines changed

packages/playground/website/src/github/git-auth-helpers.spec.ts

Lines changed: 32 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1,84 +1,12 @@
11
import { describe, it, expect, beforeEach, vi } from 'vitest';
2-
import { createGitHubAuthHeaders, isGitHubUrl } from './git-auth-helpers';
2+
import { createGitHubAuthHeaders } from './git-auth-helpers';
33
import { oAuthState } from './state';
44

55
vi.mock('virtual:cors-proxy-url', () => ({
66
corsProxyUrl: 'https://corsproxyurl/',
77
}));
88

9-
describe('isGitHubUrl', () => {
10-
describe('direct GitHub URLs', () => {
11-
it('returns true for github.com URLs', () => {
12-
expect(isGitHubUrl('https://github.com/user/repo')).toBe(true);
13-
});
14-
15-
it('returns true for api.github.com URLs', () => {
16-
expect(isGitHubUrl('https://api.github.com/repos')).toBe(true);
17-
});
18-
19-
it('returns false for non-GitHub URLs', () => {
20-
expect(isGitHubUrl('https://gitlab.com/user/repo')).toBe(false);
21-
expect(isGitHubUrl('https://bitbucket.org/user/repo')).toBe(false);
22-
});
23-
});
24-
25-
describe('security: rejects URLs with github.com in wrong places', () => {
26-
it('returns false when github.com is in the path', () => {
27-
expect(isGitHubUrl('https://evil.com/github.com/fake')).toBe(false);
28-
});
29-
30-
it('returns false when github.com is in a query parameter', () => {
31-
expect(isGitHubUrl('https://evil.com?redirect=github.com')).toBe(
32-
false
33-
);
34-
});
35-
36-
it('returns false for look-alike domains', () => {
37-
expect(isGitHubUrl('https://github.com.evil.com')).toBe(false);
38-
expect(isGitHubUrl('https://mygithub.com')).toBe(false);
39-
expect(isGitHubUrl('https://fakegithub.com')).toBe(false);
40-
});
41-
});
42-
43-
describe('CORS proxy URLs', () => {
44-
it('returns true for GitHub URLs through CORS proxy', () => {
45-
expect(
46-
isGitHubUrl(
47-
'https://corsproxyurl/?https://github.com/user/repo'
48-
)
49-
).toBe(true);
50-
});
51-
52-
it('returns false for non-GitHub URLs through CORS proxy', () => {
53-
expect(
54-
isGitHubUrl(
55-
'https://corsproxyurl/?https://gitlab.com/user/repo'
56-
)
57-
).toBe(false);
58-
});
59-
60-
it('returns false for malicious URLs through CORS proxy', () => {
61-
expect(
62-
isGitHubUrl(
63-
'https://corsproxyurl/?https://evil.com/github.com/fake'
64-
)
65-
).toBe(false);
66-
expect(
67-
isGitHubUrl('https://corsproxyurl/?https://github.com.evil.com')
68-
).toBe(false);
69-
});
70-
});
71-
72-
describe('edge cases', () => {
73-
it('returns false for invalid URLs', () => {
74-
expect(isGitHubUrl('not-a-url')).toBe(false);
75-
expect(isGitHubUrl('')).toBe(false);
76-
expect(isGitHubUrl('github.com')).toBe(false);
77-
});
78-
});
79-
});
80-
81-
describe('createGitHubAuthHeaders integration', () => {
9+
describe('createGitHubAuthHeaders', () => {
8210
beforeEach(() => {
8311
oAuthState.value = { token: '', isAuthorizing: false };
8412
});
@@ -127,7 +55,23 @@ describe('createGitHubAuthHeaders integration', () => {
12755

12856
expect(getHeaders('https://gitlab.com/user/repo')).toEqual({});
12957
expect(getHeaders('https://bitbucket.org/user/repo')).toEqual({});
58+
});
59+
60+
it('does NOT include Authorization header for malicious URLs (security)', () => {
61+
const getHeaders = createGitHubAuthHeaders();
62+
63+
// github.com in path
13064
expect(getHeaders('https://evil.com/github.com/fake')).toEqual({});
65+
66+
// github.com in query parameter
67+
expect(getHeaders('https://evil.com?redirect=github.com')).toEqual(
68+
{}
69+
);
70+
71+
// look-alike domains
72+
expect(getHeaders('https://github.com.evil.com')).toEqual({});
73+
expect(getHeaders('https://mygithub.com')).toEqual({});
74+
expect(getHeaders('https://fakegithub.com')).toEqual({});
13175
});
13276

13377
it('does NOT include Authorization header for non-GitHub URLs through CORS proxy', () => {
@@ -138,6 +82,20 @@ describe('createGitHubAuthHeaders integration', () => {
13882

13983
expect(headers).toEqual({});
14084
});
85+
86+
it('does NOT include Authorization header for malicious URLs through CORS proxy (security)', () => {
87+
const getHeaders = createGitHubAuthHeaders();
88+
89+
expect(
90+
getHeaders(
91+
'https://corsproxyurl/?https://evil.com/github.com/fake'
92+
)
93+
).toEqual({});
94+
95+
expect(
96+
getHeaders('https://corsproxyurl/?https://github.com.evil.com')
97+
).toEqual({});
98+
});
14199
});
142100

143101
describe('without GitHub token', () => {

packages/playground/website/src/github/git-auth-helpers.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { oAuthState } from './state';
22
import { corsProxyUrl } from 'virtual:cors-proxy-url';
33

4-
export function isGitHubUrl(url: string): boolean {
4+
function isGitHubUrl(url: string): boolean {
55
try {
66
const urlObj = new URL(url);
77
const corsProxyOrigin = new URL(corsProxyUrl).origin;

0 commit comments

Comments
 (0)