Something went wrong. Try again.
This repository has no description
Something went wrong. Try again.
9.0 kB · 256 lines
Go
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257package muxl
import ( "bytes" "context" "encoding/json" "os" "path/filepath" "runtime" "sort" "testing" "time"
"github.com/stretchr/testify/require")
// signedM4sStream signs the fragmented fixture through sign-segment and// reassembles the per-track signed canonical-segment bytes into one bare// .m4s stream — the storage/wire form Streamplace keeps and feeds back to// verify/wrap. Returns ("", "") via t.Skip if the sibling muxl keys are// missing.func signedM4sStream(t *testing.T) []byte { t.Helper() _, thisFile, _, _ := runtime.Caller(0) repoRoot := filepath.Join(filepath.Dir(thisFile), "..", "..") muxlRoot := filepath.Join(repoRoot, "..", "muxl")
keyPEM, err := os.ReadFile(filepath.Join(muxlRoot, "samples/test-keys/es256k-key.pem")) if err != nil { t.Skipf("skipping; sibling muxl repo with test keys not available at %s: %v", muxlRoot, err) } certPEM, err := os.ReadFile(filepath.Join(muxlRoot, "samples/test-keys/es256k-cert.pem")) require.NoError(t, err) frag, err := os.ReadFile(filepath.Join(repoRoot, "test/fixtures/h264-opus-frag.mp4")) require.NoError(t, err)
manifest := []byte(`{ "title": "muxl verify/wrap integration test", "assertions": [ {"label": "c2pa.actions", "data": {"actions": [{"action": "c2pa.created"}]}} ] }`)
eventCh := make(chan *MuxlEvent, 16) errCh := make(chan error, 1) go func() { err := RunMuxlSignSegment(context.Background(), bytes.NewReader(frag), SignerInput{ CertPEM: certPEM, KeyPEM: keyPEM, TrackManifest: manifest, WrapperManifest: manifest, }, nil, nil, eventCh) close(eventCh) errCh <- err }()
var m4s []byte for ev := range eventCh { if ev.Type != "signed-segment" { continue } tids := make([]string, 0, len(ev.Tracks)) for tid := range ev.Tracks { tids = append(tids, tid) } sort.Strings(tids) for _, tid := range tids { m4s = append(m4s, ev.Tracks[tid]...) } } require.NoError(t, <-errCh) require.NotEmpty(t, m4s, "sign-segment produced no signed track bytes") return m4s}
// TestRunMuxlVerify confirms in-wasm c2pa validation of bare canonical .m4s:// the per-track signed segments verify standalone (no synthesized header),// and the JSON matches the manifest+cert shape the host parses.func TestRunMuxlVerify(t *testing.T) { m4s := signedM4sStream(t)
out, err := RunMuxlVerify(context.Background(), bytes.NewReader(m4s)) require.NoError(t, err)
var doc struct { Segments []struct { TrackID uint32 `json:"track_id"` Manifest json.RawMessage `json:"manifest"` Cert string `json:"cert"` ValidationState string `json:"validation_state"` } `json:"segments"` } require.NoError(t, json.Unmarshal([]byte(out), &doc), "verify output is JSON: %s", out) require.GreaterOrEqual(t, len(doc.Segments), 2, "expected video+audio segments") for i, seg := range doc.Segments { require.NotEmpty(t, seg.Manifest, "segment %d has a manifest", i) require.Contains(t, seg.Cert, "BEGIN CERTIFICATE", "segment %d has a PEM cert", i) require.NotEqual(t, "Invalid", seg.ValidationState, "segment %d validates", i) }}
// TestSignSegmentStampsCawgDate confirms the streaming signer stamps each// segment's signing time into cawg.metadata/dc:date — overwriting a base// placeholder — and that it round-trips through verify as a recent RFC3339// value (the form aqtime/ParseSegmentAssertions reads back as StartTime).func TestSignSegmentStampsCawgDate(t *testing.T) { _, thisFile, _, _ := runtime.Caller(0) repoRoot := filepath.Join(filepath.Dir(thisFile), "..", "..") muxlRoot := filepath.Join(repoRoot, "..", "muxl")
keyPEM, err := os.ReadFile(filepath.Join(muxlRoot, "samples/test-keys/es256k-key.pem")) if err != nil { t.Skipf("skipping; sibling muxl test keys not available at %s: %v", muxlRoot, err) } certPEM, err := os.ReadFile(filepath.Join(muxlRoot, "samples/test-keys/es256k-cert.pem")) require.NoError(t, err) frag, err := os.ReadFile(filepath.Join(repoRoot, "test/fixtures/h264-opus-frag.mp4")) require.NoError(t, err)
// Base manifest carries a cawg.metadata with a placeholder dc:date — the // signer must overwrite it per segment (the mutate path). manifest := []byte(`{ "title": "stamp test", "assertions": [ {"label":"c2pa.actions","data":{"actions":[{"action":"c2pa.created"}]}}, {"label":"cawg.metadata","data":{ "@context":{"dc":"http://purl.org/dc/elements/1.1/"}, "dc:creator":"did:example","dc:title":"t", "dc:date":"1970-01-01T00:00:00.000Z" }} ] }`)
eventCh := make(chan *MuxlEvent, 16) errCh := make(chan error, 1) go func() { err := RunMuxlSignSegment(context.Background(), bytes.NewReader(frag), SignerInput{ CertPEM: certPEM, KeyPEM: keyPEM, TrackManifest: manifest, WrapperManifest: manifest, }, nil, nil, eventCh) close(eventCh) errCh <- err }() var m4s []byte for ev := range eventCh { if ev.Type != "signed-segment" { continue } tids := make([]string, 0, len(ev.Tracks)) for tid := range ev.Tracks { tids = append(tids, tid) } sort.Strings(tids) for _, tid := range tids { m4s = append(m4s, ev.Tracks[tid]...) } } require.NoError(t, <-errCh) require.NotEmpty(t, m4s)
out, err := RunMuxlVerify(context.Background(), bytes.NewReader(m4s)) require.NoError(t, err)
var doc struct { Segments []struct { Manifest struct { Assertions []struct { Label string `json:"label"` Data map[string]interface{} `json:"data"` } `json:"assertions"` } `json:"manifest"` } `json:"segments"` } require.NoError(t, json.Unmarshal([]byte(out), &doc)) require.NotEmpty(t, doc.Segments)
var date string for _, a := range doc.Segments[0].Manifest.Assertions { if a.Label == "cawg.metadata" { if d, ok := a.Data["dc:date"].(string); ok { date = d } } } require.NotEmpty(t, date, "cawg.metadata should carry a dc:date") require.NotEqual(t, "1970-01-01T00:00:00.000Z", date, "placeholder dc:date must be overwritten with sign time") ts, err := time.Parse(time.RFC3339, date) require.NoError(t, err, "dc:date must be RFC3339, got %q", date) require.WithinDuration(t, time.Now(), ts, 10*time.Minute, "dc:date should be ~now (sign time)")}
// TestRunMuxlUnwrapEvents confirms re-deriving the per-track event stream// from stored signed segments: one init event (catalog + per-track inits) and// one segment event per GoP, with non-zero durations and the per-track bytes// preserved verbatim — each still leads with the c2pa uuid box.func TestRunMuxlUnwrapEvents(t *testing.T) { m4s := signedM4sStream(t)
eventCh := make(chan *MuxlEvent, 16) errCh := make(chan error, 1) go func() { err := RunMuxlUnwrapEvents(context.Background(), bytes.NewReader(m4s), eventCh) close(eventCh) errCh <- err }()
initEvents, segEvents := 0, 0 for ev := range eventCh { switch ev.Type { case "init": initEvents++ require.NotEmpty(t, ev.TrackInits, "init event carries per-track init segments") require.NotNil(t, ev.Catalog, "init event carries the catalog") case "segment": segEvents++ require.NotEmpty(t, ev.Tracks, "segment event has tracks") for tid, d := range ev.Durations { require.Greater(t, d, uint64(0), "track %s duration must be > 0", tid) } for tid, b := range ev.Tracks { require.GreaterOrEqual(t, len(b), 8, "track %s segment too short", tid) require.Equal(t, "uuid", string(b[4:8]), "track %s segment must be the verbatim signed .m4s (leads with a uuid box)", tid) } } } require.NoError(t, <-errCh) require.Equal(t, 1, initEvents, "exactly one init event") require.GreaterOrEqual(t, segEvents, 2, "expected multiple GoP segment events")}
// TestRunMuxlWrap confirms the inbound header-synthesis: a bare signed .m4s// stream wraps into a playable fMP4 (and an init-only header), with the// segment bytes carried through verbatim.func TestRunMuxlWrap(t *testing.T) { m4s := signedM4sStream(t)
var fmp4 bytes.Buffer require.NoError(t, RunMuxlWrap(context.Background(), bytes.NewReader(m4s), "fmp4", &fmp4)) require.Greater(t, fmp4.Len(), len(m4s), "wrapped fMP4 should be larger than the bare segments") require.True(t, bytes.Contains(fmp4.Bytes()[:64], []byte("ftyp")), "wrapped output starts with an ftyp box (got %x)", fmp4.Bytes()[:32]) // The signed segment bytes pass through verbatim — the bare stream is a // substring of the wrapped fMP4 (header is prepended, segments untouched). require.True(t, bytes.Contains(fmp4.Bytes(), m4s), "wrapped fMP4 must contain the verbatim signed segment bytes")
var init bytes.Buffer require.NoError(t, RunMuxlWrapInit(context.Background(), bytes.NewReader(m4s), &init)) require.True(t, bytes.Contains(init.Bytes()[:64], []byte("ftyp")), "init-only output starts with an ftyp box") require.Less(t, init.Len(), fmp4.Len(), "init-only is smaller than the full wrap")}