package callmemory import ( "context" "data-terminal-cloud/internal/volcsubtitle" "github.com/google/uuid" "net/url" "strings" "testing" ) func TestRecordingIdentityAndSignedURL(t *testing.T) { prefixes, err := recordingPrefixes("KP01-020026091601", "bot_20260927080903000") if err != nil { t.Fatal(err) } key := prefixes[0] + "1790467744348_000058_c014e733.mp4" record, ok := parseRecording(key, prefixes[0], "USER", 1045859) if !ok || record.Duration != 58 || record.ID == "" { t.Fatal(record, ok) } for _, bad := range []string{strings.Replace(key, "KP01-020026091601", "other", 1), key + "/extra", strings.Replace(key, "000058", "invalid", 1)} { if _, ok := parseRecording(bad, prefixes[0], "USER", 1); ok { t.Fatal("accepted foreign/malformed object") } } if _, err = recordingPrefixes("../device", "bot_20260927080903000"); err == nil { t.Fatal("unsafe device") } if _, err = recordingPrefixes("device", "persistent-bot"); err == nil { t.Fatal("unverified room") } store, err := NewTOSRecordings("memory927", "cn-beijing", "test-ak", "test-sk", "") if err != nil { t.Fatal(err) } for _, action := range []string{"PLAY", "DOWNLOAD"} { if action == "PLAY" { if _, e := store.Sign(context.Background(), key, action, 60); e == nil { t.Fatal("default domain playback allowed") } if e := store.ConfigurePlayback("https://recordings.example.com"); e != nil { t.Fatal(e) } } signed, e := store.Sign(context.Background(), key, action, 60) if e != nil { t.Fatal(e) } u, e := url.Parse(signed) if e != nil { t.Fatal(e) } host := "memory927.tos-cn-beijing.volces.com" if action == "PLAY" { host = "recordings.example.com" } if u.Host != host || u.Scheme != "https" || u.Query().Get("response-content-type") != "audio/mp4" || u.Query().Get("X-Tos-Expires") != "60" { t.Fatal("incorrect direct URL options") } disposition := "inline" if action == "DOWNLOAD" { disposition = "attachment" } if !strings.HasPrefix(u.Query().Get("response-content-disposition"), disposition) { t.Fatal("wrong disposition") } } } func TestRecordingIdentityFromAuthenticatedSubtitle(t *testing.T) { f, d := directFixture(t) ctx := context.Background() sid := uuid.NewString() if _, err := f.s.DirectRequest(ctx, d, "start", DirectInput{SessionID: sid, BootID: f.boot}); err != nil { t.Fatal(err) } n := int64(1) packet := volcsubtitle.Packet{Type: "subtitle", Data: []volcsubtitle.Segment{{UserID: "bot_20260927080903000", RoundID: &n, Sequence: &n, Definite: true, Text: "你好"}}} if err := f.s.DirectSubtitle(ctx, sid, packet); err != nil { t.Fatal(err) } if err := f.s.DirectSubtitle(ctx, sid, packet); err != nil { t.Fatal("duplicate", err) } var stored string if err := f.p.QueryRow(ctx, `SELECT budget_snapshot->>'rtc_agent_user_id' FROM call_session WHERE id=$1::uuid`, sid).Scan(&stored); err != nil || stored != packet.Data[0].UserID { t.Fatal("identity not retained", err) } packet.Data[0].UserID = "bot_20260927090903000" if err := f.s.DirectSubtitle(ctx, sid, packet); err == nil { t.Fatal("room reassignment accepted") } } type fakeRecordings struct { items []CloudRecording listed, signed int seconds int64 } func (f *fakeRecordings) PlaybackReady() bool { return true } func (f *fakeRecordings) List(context.Context, string, string) ([]CloudRecording, error) { f.listed++ return f.items, nil } func (f *fakeRecordings) Sign(_ context.Context, key, action string, seconds int64) (string, error) { f.signed++ f.seconds = seconds return "https://memory927.tos-cn-beijing.volces.com/fixture", nil } func TestCloudRecordingAuthorization(t *testing.T) { f := setup(t) m, _, _ := f.call(t) f.exec(t, `UPDATE call_session SET budget_snapshot='{"device_name":"device","rtc_agent_user_id":"bot_20260927080903000"}' WHERE id=$1::uuid`, m.SessionID) // The fixture copies active consent types; explicitly add raw audio if absent. f.exec(t, `INSERT INTO consent_record(tenant_id,subject_id,consent_type,scope,policy_version,notice_digest,actor_user_id,evidence_ref) SELECT tenant_id,subject_id,'raw_audio_storage',scope,policy_version,notice_digest,actor_user_id,evidence_ref FROM consent_record c WHERE subject_id=$1::uuid AND NOT EXISTS(SELECT 1 FROM consent_record r WHERE r.subject_id=c.subject_id AND r.consent_type='raw_audio_storage') LIMIT 1`, f.subject) store := &fakeRecordings{items: []CloudRecording{{ID: hash([]byte("fixture")), Key: "fixture", Speaker: "USER", Duration: 58, Bytes: 100}}} f.s.ConfigureRecordings(store) in := recordingInput{ElderID: f.elder, SessionID: m.SessionID, RecordingID: store.items[0].ID, Action: "PLAY"} deny := func(code string) { t.Helper() _, e := f.s.MemoryRequest(context.Background(), f.principal, "calls/recording-access", jsonBytes(in)) if e == nil || !strings.Contains(e.Error(), code) { t.Fatalf("wanted %s got %v", code, e) } } deny("RECORDING_ACCESS_DENIED") if store.signed != 0 || store.listed != 0 { t.Fatal("storage accessed before authorization") } f.exec(t, `INSERT INTO recording_access_grant(tenant_id,subject_id,grantee_user_id,permission,purpose,granted_by,expires_at) VALUES($1::uuid,$2::uuid,'10000000-0000-0000-0000-000000000101','PLAY','test','10000000-0000-0000-0000-000000000101',now()+interval '90 seconds')`, f.tenant, f.subject) f.request(t, "calls/recording-access", in) if store.signed != 1 || store.seconds > 90 { t.Fatal("grant TTL not enforced") } in.Action = "DOWNLOAD" deny("RECORDING_ACCESS_DENIED") in.Action = "PLAY" in.RecordingID = hash([]byte("another-file")) deny("RECORDING_NOT_FOUND") in.RecordingID = store.items[0].ID in.SessionID = uuid.NewString() deny("CALL_NOT_FOUND") in.SessionID = m.SessionID other := setup(t) otherCall, _, _ := other.call(t) in.SessionID = otherCall.SessionID deny("CALL_NOT_FOUND") in.SessionID = m.SessionID before := store.signed f.exec(t, `UPDATE consent_record SET withdrawn_at=now() WHERE subject_id=$1::uuid AND consent_type='raw_audio_storage'`, f.subject) deny("RECORDING_ACCESS_DENIED") if store.signed != before { t.Fatal("revoked consent exposed URL") } }