clone

a self-hosted multitenant nostr relay with sites, file storage, git hosting, and inbox and outbox delivery

main
tinyrelay / internal / daemon / blob_report_acceptance_test.go
blob_report_acceptance_test.go 3.1K
1package daemon23import (4 "bytes"5 "context"6 "crypto/sha256"7 "encoding/base64"8 "encoding/hex"9 "encoding/json"10 "net/http"11 "net/http/httptest"12 "strings"13 "testing"14 "time"1516 "github.com/FelineStateMachine/tinyrelay/internal/blob"17 "github.com/FelineStateMachine/tinyrelay/internal/community"18 "github.com/FelineStateMachine/tinyrelay/internal/event"19)2021func TestMountedBlobReportAppearsInCommunityModeration(t *testing.T) {22 ctx := context.Background()23 app, tenant := testTenant(t)24 reporterSecret := strings.Repeat("2", 64)25 reporter, err := event.PublicKey(reporterSecret)26 if err != nil {27 t.Fatal(err)28 }29 entry, err := tenant.blobs.Put(ctx, blobPutOptions("moderated blob", reporter))30 if err != nil {31 t.Fatal(err)32 }33 now := time.Now().Unix()34 report := event.Event{Kind: event.KIND_REPORT, CreatedAt: now, Tags: [][]string{{"x", entry.SHA256, "spam"}}, Content: "reported blob"}35 if err := event.Sign(&report, reporterSecret); err != nil {36 t.Fatal(err)37 }38 body, _ := json.Marshal(report)39 req := httptest.NewRequest(http.MethodPut, "http://relay.test/r/main/report", bytes.NewReader(body))40 req.Header.Set("Content-Type", "application/json")41 signBlobReport(t, req, body, reporterSecret)42 res := httptest.NewRecorder()43 app.ServeHTTP(res, req)44 if res.Code != http.StatusOK {45 t.Fatalf("report status=%d body=%s", res.Code, res.Body.String())46 }4748 value, err := tenant.community.Execute(ctx, tenant.Policy().Owner, "listreports", reportArgs("open"))49 if err != nil {50 t.Fatal(err)51 }52 reports := value.([]community.Report)53 if len(reports) != 1 || reports[0].TargetEvent != entry.SHA256 || reports[0].Type != "blob" {54 t.Fatalf("shared reports=%+v", reports)55 }56 if _, err := tenant.community.Execute(ctx, tenant.Policy().Owner, "resolvereport", reportArgs(reports[0].ID, "dismiss")); err != nil {57 t.Fatal(err)58 }59 var hidden int60 if err := tenant.store.DB().QueryRowContext(ctx, `SELECT count(*) FROM hidden_events WHERE id=?`, entry.SHA256).Scan(&hidden); err != nil {61 t.Fatal(err)62 }63 if hidden != 0 {64 t.Fatal("blob report hid an event")65 }66 var status string67 if err := tenant.store.DB().QueryRowContext(ctx, `SELECT status FROM blob_reports WHERE target_blob=?`, entry.SHA256).Scan(&status); err != nil {68 t.Fatal(err)69 }70 if status != "resolved" {71 t.Fatalf("blob report status=%q", status)72 }73}7475func blobPutOptions(content, uploader string) blob.PutOptions {76 return blob.PutOptions{Reader: strings.NewReader(content), Type: "text/plain", Uploader: uploader}77}7879func reportArgs(values ...any) []json.RawMessage {80 out := make([]json.RawMessage, len(values))81 for i, value := range values {82 out[i], _ = json.Marshal(value)83 }84 return out85}8687func signBlobReport(t *testing.T, req *http.Request, body []byte, secret string) {88 t.Helper()89 hash := sha256.Sum256(body)90 token := event.Event{Kind: 27235, CreatedAt: time.Now().Unix(), Tags: [][]string{{"u", req.URL.String()}, {"method", req.Method}, {"payload", hex.EncodeToString(hash[:])}}}91 if err := event.Sign(&token, secret); err != nil {92 t.Fatal(err)93 }94 raw, err := json.Marshal(token)95 if err != nil {96 t.Fatal(err)97 }98 req.Header.Set("Authorization", "Nostr "+base64.StdEncoding.EncodeToString(raw))99}