diff --git a/server/server.go b/server/server.go index 65415d0e9fe4..5222244378c5 100644 --- a/server/server.go +++ b/server/server.go @@ -132,7 +132,7 @@ var backoff = wait.Backoff{ var ( clientConstraint = fmt.Sprintf(">= %s", common.MinClientVersion) - baseHRefRegex = regexp.MustCompile(``) + baseHRefRegex = regexp.MustCompile(``) // limits number of concurrent login requests to prevent password brute forcing. If set to 0 then no limit is enforced. maxConcurrentLoginRequestsCount = 50 replicasCount = 1 @@ -893,7 +893,7 @@ func (s *ArgoCDServer) getIndexData() ([]byte, error) { if s.BaseHRef == "/" || s.BaseHRef == "" { s.indexData = data } else { - s.indexData = []byte(baseHRefRegex.ReplaceAllString(string(data), fmt.Sprintf(``, strings.Trim(s.BaseHRef, "/")))) + s.indexData = []byte(replaceBaseHRef(string(data), fmt.Sprintf(``, strings.Trim(s.BaseHRef, "/")))) } }) @@ -978,6 +978,10 @@ func mustRegisterGWHandler(register registerFunc, ctx context.Context, mux *runt } } +func replaceBaseHRef(data string, replaceWith string) string { + return baseHRefRegex.ReplaceAllString(data, replaceWith) +} + // Authenticate checks for the presence of a valid token when accessing server-side resources. func (a *ArgoCDServer) Authenticate(ctx context.Context) (context.Context, error) { if a.DisableAuth { diff --git a/server/server_test.go b/server/server_test.go index 9ebd53723624..063e0835bc47 100644 --- a/server/server_test.go +++ b/server/server_test.go @@ -583,7 +583,7 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) { anonymousEnabled: false, claims: jwt.RegisteredClaims{Audience: jwt.ClaimStrings{"test-client"}, Subject: "admin", ExpiresAt: jwt.NewNumericDate(time.Now())}, expectedErrorContains: "token is expired", - expectedClaims: jwt.RegisteredClaims{Issuer:"sso"}, + expectedClaims: jwt.RegisteredClaims{Issuer: "sso"}, }, { test: "anonymous enabled, expired token, admin claim", @@ -601,7 +601,7 @@ func TestAuthenticate_3rd_party_JWTs(t *testing.T) { t.Parallel() // Must be declared here to avoid race. - ctx := context.Background() //nolint:ineffassign,staticcheck + ctx := context.Background() //nolint:ineffassign,staticcheck argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, true) testDataCopy.claims.Issuer = fmt.Sprintf("%s/api/dex", dexURL) @@ -698,7 +698,7 @@ func TestAuthenticate_no_SSO(t *testing.T) { t.Parallel() // Must be declared here to avoid race. - ctx := context.Background() //nolint:ineffassign,staticcheck + ctx := context.Background() //nolint:ineffassign,staticcheck argocd, dexURL := getTestServer(t, testDataCopy.anonymousEnabled, false) token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.RegisteredClaims{Issuer: fmt.Sprintf("%s/api/dex", dexURL)}) @@ -806,7 +806,7 @@ func TestAuthenticate_bad_request_metadata(t *testing.T) { t.Parallel() // Must be declared here to avoid race. - ctx := context.Background() //nolint:ineffassign,staticcheck + ctx := context.Background() //nolint:ineffassign,staticcheck argocd, _ := getTestServer(t, testDataCopy.anonymousEnabled, true) ctx = metadata.NewIncomingContext(context.Background(), testDataCopy.metadata) @@ -1065,39 +1065,39 @@ func TestOIDCConfigChangeDetection_NoChange(t *testing.T) { } func TestIsMainJsBundle(t *testing.T) { - testCases := []struct{ + testCases := []struct { name string url string isMainJsBundle bool }{ { - name: "localhost with valid main bundle", - url: "https://localhost:8080/main.e4188e5adc97bbfc00c3.js", + name: "localhost with valid main bundle", + url: "https://localhost:8080/main.e4188e5adc97bbfc00c3.js", isMainJsBundle: true, }, { - name: "localhost and deep path with valid main bundle", - url: "https://localhost:8080/some/argo-cd-instance/main.e4188e5adc97bbfc00c3.js", + name: "localhost and deep path with valid main bundle", + url: "https://localhost:8080/some/argo-cd-instance/main.e4188e5adc97bbfc00c3.js", isMainJsBundle: true, }, { - name: "font file", - url: "https://localhost:8080/assets/fonts/google-fonts/Heebo-Bols.woff2", + name: "font file", + url: "https://localhost:8080/assets/fonts/google-fonts/Heebo-Bols.woff2", isMainJsBundle: false, }, { - name: "no dot after main", - url: "https://localhost:8080/main/e4188e5adc97bbfc00c3.js", + name: "no dot after main", + url: "https://localhost:8080/main/e4188e5adc97bbfc00c3.js", isMainJsBundle: false, }, { - name: "wrong extension character", - url: "https://localhost:8080/main.e4188e5adc97bbfc00c3/js", + name: "wrong extension character", + url: "https://localhost:8080/main.e4188e5adc97bbfc00c3/js", isMainJsBundle: false, }, { - name: "wrong hash length", - url: "https://localhost:8080/main.e4188e5adc97bbfc00c3abcdefg.js", + name: "wrong hash length", + url: "https://localhost:8080/main.e4188e5adc97bbfc00c3abcdefg.js", isMainJsBundle: false, }, } @@ -1111,3 +1111,123 @@ func TestIsMainJsBundle(t *testing.T) { }) } } + +func TestReplaceBaseHRef(t *testing.T) { + testCases := []struct { + name string + data string + expected string + replaceWith string + }{ + { + name: "non-root basepath", + data: ` + + + + + Argo CD + + + + + + + + + +
+ + +`, + expected: ` + + + + + Argo CD + + + + + + + + + +
+ + +`, + replaceWith: ``, + }, + { + name: "root basepath", + data: ` + + + + + Argo CD + + + + + + + + + +
+ + +`, + expected: ` + + + + + Argo CD + + + + + + + + + +
+ + +`, + replaceWith: ``, + }, + } + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result := replaceBaseHRef(testCase.data, testCase.replaceWith) + assert.Equal(t, testCase.expected, result) + }) + } +}