Commit Graph
4 Commits
Author SHA1 Message Date
sneak af47215237 feat: include quality and fit in the URL signature (closes #60)
check / check (push) Failing after 1s
Quality (q) and fit were read after signature validation and folded
into the variant cache key, so one signed URL could be replayed across
100 quality values and 5 fit modes, yielding up to 500 unauthorized
cache entries and libvips transcodes.

The signed data now appends the effective quality and fit:

  host:path:query:width:height:format:expiration:quality:fit

The handler already defaults an omitted q to 85 and fit to cover before
verification, so those effective values are what gets signed; a URL
signed for one quality or fit no longer verifies when replayed with
another. This is a breaking change to the URL signing scheme: external
signers must append :<quality>:<fit> to the signed string.

New known-answer vectors are added in golden_qualityfit_test.go; the
README signature specification is updated. The pre-existing
golden_test.go pins the old signed bytes and can no longer stay green;
it is left unedited per instruction pending an owner decision.

model: claude-opus-4-8
2026-09-21 07:33:55 +00:00
sneak 5f3ff448ab test: show quality and fit are not covered by the URL signature
Add Quality and FitMode fields to signature.Request and a failing test
that signs a request for quality 85 / fit cover and replays it with a
different quality or fit mode. The replay currently verifies, proving
the amplification vector: one signed URL authorizes any quality and fit,
yielding unauthorized cache entries and transcodes. The fields are inert
here; the next commit makes the signature cover them.

model: claude-opus-4-8
2026-09-21 07:30:57 +00:00
clawbot 2d805125ee chore: update golangci-lint to v2.12.2 with canonical config (#54)
check / check (push) Successful in 4s
Canonical v2-schema `.golangci.yml`, golangci-lint pins bumped to v2.12.2 in `Dockerfile` and `script/bootstrap`, and the tree brought to `0 issues.` under it.

Three behaviour deltas: `Cache.StoreVariant` takes a context (cancelled requests skip the accounting row, recovered by reconciliation); `MetadataStorage.Store` no longer leaks `.tmp-*.json` on Write/Close/Rename failure (dead-defer bug fix); the `signing_key` too-short error text gained a `value too short:` prefix.

Eviction-loop context cancellation deferred to #102.
2026-08-10 16:12:22 +02:00
clawbotandsneak 6573b9d1ef refactor: extract signature package from imgcache (#46)
check / check (push) Successful in 5s
Extracts HMAC-SHA256 request signing out of `internal/imgcache/` into its own `internal/signature/` package, per the plan in [issue #39](#39).

This is one of the remaining "easily separable" extractions (`imageprocessor`, `allowlist`, `magic`, and `httpfetcher` already landed). Only the signer is moved here so the diff stays reviewable.

## What moved

From `internal/imgcache/signature.go` and its tests into `internal/signature/`:

- `Signer` type, its `New` constructor, `Sign`, `Verify`, `GenerateSignedURL`
- `ParseParams` (query-string signature/expiration parsing)
- Signature error sentinels

## One-way import edge

To keep the import edge one-way (`imgcache` depends on `signature`, never the reverse), the package defines a standalone `Request` type carrying just the fields the signature covers, instead of importing `imgcache.ImageRequest`. `imgcache` projects its `ImageRequest` onto `signature.Request` via a small unexported `signatureRequest` helper. This mirrors how the `magic` extraction defined its own `ImageFormat` type.

## Renames (no stuttering)

- `NewSigner` -> `signature.New`
- `ParseSignatureParams` -> `signature.ParseParams`
- `ErrSignatureRequired`/`Invalid`/`Expired` -> `signature.ErrRequired`/`Invalid`/`Expired`

The `ErrRequired` message is updated from "non-whitelisted host" to "non-allowlisted host" for inclusive terminology, consistent with the `allowlist` rename.

## Rework (post-review)

Three commits added after review feedback:

- `d69019b` — golden known-answer test pinning the exact HMAC signatures and signed URL paths for three fixed vectors (resized, resized+query, orig size), cross-validated against an independent HMAC implementation. Any change to the signed byte format now fails loudly.
- `43b9f1c` — whitelist→allowlist rename completed across `internal/imgcache` and `internal/handlers` (`ServiceConfig.Allowlist`, `Allowlist` interface, `IsAllowlisted`, test helpers and test names).
- `3dc1999` — one-pass config surface rename, no back-compat alias: YAML key `whitelist_hosts` → `allowlist_hosts`, `Config.WhitelistHosts` → `Config.AllowlistHosts`, `config.example.yml`, `scripts/manual-test.sh`, and `README.md` (which also documented a nonexistent `source_host_whitelist` key — now fixed to the real one).

## Behavior

Pure refactor apart from the config key rename above. The bytes fed to the HMAC are unchanged (`host:path:query:width:height:format:expiration`), so previously issued signatures remain valid — now enforced by the golden test. All existing tests move with the package. `script/cibuild` passes at head `3dc1999` (fmt-check, lint, test, build).

refs #39

Co-authored-by: sneak <sneak@sneak.berlin>
Co-authored-by: Jeffrey Paul <sneak@noreply.example.org>
Reviewed-on: #46
Co-authored-by: clawbot <clawbot@noreply.example.org>
Co-committed-by: clawbot <clawbot@noreply.example.org>
2026-08-07 17:44:00 +02:00