11import { describe , it , expect , beforeEach , vi } from 'vitest' ;
2- import { createGitHubAuthHeaders , isGitHubUrl } from './git-auth-helpers' ;
2+ import { createGitHubAuthHeaders } from './git-auth-helpers' ;
33import { oAuthState } from './state' ;
44
55vi . 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' , ( ) => {
0 commit comments