diff --git a/hscontrol/handlers.go b/hscontrol/handlers.go index 717934bf0..a4c981a22 100644 --- a/hscontrol/handlers.go +++ b/hscontrol/handlers.go @@ -8,7 +8,6 @@ import ( "io" "net/http" "strconv" - "strings" "time" "github.com/juanfont/headscale/hscontrol/assets" @@ -305,14 +304,9 @@ func NewAuthProviderWeb(serverURL string) *AuthProviderWeb { } // authPathURL builds an auth-flow URL of the form -// "//", trimming a trailing slash from serverURL. +// "//". func authPathURL(serverURL, kind string, authID types.AuthID) string { - return fmt.Sprintf( - "%s/%s/%s", - strings.TrimSuffix(serverURL, "/"), - kind, - authID.String(), - ) + return fmt.Sprintf("%s/%s/%s", serverURL, kind, authID.String()) } func (a *AuthProviderWeb) RegisterURL(authID types.AuthID) string { diff --git a/hscontrol/oidc.go b/hscontrol/oidc.go index 62f8c6cc2..fa763b448 100644 --- a/hscontrol/oidc.go +++ b/hscontrol/oidc.go @@ -133,7 +133,7 @@ func (a *AuthProviderOIDC) cookiesSecure() bool { } func oidcCallbackURL(serverURL string) string { - return strings.TrimSuffix(serverURL, "/") + "/oidc/callback" + return serverURL + "/oidc/callback" } func (a *AuthProviderOIDC) oidcCallbackPath() string { diff --git a/hscontrol/types/config.go b/hscontrol/types/config.go index d93007e34..f105d2eca 100644 --- a/hscontrol/types/config.go +++ b/hscontrol/types/config.go @@ -1661,7 +1661,7 @@ func LoadServerConfig() (*Config, error) { } } - serverURL := viper.GetString("server_url") + serverURL := strings.TrimRight(viper.GetString("server_url"), "/") // BaseDomain cannot be the same as the server URL. // This is because Tailscale takes over the domain in BaseDomain, diff --git a/hscontrol/types/config_test.go b/hscontrol/types/config_test.go index a5f1d2202..507649f69 100644 --- a/hscontrol/types/config_test.go +++ b/hscontrol/types/config_test.go @@ -817,6 +817,38 @@ dns: } } +func TestServerURLTrailingSlash(t *testing.T) { + tests := []struct { + name string + input string + want string + }{ + {name: "no slash", input: "https://h", want: "https://h"}, + {name: "one slash", input: "https://h/", want: "https://h"}, + {name: "two slashes", input: "https://h//", want: "https://h"}, + {name: "port", input: "https://h:8443/", want: "https://h:8443"}, + {name: "path prefix", input: "https://h/hs/", want: "https://h/hs"}, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + viper.Reset() + t.Cleanup(viper.Reset) + require.NoError(t, LoadConfig("testdata/minimal.yaml", true)) + + viper.Set("server_url", tt.input) + viper.Set("prefixes.v4", "100.64.0.0/10") + viper.Set("database.type", "sqlite3") + viper.Set("dns.magic_dns", false) + viper.Set("dns.override_local_dns", false) + + cfg, err := LoadServerConfig() + require.NoError(t, err) + assert.Equal(t, tt.want, cfg.ServerURL) + }) + } +} + // OK // server_url: headscale.com, base: clients.headscale.com // server_url: headscale.com, base: headscale.net