package main import "testing" // Which Origin headers count as "this machine". // // This exists because Flutter Web's dev server binds a random high port on every // launch, so no fixed allowlist can name it — the app hit // PreflightMissingAllowOriginHeader from http://localhost:65256 and would have // hit it again from a different port tomorrow. // // The reason it is worth a test rather than a one-line helper: the obvious // implementation is a prefix or substring match on "localhost", and that quietly // admits http://localhost.attacker.com — a completely different machine that // merely starts with the right word. Combined with AllowCredentials, that would // let an attacker-controlled page make authenticated calls as the signed-in user. // A parsed-host comparison is the only version that is actually safe, and this // pins it. func TestLoopbackOriginsAreAllowed(t *testing.T) { for _, origin := range []string{ "http://localhost:65256", // the port Flutter Web picked; it changes every run "http://localhost:5173", "http://localhost", "https://localhost:8443", "http://127.0.0.1:3000", "http://127.0.0.1", "http://[::1]:8080", } { if !isLoopbackOrigin(origin) { t.Errorf("%q is this machine and should be allowed in development", origin) } } } func TestLookalikeOriginsAreRefused(t *testing.T) { // Every one of these contains "localhost" or "127.0.0.1" as a substring and // is a different host. A prefix or Contains check would admit all of them. for _, origin := range []string{ "http://localhost.attacker.com", "https://localhost.evil.io:443", "http://notlocalhost", "http://mylocalhost:3000", "http://127.0.0.1.attacker.com", "http://evil.com/?x=http://localhost:3000", "http://evil.com#localhost", } { if isLoopbackOrigin(origin) { t.Errorf("%q is NOT this machine and must be refused", origin) } } } func TestNonHTTPSchemesAreRefused(t *testing.T) { // An Origin is a scheme/host/port triple. Anything else is either a browser // that will not send it or something forged, and neither should be trusted. for _, origin := range []string{ "file://localhost", "ftp://localhost:21", "javascript:alert(1)", "chrome-extension://abcdefghijklmnop", } { if isLoopbackOrigin(origin) { t.Errorf("%q is not an http(s) origin and must be refused", origin) } } } func TestMalformedOriginsAreRefused(t *testing.T) { for _, origin := range []string{ "", "null", // what a sandboxed iframe sends "not a url at all", "://missing-scheme", } { if isLoopbackOrigin(origin) { t.Errorf("%q is not a usable origin and must be refused", origin) } } }