package signature_test import ( "testing" "time" "sneak.berlin/go/pixa/internal/signature" ) // Fixed inputs for the quality/fit golden vectors. They are independent of // the constants in golden_test.go so this file pins the current signed // format on its own. const ( qfSigningKey = "golden-test-key" qfExpiresUnix int64 = 1704067200 // 2024-01-01T00:00:00Z qfFitCover = "cover" qfFitContain = "contain" ) type qualityFitGoldenVector struct { name string req signature.Request // wantSignature is the exact base64url (RFC 4648 URL-safe, padded) // HMAC-SHA256 signature for the request with Expires set to // qfExpiresUnix, under the signed format // "host:path:query:width:height:format:expiration:quality:fit". wantSignature string } // qualityFitGoldenVectors returns the known-answer vectors that pin quality // and fit as signed components. The three default-value vectors use the // effective quality (85) and fit ("cover") the handler applies when a URL // omits q and fit, so they are the signatures real signed URLs must carry. func qualityFitGoldenVectors() []qualityFitGoldenVector { return []qualityFitGoldenVector{ { name: "resized, default quality and fit", req: signature.Request{ SourceHost: testHost, SourcePath: testPath, Width: 800, Height: 600, Format: testFormatWebP, Quality: 85, FitMode: qfFitCover, }, // "cdn.example.com:/photos/cat.jpg::800:600:webp:1704067200:85:cover" wantSignature: "kdqeGoW2SX7qnaYtoB970wEnLydn0UnIgQYQLfAnjXQ=", }, { name: "resized with query, default quality and fit", req: signature.Request{ SourceHost: testHost, SourcePath: testPath, SourceQuery: "token=abc&v=2", Width: 800, Height: 600, Format: testFormatWebP, Quality: 85, FitMode: qfFitCover, }, // "cdn.example.com:/photos/cat.jpg:token=abc&v=2:800:600:webp:1704067200:85:cover" wantSignature: "pKgVBOTd_Q_EikI7MNQLC9Q8Hurdxzyv3EIYvVhqc2I=", }, { name: "original size, default quality and fit", req: signature.Request{ SourceHost: testHost, SourcePath: testPath, Width: 0, Height: 0, Format: testFormatPNG, Quality: 85, FitMode: qfFitCover, }, // "cdn.example.com:/photos/cat.jpg::0:0:png:1704067200:85:cover" wantSignature: "6_rZ0yyVbGZRs8kG7n7HLgLi5Jt8vjiWQljIEL1jbIs=", }, { name: "non-default quality and fit", req: signature.Request{ SourceHost: testHost, SourcePath: testPath, Width: 800, Height: 600, Format: testFormatWebP, Quality: 40, FitMode: qfFitContain, }, // "cdn.example.com:/photos/cat.jpg::800:600:webp:1704067200:40:contain" wantSignature: "pGaXpPUbI3A7nMx-4T9bfq9bYWBNL0kY4bxlcv3g1F8=", }, } } // TestSigner_GoldenVectors_QualityFit pins the exact HMAC-SHA256 signature // output for requests that carry quality and fit as signed components. If // these assertions fail, the signed byte format // ("host:path:query:width:height:format:expiration:quality:fit") or the // base64url encoding has changed, breaking every signature already issued. // Update these constants only as part of a deliberate, documented signature // format migration. func TestSigner_GoldenVectors_QualityFit(t *testing.T) { t.Parallel() signer := signature.New(qfSigningKey) for _, tt := range qualityFitGoldenVectors() { t.Run(tt.name, func(t *testing.T) { t.Parallel() signReq := tt.req signReq.Expires = time.Unix(qfExpiresUnix, 0) gotSignature := signer.Sign(&signReq) if gotSignature != tt.wantSignature { t.Errorf("Sign() = %q, want %q (signed byte format changed?)", gotSignature, tt.wantSignature) } }) } }