diff --git a/internal/stealth/headers.go b/internal/stealth/headers.go new file mode 100644 index 0000000..7f72615 --- /dev/null +++ b/internal/stealth/headers.go @@ -0,0 +1,25 @@ +package stealth + +// HeaderSet is a consistent header bundle plus advisories the MCP cannot enforce. +type HeaderSet struct { + Headers map[string]string `json:"headers"` + Advisories []string `json:"advisories"` +} + +// HeadersFor builds an HTTP header set consistent with the given fingerprint. +func HeadersFor(fp Fingerprint) HeaderSet { + return HeaderSet{ + Headers: map[string]string{ + "User-Agent": fp.UserAgent, + "Accept-Language": fp.Locale + ",en;q=0.9", + "Sec-CH-UA": fp.SecCHUA, + "Sec-CH-UA-Platform": fp.SecCHUAPlatform, + "Sec-CH-UA-Mobile": "?0", + "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8", + }, + Advisories: []string{ + "TLS/JA3 fingerprint is set by the browser's TLS stack and cannot be changed by this MCP — use a matching browser build or a TLS-rotating proxy.", + "HTTP/2 frame fingerprint is browser-controlled; header order here is advisory only.", + }, + } +} diff --git a/internal/stealth/headers_test.go b/internal/stealth/headers_test.go new file mode 100644 index 0000000..7d51925 --- /dev/null +++ b/internal/stealth/headers_test.go @@ -0,0 +1,17 @@ +package stealth + +import "testing" + +func TestHeadersFor(t *testing.T) { + fp := GenerateFingerprint(FingerprintParams{OS: "macos", Browser: "chrome", Locale: "en-GB", Seed: 5}) + h := HeadersFor(fp) + if h.Headers["User-Agent"] != fp.UserAgent { + t.Fatalf("UA mismatch") + } + if h.Headers["Accept-Language"] == "" || h.Headers["Sec-CH-UA-Platform"] == "" { + t.Fatalf("missing client hints: %+v", h.Headers) + } + if len(h.Advisories) == 0 { + t.Fatal("expected TLS/JA3 advisory") + } +}