check / check (push) Canceled after 0s
The new package internal/imagerequest holds the request type, its two parts Source and Transform, the Format and Fit types, the dimension and fit checks, the /v1/image/ path parsing and the variant key; it imports no other package of pixa. imgcache.ParsedURL, imgcache.ImageRequest, signature.Request, imageprocessor.Request, the second Size, format and fit types and the conversions between them are gone. The image processor takes a Transform only. encurl keeps a private struct with the token's short CBOR field names. VariantKey moves with the function that makes it. Tests follow the moved and renamed code; the tests of the removed conversions go with them. Model: opus-5-5
73 lines
1.9 KiB
Go
73 lines
1.9 KiB
Go
package signature_test
|
|
|
|
import (
|
|
"errors"
|
|
"testing"
|
|
"time"
|
|
|
|
"sneak.berlin/go/pixa/internal/imagerequest"
|
|
"sneak.berlin/go/pixa/internal/signature"
|
|
)
|
|
|
|
// signedQualityFitRequest returns a request signed for quality 85 and fit
|
|
// mode "cover", the effective defaults the handler applies before
|
|
// verification.
|
|
func signedQualityFitRequest(signer *signature.Signer) *imagerequest.Request {
|
|
req := &imagerequest.Request{
|
|
Source: imagerequest.Source{
|
|
Host: testHost,
|
|
Path: testPath,
|
|
},
|
|
Transform: imagerequest.Transform{
|
|
Size: imagerequest.Size{Width: 800, Height: 600},
|
|
Format: testFormatWebP,
|
|
Quality: 85,
|
|
FitMode: testFitCover,
|
|
},
|
|
Expires: time.Now().Add(1 * time.Hour),
|
|
}
|
|
req.Signature = signer.Sign(req)
|
|
|
|
return req
|
|
}
|
|
|
|
// TestSigner_Verify_QualityAndFitAreSigned proves that quality and fit are
|
|
// covered by the signature: a URL signed for one quality or fit mode must
|
|
// not verify when replayed with a different quality or fit mode. This is the
|
|
// amplification vector from the issue — one signed URL replayed across many
|
|
// quality and fit values yields many unauthorized cache entries and
|
|
// transcodes — so it must be rejected.
|
|
func TestSigner_Verify_QualityAndFitAreSigned(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
signer := signature.New("test-secret-key")
|
|
|
|
cases := []struct {
|
|
name string
|
|
tamper func(r *imagerequest.Request)
|
|
}{
|
|
{
|
|
name: "replayed with different quality",
|
|
tamper: func(r *imagerequest.Request) { r.Transform.Quality = 40 },
|
|
},
|
|
{
|
|
name: "replayed with different fit mode",
|
|
tamper: func(r *imagerequest.Request) { r.Transform.FitMode = testFitContain },
|
|
},
|
|
}
|
|
|
|
for _, tt := range cases {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
t.Parallel()
|
|
|
|
req := signedQualityFitRequest(signer)
|
|
tt.tamper(req)
|
|
|
|
err := signer.Verify(req)
|
|
if !errors.Is(err, signature.ErrInvalid) {
|
|
t.Errorf("Verify() = %v, want %v", err, signature.ErrInvalid)
|
|
}
|
|
})
|
|
}
|
|
}
|