mirror of
https://github.com/Noooste/garage-ui.git
synced 2026-07-26 07:48:13 +00:00
c0976a1e1d
* 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
123 lines
4.0 KiB
Go
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")
|
|
}
|
|
}
|