Address review findings on the cover-path deletion (#63)

- Move the kagane cover URL shape into the extraction module (sites.go):
  browserOnlyCoverURL + kaganeImageURLRe now own the claim; the byte-fetch
  router and BrowserFetcher.Image reference it. One shape gate for producer
  and fetcher (the id regex is folded into the full-URL match), so no Site
  name appears in a cover path outside the extraction module and the
  producer cannot emit an address the fetch would refuse.
- Restore the serving-boundary guarantee: GET /covers/{addr} re-checks the
  stored media type via store.CoverContentType and 404s a poisoned row;
  TestPublicCoverNeverEchoesNonImage now seeds one directly behind the
  write gate and pins the refusal where bytes leave.
- Restore the SSRF rationale (client-supplied stored URL, headless browser
  as a strong primitive) on the URL regex.
This commit is contained in:
2026-08-10 11:36:54 +07:00
parent cce3d61799
commit 0a79e5f3d7
6 changed files with 60 additions and 34 deletions
-20
View File
@@ -24,26 +24,6 @@ const challengeTimeout = 45 * time.Second
var kaganeSeriesRe = regexp.MustCompile(`^/series/([0-9a-f-]{36})/?$`)
// kaganeImageIDRe pins the only image id the kagane extractor accepts. It
// arrives from the browser-fetched API body, so it is matched rather than
// trusted.
var kaganeImageIDRe = regexp.MustCompile(`^[0-9a-f-]{36}$`)
// kaganeImageURLRe matches the only cover URL Image fetches: the canonical
// compressed image route kagane's API publishes. It doubles as the byte-fetch
// router's claim check (fetchCoverBytes) — an address of this shape answers a
// plain fetch with a challenge, so the browser is the only route for it.
var kaganeImageURLRe = regexp.MustCompile(`^https://kagane\.to/api/v2/image/([0-9a-f-]{36})/compressed$`)
// browserCoverURL reports whether the browser sidecar is the only fetcher for
// cover bytes at imageURL. kagane serves them behind the same challenge as its
// pages, so a plain TLS fetch would only ever retrieve a challenge page and
// must not be attempted (ADR-0007). Per-Site knowledge, kept in the browser
// module with the rest of it.
func browserCoverURL(imageURL string) bool {
return kaganeImageURLRe.MatchString(imageURL)
}
// BrowserFetcher retrieves pages through a remote headless Chrome over the
// DevTools Protocol.
//