Profile page: - No WASM or video download until play button clicked - Play button visible immediately, loading on-demand - Removed auto-play behavior completely Streaming: - GetV3HeaderFromPrefix for parsing from partial data - v3 demo file with 128KB chunks for streaming tests
677 lines
17 KiB
Go
677 lines
17 KiB
Go
package smsg
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
func TestDeriveStreamKey(t *testing.T) {
|
|
// Test that same inputs produce same key
|
|
key1 := DeriveStreamKey("2026-01-12", "license123", "fingerprint456")
|
|
key2 := DeriveStreamKey("2026-01-12", "license123", "fingerprint456")
|
|
|
|
if len(key1) != 32 {
|
|
t.Errorf("Key length = %d, want 32", len(key1))
|
|
}
|
|
|
|
if string(key1) != string(key2) {
|
|
t.Error("Same inputs should produce same key")
|
|
}
|
|
|
|
// Test that different dates produce different keys
|
|
key3 := DeriveStreamKey("2026-01-13", "license123", "fingerprint456")
|
|
if string(key1) == string(key3) {
|
|
t.Error("Different dates should produce different keys")
|
|
}
|
|
|
|
// Test that different licenses produce different keys
|
|
key4 := DeriveStreamKey("2026-01-12", "license789", "fingerprint456")
|
|
if string(key1) == string(key4) {
|
|
t.Error("Different licenses should produce different keys")
|
|
}
|
|
}
|
|
|
|
func TestGetRollingDates(t *testing.T) {
|
|
today, tomorrow := GetRollingDates()
|
|
|
|
// Parse dates to verify format
|
|
todayTime, err := time.Parse("2006-01-02", today)
|
|
if err != nil {
|
|
t.Fatalf("Invalid today format: %v", err)
|
|
}
|
|
|
|
tomorrowTime, err := time.Parse("2006-01-02", tomorrow)
|
|
if err != nil {
|
|
t.Fatalf("Invalid tomorrow format: %v", err)
|
|
}
|
|
|
|
// Tomorrow should be 1 day after today
|
|
diff := tomorrowTime.Sub(todayTime)
|
|
if diff != 24*time.Hour {
|
|
t.Errorf("Tomorrow should be 24h after today, got %v", diff)
|
|
}
|
|
}
|
|
|
|
func TestWrapUnwrapCEK(t *testing.T) {
|
|
// Generate a test CEK
|
|
cek, err := GenerateCEK()
|
|
if err != nil {
|
|
t.Fatalf("GenerateCEK failed: %v", err)
|
|
}
|
|
|
|
// Generate a stream key
|
|
streamKey := DeriveStreamKey("2026-01-12", "test-license", "test-fp")
|
|
|
|
// Wrap CEK
|
|
wrapped, err := WrapCEK(cek, streamKey)
|
|
if err != nil {
|
|
t.Fatalf("WrapCEK failed: %v", err)
|
|
}
|
|
|
|
// Unwrap CEK
|
|
unwrapped, err := UnwrapCEK(wrapped, streamKey)
|
|
if err != nil {
|
|
t.Fatalf("UnwrapCEK failed: %v", err)
|
|
}
|
|
|
|
// Verify CEK matches
|
|
if string(cek) != string(unwrapped) {
|
|
t.Error("Unwrapped CEK doesn't match original")
|
|
}
|
|
|
|
// Wrong key should fail
|
|
wrongKey := DeriveStreamKey("2026-01-12", "wrong-license", "test-fp")
|
|
_, err = UnwrapCEK(wrapped, wrongKey)
|
|
if err == nil {
|
|
t.Error("UnwrapCEK with wrong key should fail")
|
|
}
|
|
}
|
|
|
|
func TestEncryptDecryptV3RoundTrip(t *testing.T) {
|
|
msg := NewMessage("Hello, this is a v3 streaming message!").
|
|
WithSubject("V3 Test").
|
|
WithFrom("stream@dapp.fm")
|
|
|
|
params := &StreamParams{
|
|
License: "test-license-123",
|
|
Fingerprint: "device-fp-456",
|
|
}
|
|
|
|
manifest := NewManifest("Test Track")
|
|
manifest.Artist = "Test Artist"
|
|
manifest.LicenseType = "stream"
|
|
|
|
// Encrypt
|
|
encrypted, err := EncryptV3(msg, params, manifest)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Decrypt with same params
|
|
decrypted, header, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Verify message content
|
|
if decrypted.Body != msg.Body {
|
|
t.Errorf("Body = %q, want %q", decrypted.Body, msg.Body)
|
|
}
|
|
if decrypted.Subject != msg.Subject {
|
|
t.Errorf("Subject = %q, want %q", decrypted.Subject, msg.Subject)
|
|
}
|
|
|
|
// Verify header
|
|
if header.Format != FormatV3 {
|
|
t.Errorf("Format = %q, want %q", header.Format, FormatV3)
|
|
}
|
|
if header.KeyMethod != KeyMethodLTHNRolling {
|
|
t.Errorf("KeyMethod = %q, want %q", header.KeyMethod, KeyMethodLTHNRolling)
|
|
}
|
|
if len(header.WrappedKeys) != 2 {
|
|
t.Errorf("WrappedKeys count = %d, want 2", len(header.WrappedKeys))
|
|
}
|
|
|
|
// Verify manifest
|
|
if header.Manifest == nil {
|
|
t.Fatal("Manifest is nil")
|
|
}
|
|
if header.Manifest.Title != "Test Track" {
|
|
t.Errorf("Manifest.Title = %q, want %q", header.Manifest.Title, "Test Track")
|
|
}
|
|
}
|
|
|
|
func TestDecryptV3WrongLicense(t *testing.T) {
|
|
msg := NewMessage("Secret content")
|
|
|
|
params := &StreamParams{
|
|
License: "correct-license",
|
|
Fingerprint: "device-fp",
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Try to decrypt with wrong license
|
|
wrongParams := &StreamParams{
|
|
License: "wrong-license",
|
|
Fingerprint: "device-fp",
|
|
}
|
|
|
|
_, _, err = DecryptV3(encrypted, wrongParams)
|
|
if err == nil {
|
|
t.Error("DecryptV3 with wrong license should fail")
|
|
}
|
|
if err != ErrNoValidKey {
|
|
t.Errorf("Error = %v, want ErrNoValidKey", err)
|
|
}
|
|
}
|
|
|
|
func TestDecryptV3WrongFingerprint(t *testing.T) {
|
|
msg := NewMessage("Secret content")
|
|
|
|
params := &StreamParams{
|
|
License: "test-license",
|
|
Fingerprint: "correct-fingerprint",
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Try to decrypt with wrong fingerprint
|
|
wrongParams := &StreamParams{
|
|
License: "test-license",
|
|
Fingerprint: "wrong-fingerprint",
|
|
}
|
|
|
|
_, _, err = DecryptV3(encrypted, wrongParams)
|
|
if err == nil {
|
|
t.Error("DecryptV3 with wrong fingerprint should fail")
|
|
}
|
|
}
|
|
|
|
func TestEncryptV3WithAttachment(t *testing.T) {
|
|
msg := NewMessage("Message with attachment")
|
|
msg.AddBinaryAttachment("test.mp3", []byte("fake audio data here"), "audio/mpeg")
|
|
|
|
params := &StreamParams{
|
|
License: "test-license",
|
|
Fingerprint: "test-fp",
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 failed: %v", err)
|
|
}
|
|
|
|
decrypted, _, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Verify attachment
|
|
if len(decrypted.Attachments) != 1 {
|
|
t.Fatalf("Attachment count = %d, want 1", len(decrypted.Attachments))
|
|
}
|
|
|
|
att := decrypted.GetAttachment("test.mp3")
|
|
if att == nil {
|
|
t.Fatal("Attachment not found")
|
|
}
|
|
if att.MimeType != "audio/mpeg" {
|
|
t.Errorf("MimeType = %q, want %q", att.MimeType, "audio/mpeg")
|
|
}
|
|
}
|
|
|
|
func TestEncryptV3RequiresLicense(t *testing.T) {
|
|
msg := NewMessage("Test")
|
|
|
|
// Nil params
|
|
_, err := EncryptV3(msg, nil, nil)
|
|
if err != ErrLicenseRequired {
|
|
t.Errorf("Error = %v, want ErrLicenseRequired", err)
|
|
}
|
|
|
|
// Empty license
|
|
_, err = EncryptV3(msg, &StreamParams{}, nil)
|
|
if err != ErrLicenseRequired {
|
|
t.Errorf("Error = %v, want ErrLicenseRequired", err)
|
|
}
|
|
}
|
|
|
|
func TestCadencePeriods(t *testing.T) {
|
|
// Test at a known time: 2026-01-12 15:30:00 UTC
|
|
testTime := time.Date(2026, 1, 12, 15, 30, 0, 0, time.UTC)
|
|
|
|
tests := []struct {
|
|
cadence Cadence
|
|
expectedCurrent string
|
|
expectedNext string
|
|
}{
|
|
{CadenceDaily, "2026-01-12", "2026-01-13"},
|
|
{CadenceHalfDay, "2026-01-12-PM", "2026-01-13-AM"},
|
|
{CadenceQuarter, "2026-01-12-12", "2026-01-12-18"},
|
|
{CadenceHourly, "2026-01-12-15", "2026-01-12-16"},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(string(tc.cadence), func(t *testing.T) {
|
|
current, next := GetRollingPeriods(tc.cadence, testTime)
|
|
if current != tc.expectedCurrent {
|
|
t.Errorf("current = %q, want %q", current, tc.expectedCurrent)
|
|
}
|
|
if next != tc.expectedNext {
|
|
t.Errorf("next = %q, want %q", next, tc.expectedNext)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCadenceHalfDayAM(t *testing.T) {
|
|
// Test in the morning
|
|
testTime := time.Date(2026, 1, 12, 9, 0, 0, 0, time.UTC)
|
|
current, next := GetRollingPeriods(CadenceHalfDay, testTime)
|
|
|
|
if current != "2026-01-12-AM" {
|
|
t.Errorf("current = %q, want %q", current, "2026-01-12-AM")
|
|
}
|
|
if next != "2026-01-12-PM" {
|
|
t.Errorf("next = %q, want %q", next, "2026-01-12-PM")
|
|
}
|
|
}
|
|
|
|
func TestCadenceQuarterBoundary(t *testing.T) {
|
|
// Test at 23:00 - should wrap to next day
|
|
testTime := time.Date(2026, 1, 12, 23, 0, 0, 0, time.UTC)
|
|
current, next := GetRollingPeriods(CadenceQuarter, testTime)
|
|
|
|
if current != "2026-01-12-18" {
|
|
t.Errorf("current = %q, want %q", current, "2026-01-12-18")
|
|
}
|
|
if next != "2026-01-13-00" {
|
|
t.Errorf("next = %q, want %q", next, "2026-01-13-00")
|
|
}
|
|
}
|
|
|
|
func TestEncryptDecryptV3WithCadence(t *testing.T) {
|
|
cadences := []Cadence{CadenceDaily, CadenceHalfDay, CadenceQuarter, CadenceHourly}
|
|
|
|
for _, cadence := range cadences {
|
|
t.Run(string(cadence), func(t *testing.T) {
|
|
msg := NewMessage("Testing " + string(cadence) + " cadence")
|
|
|
|
params := &StreamParams{
|
|
License: "cadence-test-license",
|
|
Fingerprint: "cadence-test-fp",
|
|
Cadence: cadence,
|
|
}
|
|
|
|
// Encrypt
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Decrypt with same params
|
|
decrypted, header, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 failed: %v", err)
|
|
}
|
|
|
|
if decrypted.Body != msg.Body {
|
|
t.Errorf("Body = %q, want %q", decrypted.Body, msg.Body)
|
|
}
|
|
|
|
// Verify cadence in header
|
|
if header.Cadence != cadence {
|
|
t.Errorf("Cadence = %q, want %q", header.Cadence, cadence)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestRollingKeyWindow(t *testing.T) {
|
|
// This test verifies that both today's and tomorrow's keys work
|
|
msg := NewMessage("Rolling window test")
|
|
|
|
// Create params
|
|
params := &StreamParams{
|
|
License: "rolling-test-license",
|
|
Fingerprint: "rolling-test-fp",
|
|
}
|
|
|
|
// Encrypt with current time
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 failed: %v", err)
|
|
}
|
|
|
|
// Should decrypt successfully (within rolling window)
|
|
decrypted, header, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 failed: %v", err)
|
|
}
|
|
|
|
if decrypted.Body != msg.Body {
|
|
t.Errorf("Body = %q, want %q", decrypted.Body, msg.Body)
|
|
}
|
|
|
|
// Verify we have both today and tomorrow keys
|
|
today, tomorrow := GetRollingDates()
|
|
hasToday := false
|
|
hasTomorrow := false
|
|
for _, wk := range header.WrappedKeys {
|
|
if wk.Date == today {
|
|
hasToday = true
|
|
}
|
|
if wk.Date == tomorrow {
|
|
hasTomorrow = true
|
|
}
|
|
}
|
|
if !hasToday {
|
|
t.Error("Missing today's wrapped key")
|
|
}
|
|
if !hasTomorrow {
|
|
t.Error("Missing tomorrow's wrapped key")
|
|
}
|
|
}
|
|
|
|
// =============================================================================
|
|
// V3 Chunked Streaming Tests
|
|
// =============================================================================
|
|
|
|
func TestEncryptDecryptV3ChunkedBasic(t *testing.T) {
|
|
msg := NewMessage("This is a chunked streaming test message")
|
|
msg.WithSubject("Chunked Test")
|
|
|
|
params := &StreamParams{
|
|
License: "chunk-license",
|
|
Fingerprint: "chunk-fp",
|
|
ChunkSize: 64, // Small chunks for testing
|
|
}
|
|
|
|
manifest := NewManifest("Chunked Track")
|
|
manifest.Artist = "Test Artist"
|
|
|
|
// Encrypt with chunking
|
|
encrypted, err := EncryptV3(msg, params, manifest)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
// Decrypt - automatically handles chunked format
|
|
decrypted, header, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
// Verify content
|
|
if decrypted.Body != msg.Body {
|
|
t.Errorf("Body = %q, want %q", decrypted.Body, msg.Body)
|
|
}
|
|
if decrypted.Subject != msg.Subject {
|
|
t.Errorf("Subject = %q, want %q", decrypted.Subject, msg.Subject)
|
|
}
|
|
|
|
// Verify header
|
|
if header.Format != FormatV3 {
|
|
t.Errorf("Format = %q, want %q", header.Format, FormatV3)
|
|
}
|
|
if header.Chunked == nil {
|
|
t.Fatal("Chunked info is nil")
|
|
}
|
|
if header.Chunked.ChunkSize != 64 {
|
|
t.Errorf("ChunkSize = %d, want 64", header.Chunked.ChunkSize)
|
|
}
|
|
}
|
|
|
|
func TestV3ChunkedWithAttachment(t *testing.T) {
|
|
// Create a message with attachment larger than chunk size
|
|
attachmentData := make([]byte, 256)
|
|
for i := range attachmentData {
|
|
attachmentData[i] = byte(i)
|
|
}
|
|
|
|
msg := NewMessage("Message with large attachment")
|
|
msg.AddBinaryAttachment("test.bin", attachmentData, "application/octet-stream")
|
|
|
|
params := &StreamParams{
|
|
License: "attach-license",
|
|
Fingerprint: "attach-fp",
|
|
ChunkSize: 64, // Force multiple chunks
|
|
}
|
|
|
|
// Encrypt
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
// Verify we have multiple chunks
|
|
header, err := GetV3Header(encrypted)
|
|
if err != nil {
|
|
t.Fatalf("GetV3Header failed: %v", err)
|
|
}
|
|
|
|
if header.Chunked.TotalChunks <= 1 {
|
|
t.Errorf("TotalChunks = %d, want > 1", header.Chunked.TotalChunks)
|
|
}
|
|
|
|
// Decrypt
|
|
decrypted, _, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
// Verify attachment
|
|
if len(decrypted.Attachments) != 1 {
|
|
t.Fatalf("Attachment count = %d, want 1", len(decrypted.Attachments))
|
|
}
|
|
}
|
|
|
|
func TestV3ChunkedIndividualChunks(t *testing.T) {
|
|
// Create content that spans multiple chunks
|
|
largeContent := make([]byte, 200)
|
|
for i := range largeContent {
|
|
largeContent[i] = byte(i % 256)
|
|
}
|
|
|
|
msg := NewMessage("Chunk-by-chunk test")
|
|
msg.AddBinaryAttachment("data.bin", largeContent, "application/octet-stream")
|
|
|
|
params := &StreamParams{
|
|
License: "individual-license",
|
|
Fingerprint: "individual-fp",
|
|
ChunkSize: 50, // Force ~5 chunks
|
|
}
|
|
|
|
// Encrypt
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
// Get header and payload
|
|
header, err := GetV3Header(encrypted)
|
|
if err != nil {
|
|
t.Fatalf("GetV3Header failed: %v", err)
|
|
}
|
|
|
|
payload, err := GetV3Payload(encrypted)
|
|
if err != nil {
|
|
t.Fatalf("GetV3Payload failed: %v", err)
|
|
}
|
|
|
|
// Unwrap CEK
|
|
cek, err := UnwrapCEKFromHeader(header, params)
|
|
if err != nil {
|
|
t.Fatalf("UnwrapCEKFromHeader failed: %v", err)
|
|
}
|
|
|
|
// Decrypt each chunk individually
|
|
var allDecrypted []byte
|
|
for i := 0; i < header.Chunked.TotalChunks; i++ {
|
|
chunk, err := DecryptV3Chunk(payload, cek, i, header.Chunked)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3Chunk(%d) failed: %v", i, err)
|
|
}
|
|
allDecrypted = append(allDecrypted, chunk...)
|
|
}
|
|
|
|
// Verify total size matches
|
|
if int64(len(allDecrypted)) != header.Chunked.TotalSize {
|
|
t.Errorf("Decrypted size = %d, want %d", len(allDecrypted), header.Chunked.TotalSize)
|
|
}
|
|
}
|
|
|
|
func TestV3ChunkedWrongLicense(t *testing.T) {
|
|
msg := NewMessage("Secret chunked content")
|
|
|
|
params := &StreamParams{
|
|
License: "correct-chunked-license",
|
|
Fingerprint: "device-fp",
|
|
ChunkSize: 64,
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
// Try to decrypt with wrong license
|
|
wrongParams := &StreamParams{
|
|
License: "wrong-chunked-license",
|
|
Fingerprint: "device-fp",
|
|
}
|
|
|
|
_, _, err = DecryptV3(encrypted, wrongParams)
|
|
if err == nil {
|
|
t.Error("DecryptV3 (chunked) with wrong license should fail")
|
|
}
|
|
if err != ErrNoValidKey {
|
|
t.Errorf("Error = %v, want ErrNoValidKey", err)
|
|
}
|
|
}
|
|
|
|
func TestV3ChunkedChunkIndex(t *testing.T) {
|
|
msg := NewMessage("Index test")
|
|
msg.AddBinaryAttachment("test.dat", make([]byte, 150), "application/octet-stream")
|
|
|
|
params := &StreamParams{
|
|
License: "index-license",
|
|
Fingerprint: "index-fp",
|
|
ChunkSize: 50,
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
header, err := GetV3Header(encrypted)
|
|
if err != nil {
|
|
t.Fatalf("GetV3Header failed: %v", err)
|
|
}
|
|
|
|
// Verify index structure
|
|
if len(header.Chunked.Index) != header.Chunked.TotalChunks {
|
|
t.Errorf("Index length = %d, want %d", len(header.Chunked.Index), header.Chunked.TotalChunks)
|
|
}
|
|
|
|
// Verify offsets are sequential
|
|
expectedOffset := 0
|
|
for i, ci := range header.Chunked.Index {
|
|
if ci.Offset != expectedOffset {
|
|
t.Errorf("Chunk %d offset = %d, want %d", i, ci.Offset, expectedOffset)
|
|
}
|
|
expectedOffset += ci.Size
|
|
}
|
|
}
|
|
|
|
func TestV3ChunkedSeekMiddleChunk(t *testing.T) {
|
|
// Create predictable data
|
|
data := make([]byte, 300)
|
|
for i := range data {
|
|
data[i] = byte(i % 256)
|
|
}
|
|
|
|
msg := NewMessage("Seek test")
|
|
msg.AddBinaryAttachment("seek.bin", data, "application/octet-stream")
|
|
|
|
params := &StreamParams{
|
|
License: "seek-license",
|
|
Fingerprint: "seek-fp",
|
|
ChunkSize: 100, // 3 data chunks minimum
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (chunked) failed: %v", err)
|
|
}
|
|
|
|
header, err := GetV3Header(encrypted)
|
|
if err != nil {
|
|
t.Fatalf("GetV3Header failed: %v", err)
|
|
}
|
|
|
|
payload, err := GetV3Payload(encrypted)
|
|
if err != nil {
|
|
t.Fatalf("GetV3Payload failed: %v", err)
|
|
}
|
|
|
|
cek, err := UnwrapCEKFromHeader(header, params)
|
|
if err != nil {
|
|
t.Fatalf("UnwrapCEKFromHeader failed: %v", err)
|
|
}
|
|
|
|
// Skip to middle chunk (simulate seeking)
|
|
if header.Chunked.TotalChunks < 2 {
|
|
t.Skip("Need at least 2 chunks for seek test")
|
|
}
|
|
|
|
middleIdx := header.Chunked.TotalChunks / 2
|
|
chunk, err := DecryptV3Chunk(payload, cek, middleIdx, header.Chunked)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3Chunk(%d) failed: %v", middleIdx, err)
|
|
}
|
|
|
|
// Just verify we got something
|
|
if len(chunk) == 0 {
|
|
t.Error("Middle chunk is empty")
|
|
}
|
|
}
|
|
|
|
func TestV3NonChunkedStillWorks(t *testing.T) {
|
|
// Verify non-chunked v3 still works (ChunkSize = 0)
|
|
msg := NewMessage("Non-chunked v3 test")
|
|
msg.WithSubject("No Chunks")
|
|
|
|
params := &StreamParams{
|
|
License: "non-chunk-license",
|
|
Fingerprint: "non-chunk-fp",
|
|
// ChunkSize = 0 (default) - no chunking
|
|
}
|
|
|
|
encrypted, err := EncryptV3(msg, params, nil)
|
|
if err != nil {
|
|
t.Fatalf("EncryptV3 (non-chunked) failed: %v", err)
|
|
}
|
|
|
|
decrypted, header, err := DecryptV3(encrypted, params)
|
|
if err != nil {
|
|
t.Fatalf("DecryptV3 (non-chunked) failed: %v", err)
|
|
}
|
|
|
|
if decrypted.Body != msg.Body {
|
|
t.Errorf("Body = %q, want %q", decrypted.Body, msg.Body)
|
|
}
|
|
|
|
// Non-chunked should not have Chunked info
|
|
if header.Chunked != nil {
|
|
t.Error("Non-chunked v3 should not have Chunked info")
|
|
}
|
|
}
|