diff --git a/hscontrol/types/config.go b/hscontrol/types/config.go index fb720169..18fcd939 100644 --- a/hscontrol/types/config.go +++ b/hscontrol/types/config.go @@ -1301,23 +1301,11 @@ func isSafeServerURL(serverURL, baseDomain string) error { return errServerURLSame } - serverDomainParts := strings.Split(server.Host, ".") - baseDomainParts := strings.Split(baseDomain, ".") - - if len(serverDomainParts) <= len(baseDomainParts) { - return nil + if strings.HasSuffix(server.Hostname(), "."+baseDomain) { + return errServerURLSuffix } - s := len(serverDomainParts) - - b := len(baseDomainParts) - for i := range baseDomainParts { - if serverDomainParts[s-i-1] != baseDomainParts[b-i-1] { - return nil - } - } - - return errServerURLSuffix + return nil } type deprecator struct { diff --git a/hscontrol/types/config_test.go b/hscontrol/types/config_test.go index 8d7b286d..d9acf253 100644 --- a/hscontrol/types/config_test.go +++ b/hscontrol/types/config_test.go @@ -507,6 +507,47 @@ func TestSafeServerURL(t *testing.T) { } } +func TestSafeServerURLWithPort(t *testing.T) { + tests := []struct { + serverURL, baseDomain, + wantErr string + }{ + { + serverURL: "https://server.headscale.com:443", + baseDomain: "headscale.com", + wantErr: errServerURLSuffix.Error(), + }, + { + serverURL: "https://server.subdomain.headscale.com:8080", + baseDomain: "headscale.com", + wantErr: errServerURLSuffix.Error(), + }, + { + serverURL: "https://headscale.com:443", + baseDomain: "headscale.com", + wantErr: errServerURLSame.Error(), + }, + { + serverURL: "https://example.com:8080", + baseDomain: "example.org", + }, + } + + for _, tt := range tests { + testName := fmt.Sprintf("server=%s domain=%s", tt.serverURL, tt.baseDomain) + t.Run(testName, func(t *testing.T) { + err := isSafeServerURL(tt.serverURL, tt.baseDomain) + if tt.wantErr != "" { + assert.EqualError(t, err, tt.wantErr) + + return + } + + assert.NoError(t, err) + }) + } +} + // TestConfigJSONOmitsSecrets verifies that marshalling a [Config] to JSON // (as /debug/config does via [state.State.DebugConfig]) does not leak the // Postgres password, the OIDC client secret, or the headscale admin