mirror of
https://gitee.com/wanwujie/sub2api
synced 2026-04-10 01:54:46 +08:00
124 lines
3.5 KiB
Go
124 lines
3.5 KiB
Go
|
|
package admin
|
||
|
|
|
||
|
|
import (
|
||
|
|
"net/http"
|
||
|
|
"net/netip"
|
||
|
|
"testing"
|
||
|
|
)
|
||
|
|
|
||
|
|
func TestIsAllowedOpsWSOrigin_AllowsEmptyOrigin(t *testing.T) {
|
||
|
|
original := opsWSProxyConfig
|
||
|
|
t.Cleanup(func() { opsWSProxyConfig = original })
|
||
|
|
opsWSProxyConfig = OpsWSProxyConfig{OriginPolicy: OriginPolicyPermissive}
|
||
|
|
|
||
|
|
req, err := http.NewRequest(http.MethodGet, "http://example.test", nil)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRequest: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if !isAllowedOpsWSOrigin(req) {
|
||
|
|
t.Fatalf("expected empty Origin to be allowed")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIsAllowedOpsWSOrigin_RejectsEmptyOrigin_WhenStrict(t *testing.T) {
|
||
|
|
original := opsWSProxyConfig
|
||
|
|
t.Cleanup(func() { opsWSProxyConfig = original })
|
||
|
|
opsWSProxyConfig = OpsWSProxyConfig{OriginPolicy: OriginPolicyStrict}
|
||
|
|
|
||
|
|
req, err := http.NewRequest(http.MethodGet, "http://example.test", nil)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRequest: %v", err)
|
||
|
|
}
|
||
|
|
|
||
|
|
if isAllowedOpsWSOrigin(req) {
|
||
|
|
t.Fatalf("expected empty Origin to be rejected under strict policy")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestIsAllowedOpsWSOrigin_UsesXForwardedHostOnlyFromTrustedProxy(t *testing.T) {
|
||
|
|
original := opsWSProxyConfig
|
||
|
|
t.Cleanup(func() { opsWSProxyConfig = original })
|
||
|
|
|
||
|
|
opsWSProxyConfig = OpsWSProxyConfig{
|
||
|
|
TrustProxy: true,
|
||
|
|
TrustedProxies: []netip.Prefix{
|
||
|
|
netip.MustParsePrefix("127.0.0.0/8"),
|
||
|
|
},
|
||
|
|
}
|
||
|
|
|
||
|
|
// Untrusted peer: ignore X-Forwarded-Host and compare against r.Host.
|
||
|
|
{
|
||
|
|
req, err := http.NewRequest(http.MethodGet, "http://internal.service.local", nil)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRequest: %v", err)
|
||
|
|
}
|
||
|
|
req.RemoteAddr = "192.0.2.1:12345"
|
||
|
|
req.Host = "internal.service.local"
|
||
|
|
req.Header.Set("Origin", "https://public.example.com")
|
||
|
|
req.Header.Set("X-Forwarded-Host", "public.example.com")
|
||
|
|
|
||
|
|
if isAllowedOpsWSOrigin(req) {
|
||
|
|
t.Fatalf("expected Origin to be rejected when peer is not a trusted proxy")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Trusted peer: allow X-Forwarded-Host to participate in Origin validation.
|
||
|
|
{
|
||
|
|
req, err := http.NewRequest(http.MethodGet, "http://internal.service.local", nil)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRequest: %v", err)
|
||
|
|
}
|
||
|
|
req.RemoteAddr = "127.0.0.1:23456"
|
||
|
|
req.Host = "internal.service.local"
|
||
|
|
req.Header.Set("Origin", "https://public.example.com")
|
||
|
|
req.Header.Set("X-Forwarded-Host", "public.example.com")
|
||
|
|
|
||
|
|
if !isAllowedOpsWSOrigin(req) {
|
||
|
|
t.Fatalf("expected Origin to be accepted when peer is a trusted proxy")
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLoadOpsWSProxyConfigFromEnv_OriginPolicy(t *testing.T) {
|
||
|
|
t.Setenv(envOpsWSOriginPolicy, "STRICT")
|
||
|
|
cfg := loadOpsWSProxyConfigFromEnv()
|
||
|
|
if cfg.OriginPolicy != OriginPolicyStrict {
|
||
|
|
t.Fatalf("OriginPolicy=%q, want %q", cfg.OriginPolicy, OriginPolicyStrict)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestLoadOpsWSProxyConfigFromEnv_OriginPolicyInvalidUsesDefault(t *testing.T) {
|
||
|
|
t.Setenv(envOpsWSOriginPolicy, "nope")
|
||
|
|
cfg := loadOpsWSProxyConfigFromEnv()
|
||
|
|
if cfg.OriginPolicy != OriginPolicyPermissive {
|
||
|
|
t.Fatalf("OriginPolicy=%q, want %q", cfg.OriginPolicy, OriginPolicyPermissive)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestParseTrustedProxyList(t *testing.T) {
|
||
|
|
prefixes, invalid := parseTrustedProxyList("10.0.0.1, 10.0.0.0/8, bad, ::1/128")
|
||
|
|
if len(prefixes) != 3 {
|
||
|
|
t.Fatalf("prefixes=%d, want 3", len(prefixes))
|
||
|
|
}
|
||
|
|
if len(invalid) != 1 || invalid[0] != "bad" {
|
||
|
|
t.Fatalf("invalid=%v, want [bad]", invalid)
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
func TestRequestPeerIP_ParsesIPv6(t *testing.T) {
|
||
|
|
req, err := http.NewRequest(http.MethodGet, "http://example.test", nil)
|
||
|
|
if err != nil {
|
||
|
|
t.Fatalf("NewRequest: %v", err)
|
||
|
|
}
|
||
|
|
req.RemoteAddr = "[::1]:1234"
|
||
|
|
|
||
|
|
addr, ok := requestPeerIP(req)
|
||
|
|
if !ok {
|
||
|
|
t.Fatalf("expected IPv6 peer IP to parse")
|
||
|
|
}
|
||
|
|
if addr != netip.MustParseAddr("::1") {
|
||
|
|
t.Fatalf("addr=%s, want ::1", addr)
|
||
|
|
}
|
||
|
|
}
|