Lower-case the image URL's host and require a signature for a port (closes #246) #266

Merged
clawbot merged 5 commits from issue-246-normalize-source-host into next 2026-10-15 12:31:15 +02:00
5 Commits
Author SHA1 Message Date
sneak 6453b9a125 Say the source host is signed as the URL writes it (part of #246)
check / check (push) Waiting to run
The Signature Specification read as though the hostname were signed
with ":" and the port appended. The code signs the host segment as the
URL writes it up to the first "/", lower-cased, so IPv6 brackets and a
":" with or without a port are kept. The README line, the TODO.md entry
and the parser comment now say so.

Model: opus-5-5
2026-10-15 10:03:47 +00:00
sneak 589318db97 Read the source host's port from the parsed URL (part of #246)
check / check (push) Waiting to run
net.SplitHostPort fails on an IPv6 address written without brackets,
so with 2001:db8::1 allowlisted, 2001:db8::1:8443 and 2001:db8::1:
counted as having no port and were served without a signature, though
the fetcher connects to port 8443. ValidateRequest now takes a host to
have a port when the parsed URL's Port() is set or the host ends in
":", as Go's URL parser and so the fetcher read it.

Model: opus-5-5
2026-10-15 07:38:14 +00:00
sneak b71f2958db Test that an unbracketed IPv6 host with a port needs a signature (part of #246)
With 2001:db8::1 allowlisted, Go's URL parser, which the fetcher uses,
reads 2001:db8::1:8443 as 2001:db8::1 with port 8443, and
2001:db8::1: as 2001:db8::1 with an empty port. Both must need a
signature. The test fails until the port check reads the port as the
parsed URL does.

Model: opus-5-5
2026-10-15 07:38:14 +00:00
sneak ad47aab290 Lower-case the image URL's host and require a signature for a port (closes #246)
With cdn.example.com allowlisted, CDN.Example.com and
cdn.example.com:8443 passed the allowlist too, and each spelling had its
own cache entries and its own connections under
upstream_connections_per_host. The image URL parser now lower-cases the
host and refuses one holding "@" with ErrInvalidHost (400).
ValidateRequest counts a host followed by ":", with or without a port,
as not allowlisted, so it needs a signature. That check is not in
allowlist.IsAllowed, which also matches referer_blocklist. A URL is now
signed over the lower-cased host; README.md says so.

Model: opus-5-5
2026-10-15 07:38:14 +00:00
sneak 9d9fb52c97 Test that the image URL's host is one spelling (part of #246)
The image URL parser must lower-case the host and refuse one holding
"@", which a URL reads as a user name and password before the host;
ErrInvalidHost is added for that refusal. A host with a port, or a ":"
with no port, must match no allowlist entry, so its request needs a
signature. All three tests fail until the fix.

Model: opus-5-5
2026-10-15 07:37:40 +00:00