Files
weircon-random-proxy/service/main_test.go
T
agw 06bdd1423f fetch: every outbound request carries one generic browser User-Agent
Stripping forwarding headers kept our IP and chain out of reach, but the
User-Agent went through untouched. Clients that fell back to their own name
("crawlkit-roles", "crawlkit-virk", ...) tied all ten exits together as one
actor, and one missing UA meant Go-http-client. The proxy now overwrites the
UA on every request (WEIRCON_USER_AGENT, default current Firefox) and the
egress prober uses the same string.

Also dropped: From, Sec-Ch-Ua* (would contradict a Firefox UA) and any
X-Weircon-* by prefix. New end-to-end test drives the whole handler and
checks what the target actually receives.

Claude-Session: https://claude.ai/code/session_01AUj1LSMmrowcomkn1ciAgj
2026-09-29 20:14:07 +02:00

129 lines
3.7 KiB
Go

package main
import (
"net/http"
"net/http/httptest"
"strings"
"testing"
"time"
)
func TestStripIdentifying(t *testing.T) {
h := http.Header{}
// Headers that MUST be removed before the request reaches the target.
removed := []string{
"X-Weircon-Random-Ip",
"X-Weircon-Proxy-Id",
"X-Forwarded-For",
"X-Forwarded-Host",
"X-Forwarded-Proto",
"X-Forwarded-Port",
"X-Forwarded-Custom-Vendor", // caught by prefix sweep
"X-Real-Ip",
"Forwarded",
"Via",
"Cf-Connecting-Ip",
"True-Client-Ip",
"Fastly-Client-Ip",
"X-Original-Forwarded-For",
"X-Client-Ip",
"X-Weircon-Anything-New", // caught by prefix sweep
"From",
"Sec-Ch-Ua",
"Sec-Ch-Ua-Platform",
}
for _, k := range removed {
h.Set(k, "leak")
}
// Headers a crawler legitimately sets — these MUST survive untouched.
kept := map[string]string{
"User-Agent": "my-crawler/1.0",
"Cookie": "session=abc",
"Accept": "text/html",
"Accept-Language": "en-US",
"Referer": "https://example.com",
"X-Forward": "not-a-forwarding-header", // does not match "X-Forwarded" prefix
}
for k, v := range kept {
h.Set(k, v)
}
stripIdentifying(h)
for _, k := range removed {
if got := h.Get(k); got != "" {
t.Errorf("expected %q to be stripped, still present: %q", k, got)
}
}
for k, want := range kept {
if got := h.Get(k); got != want {
t.Errorf("expected %q to survive as %q, got %q", k, want, got)
}
}
}
func TestAnonymizeOverridesUserAgent(t *testing.T) {
for _, ua := range []string{"crawlkit-roles", "python-requests/2.32", "Go-http-client/1.1", ""} {
h := http.Header{}
if ua != "" {
h.Set("User-Agent", ua)
}
h.Set("X-Forwarded-For", "10.0.0.1")
anonymize(h, defaultUserAgent)
if got := h.Values("User-Agent"); len(got) != 1 || got[0] != defaultUserAgent {
t.Errorf("caller UA %q: outbound User-Agent = %q, want only the browser UA", ua, got)
}
if h.Get("X-Forwarded-For") != "" {
t.Errorf("anonymize must still strip forwarding headers")
}
}
}
func TestDefaultUserAgentIsBrowser(t *testing.T) {
if !strings.HasPrefix(defaultUserAgent, "Mozilla/5.0 (") || !strings.Contains(defaultUserAgent, "Firefox/") {
t.Errorf("default UA should be a plain Firefox string, got %q", defaultUserAgent)
}
}
// End to end: what the TARGET receives when a careless client goes through the
// full handler. This is the no-leak contract, not just the helper.
func TestHandlerTargetSeesOnlyBrowser(t *testing.T) {
var got http.Header
target := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
got = r.Header.Clone()
}))
defer target.Close()
cfg := Config{UserAgent: defaultUserAgent}
mgr := newProxyManager(1, 0, 0, time.Minute)
h := newHandler(cfg, []*http.Transport{{}}, mgr)
req := httptest.NewRequest(http.MethodGet, "/", nil)
req.Header.Set("X-Weircon-Random-Ip", "secret-key")
req.Header.Set("X-Weircon-Random-Ip-Redirect", target.URL+"/x")
req.Header.Set("User-Agent", "crawlkit-roles")
req.Header.Set("From", "someone@example.com")
req.Header.Set("X-Forwarded-For", "192.168.10.144")
req.Header.Set("X-Real-Ip", "192.168.10.144")
req.Header.Set("Sec-Ch-Ua", `"Chromium";v="125"`)
rec := httptest.NewRecorder()
h.ServeHTTP(rec, req)
if rec.Code != http.StatusOK {
t.Fatalf("status %d: %s", rec.Code, rec.Body.String())
}
if ua := got.Values("User-Agent"); len(ua) != 1 || ua[0] != defaultUserAgent {
t.Errorf("target saw User-Agent %q", ua)
}
for k, v := range got {
lk := strings.ToLower(k + ":" + strings.Join(v, ","))
for _, bad := range []string{"weircon", "crawlkit", "secret-key", "192.168.", "example.com", "forwarded", "sec-ch-ua", "from:"} {
if strings.Contains(lk, bad) {
t.Errorf("target saw identifying header %s: %v", k, v)
}
}
}
}