Files
garage-ui/backend/internal/auth/preview_test.go
T
Noste c0976a1e1d feat(preview): Implement object preview functionality (#94)
* feat(preview): implement object preview functionality with token-based access

* docs: update README to include inline object preview feature

* test: add range read error handling and attachment content disposition tests
2026-07-15 00:01:04 +02:00

123 lines
4.0 KiB
Go

package auth
import (
"encoding/base64"
"strings"
"testing"
"time"
)
func newPreviewTestService(t *testing.T) *Service {
t.Helper()
jwtSvc, err := NewJWTService()
if err != nil {
t.Fatalf("NewJWTService: %v", err)
}
return &Service{jwtService: jwtSvc}
}
func TestPreviewToken_RoundTrip(t *testing.T) {
svc := newPreviewTestService(t)
token, expiresAt, err := svc.MintPreviewToken("b1", "dir/clip.mp4", time.Hour)
if err != nil {
t.Fatalf("MintPreviewToken: %v", err)
}
if remaining := time.Until(expiresAt); remaining < 59*time.Minute || remaining > time.Hour {
t.Errorf("expiresAt %v is not about an hour away", expiresAt)
}
if err := svc.ValidatePreviewToken(token, "b1", "dir/clip.mp4"); err != nil {
t.Errorf("ValidatePreviewToken: %v", err)
}
}
func TestPreviewToken_Expired(t *testing.T) {
svc := newPreviewTestService(t)
token, _, err := svc.MintPreviewToken("b1", "k", -time.Minute)
if err != nil {
t.Fatalf("MintPreviewToken: %v", err)
}
if err := svc.ValidatePreviewToken(token, "b1", "k"); err == nil {
t.Error("expected expired token to be rejected")
}
}
func TestPreviewToken_WrongObject(t *testing.T) {
svc := newPreviewTestService(t)
token, _, err := svc.MintPreviewToken("b1", "k1", time.Hour)
if err != nil {
t.Fatalf("MintPreviewToken: %v", err)
}
if err := svc.ValidatePreviewToken(token, "b2", "k1"); err == nil {
t.Error("expected wrong bucket to be rejected")
}
if err := svc.ValidatePreviewToken(token, "b1", "k2"); err == nil {
t.Error("expected wrong key to be rejected")
}
}
func TestPreviewToken_Tampered(t *testing.T) {
svc := newPreviewTestService(t)
token, _, err := svc.MintPreviewToken("b1", "k", time.Hour)
if err != nil {
t.Fatalf("MintPreviewToken: %v", err)
}
payload, sig, _ := strings.Cut(token, ".")
flipped := "A" + payload[1:]
if flipped == payload {
flipped = "B" + payload[1:]
}
if err := svc.ValidatePreviewToken(flipped+"."+sig, "b1", "k"); err == nil {
t.Error("expected tampered payload to be rejected")
}
if err := svc.ValidatePreviewToken(payload+".AAAA", "b1", "k"); err == nil {
t.Error("expected tampered signature to be rejected")
}
}
func TestPreviewToken_Malformed(t *testing.T) {
svc := newPreviewTestService(t)
for _, tok := range []string{"", "nodot", "a.b.c", "!!!.???", "bm90anNvbg.sig"} {
if err := svc.ValidatePreviewToken(tok, "b1", "k"); err == nil {
t.Errorf("expected malformed token %q to be rejected", tok)
}
}
}
func TestPreviewToken_DifferentServicesRejectEachOther(t *testing.T) {
a := newPreviewTestService(t)
b := newPreviewTestService(t)
token, _, err := a.MintPreviewToken("b1", "k", time.Hour)
if err != nil {
t.Fatalf("MintPreviewToken: %v", err)
}
if err := b.ValidatePreviewToken(token, "b1", "k"); err == nil {
t.Error("expected a token from another key to be rejected")
}
}
// TestPreviewToken_ValidSignatureMalformedBase64Payload signs a payload that
// is not valid RawURLEncoding, so the signature check passes but the base64
// decode fails. This exercises the decode error branch in verifyPreviewToken.
func TestPreviewToken_ValidSignatureMalformedBase64Payload(t *testing.T) {
svc := newPreviewTestService(t)
secret := svc.jwtService.previewSecret()
enc := "!!not-base64!!"
token := enc + "." + signPreview(secret, enc)
if err := svc.ValidatePreviewToken(token, "b1", "k"); err == nil {
t.Error("expected a validly signed but non-base64 payload to be rejected")
}
}
// TestPreviewToken_ValidSignatureNonJSONPayload signs a valid base64 payload
// whose bytes are not JSON, so the signature and decode both pass but the
// unmarshal fails. This exercises the JSON error branch in verifyPreviewToken.
func TestPreviewToken_ValidSignatureNonJSONPayload(t *testing.T) {
svc := newPreviewTestService(t)
secret := svc.jwtService.previewSecret()
enc := base64.RawURLEncoding.EncodeToString([]byte("not json"))
token := enc + "." + signPreview(secret, enc)
if err := svc.ValidatePreviewToken(token, "b1", "k"); err == nil {
t.Error("expected a validly signed but non-JSON payload to be rejected")
}
}