check / check (push) Canceled after 0s
With TRUSTED_PROXIES unset, the server now trusts reverse proxies in the private ranges of RFC 1918. A proxy such as traefik on a Docker network is then believed. /ip/, the home page's curl card and the request log give the client's address from X-Forwarded-For instead of the proxy's address. A list in TRUSTED_PROXIES replaces the default. TRUSTED_PROXIES set but empty trusts no proxy, so the config package reads it with os.LookupEnv. A direct client at a public address still cannot choose its address with a forged header. Model: opus-5-5
154 lines
3.6 KiB
Go
154 lines
3.6 KiB
Go
package config
|
|
|
|
import (
|
|
"net/netip"
|
|
"os"
|
|
"runtime"
|
|
"slices"
|
|
"testing"
|
|
)
|
|
|
|
func TestNewReadsPort(t *testing.T) {
|
|
tests := map[string]int{
|
|
"": defaultPort,
|
|
"1": 1,
|
|
"9090": 9090,
|
|
"65535": 65535,
|
|
}
|
|
|
|
for value, want := range tests {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("PORT", value)
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
cfg, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() with PORT=%q: %v", value, err)
|
|
}
|
|
|
|
if cfg.Port != want {
|
|
t.Errorf("New() with PORT=%q: Port = %d, want %d", value, cfg.Port, want)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewRefusesInvalidPort(t *testing.T) {
|
|
for _, value := range []string{"0", "65536", "-1", "+9090", "http", "80.5"} {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("PORT", value)
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
_, err := New()
|
|
if err == nil {
|
|
t.Errorf("New() with PORT=%q returned no error", value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// TestNewTrustsPrivateRangesByDefault checks that with TRUSTED_PROXIES unset
|
|
// the trusted proxies are the private ranges of RFC 1918. Before the fix no
|
|
// proxy was trusted, so a reverse proxy at a private address was taken for the
|
|
// client (https://git.eeqj.de/sneak/routewatch/issues/198).
|
|
func TestNewTrustsPrivateRangesByDefault(t *testing.T) {
|
|
t.Setenv("PORT", "")
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
// t.Setenv puts the variable back when the test ends.
|
|
t.Setenv("TRUSTED_PROXIES", "")
|
|
|
|
err := os.Unsetenv("TRUSTED_PROXIES")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
cfg, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() without TRUSTED_PROXIES: %v", err)
|
|
}
|
|
|
|
want := []netip.Prefix{
|
|
netip.MustParsePrefix("10.0.0.0/8"),
|
|
netip.MustParsePrefix("172.16.0.0/12"),
|
|
netip.MustParsePrefix("192.168.0.0/16"),
|
|
}
|
|
if !slices.Equal(cfg.TrustedProxies, want) {
|
|
t.Errorf("New() without TRUSTED_PROXIES: TrustedProxies = %v, want %v",
|
|
cfg.TrustedProxies, want)
|
|
}
|
|
}
|
|
|
|
// TestNewReadsTrustedProxies checks that a list in TRUSTED_PROXIES replaces
|
|
// the default, and that TRUSTED_PROXIES set but empty trusts no proxy.
|
|
func TestNewReadsTrustedProxies(t *testing.T) {
|
|
t.Setenv("PORT", "")
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
|
|
t.Setenv("TRUSTED_PROXIES", "10.0.0.0/8, 192.0.2.1,2001:db8::/32")
|
|
|
|
cfg, err := New()
|
|
if err != nil {
|
|
t.Fatalf("New() with TRUSTED_PROXIES: %v", err)
|
|
}
|
|
|
|
want := []netip.Prefix{
|
|
netip.MustParsePrefix("10.0.0.0/8"),
|
|
netip.MustParsePrefix("192.0.2.1/32"),
|
|
netip.MustParsePrefix("2001:db8::/32"),
|
|
}
|
|
if !slices.Equal(cfg.TrustedProxies, want) {
|
|
t.Errorf("TrustedProxies = %v, want %v", cfg.TrustedProxies, want)
|
|
}
|
|
|
|
t.Setenv("TRUSTED_PROXIES", "")
|
|
|
|
cfg, err = New()
|
|
if err != nil {
|
|
t.Fatalf("New() with TRUSTED_PROXIES set but empty: %v", err)
|
|
}
|
|
|
|
if len(cfg.TrustedProxies) != 0 {
|
|
t.Errorf("New() with TRUSTED_PROXIES set but empty: TrustedProxies = %v, "+
|
|
"want none", cfg.TrustedProxies)
|
|
}
|
|
}
|
|
|
|
func TestNewRefusesInvalidTrustedProxies(t *testing.T) {
|
|
invalid := []string{"proxy.example", "10.0.0.0/33", "192.0.2.1:80", "192.0.2.1,"}
|
|
for _, value := range invalid {
|
|
t.Run(value, func(t *testing.T) {
|
|
t.Setenv("PORT", "")
|
|
t.Setenv("XDG_DATA_HOME", "")
|
|
t.Setenv("TRUSTED_PROXIES", value)
|
|
|
|
_, err := New()
|
|
if err == nil {
|
|
t.Errorf("New() with TRUSTED_PROXIES=%q returned no error", value)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestNewRefusesRelativeXDGDataHome(t *testing.T) {
|
|
if runtime.GOOS == "darwin" {
|
|
t.Skip("macOS does not read XDG_DATA_HOME")
|
|
}
|
|
|
|
t.Setenv("PORT", "")
|
|
|
|
t.Setenv("XDG_DATA_HOME", "relative/path")
|
|
|
|
_, err := New()
|
|
if err == nil {
|
|
t.Error("New() with a relative XDG_DATA_HOME returned no error")
|
|
}
|
|
|
|
t.Setenv("XDG_DATA_HOME", "/var/lib")
|
|
|
|
_, err = New()
|
|
if err != nil {
|
|
t.Errorf("New() with XDG_DATA_HOME=/var/lib: %v", err)
|
|
}
|
|
}
|