| 1 | package tinyclient |
| 2 | |
| 3 | import ( |
| 4 | "strings" |
| 5 | "testing" |
| 6 | ) |
| 7 | |
| 8 | func TestRoomAttachmentsParsesNIP92AndStripsReferences(t *testing.T) { |
| 9 | url := "https://cdn.example.test/photo.png" |
| 10 | row := map[string]any{"content" : "Look  and " + url, "tags" : [][]string{{"imeta" , "url " + url, "m image/png" , "x " + strings.Repeat("a" , 64), "size 42" , "alt a <photo>" }}} |
| 11 | got := roomAttachments(row) |
| 12 | if len(got) != 1 || got[0].URL != url || got[0].MIME != "image/png" || got[0].Hash != strings.Repeat("a" , 64) || got[0].Size != 42 || got[0].Name != "a <photo>" { |
| 13 | t.Fatalf("attachments = %#v" , got) |
| 14 | } |
| 15 | if text := roomAttachmentContent(valueMap(row)["content" ].(string), got); text != valueMap(row)["content" ].(string) { |
| 16 | t.Fatalf("content = %q" , text) |
| 17 | } |
| 18 | } |
| 19 | |
| 20 | func TestRoomAttachmentsRejectUnsafeAndBoundValues(t *testing.T) { |
| 21 | long := strings.Repeat("x" , 5000) |
| 22 | row := map[string]any{"content" : "https://cdn.example/file" , "tags" : [][]string{{"imeta" , "url javascript:alert(1)" , "m image/svg+xml" }, {"imeta" , "url data:image/png;base64,abc" , "m image/png" }, {"imeta" , "url https://cdn.example/file" , "m application/octet-stream" , "filename " + long}}} |
| 23 | got := roomAttachments(row) |
| 24 | if len(got) != 1 || got[0].URL != "https://cdn.example/file" { |
| 25 | t.Fatalf("unsafe attachments = %#v" , got) |
| 26 | } |
| 27 | } |
| 28 | |
| 29 | func TestRoomAttachmentsIgnoreCodeAndDeduplicate(t *testing.T) { |
| 30 | url := "https://cdn.example.test/photo.png" |
| 31 | row := map[string]any{"content" : "`" + url + "`\n" + url, "tags" : [][]string{{"imeta" , "url " + url, "m image/png" }, {"imeta" , "url " + url, "m image/png" }}} |
| 32 | if got := roomAttachments(row); len(got) != 1 { |
| 33 | t.Fatalf("attachments = %#v" , got) |
| 34 | } |
| 35 | row["content" ] = "```\n" + url + "\n```" |
| 36 | if got := roomAttachments(row); len(got) != 0 { |
| 37 | t.Fatalf("code attachment = %#v" , got) |
| 38 | } |
| 39 | } |
| 40 | |
| 41 | func TestRoomAttachmentMarkupEscapesAndClassifiesMedia(t *testing.T) { |
| 42 | items := []roomAttachment{{URL: "https://cdn.example/a.mp4?a=1&b=2" , MIME: "video/mp4" , Name: "A \"clip\"" }, {URL: "https://cdn.example/report.pdf" , MIME: "application/pdf" , Name: "report.pdf" , Size: 2048}} |
| 43 | markup := string(roomAttachmentMarkup(items)) |
| 44 | for _, want := range []string{"room-attachments" , "<video" , "controls" , "report.pdf" , "download" , "2 KB" } { |
| 45 | if !strings.Contains(markup, want) { |
| 46 | t.Errorf("markup missing %q: %s" , want, markup) |
| 47 | } |
| 48 | } |
| 49 | if strings.Contains(markup, `class=` ) || strings.Contains(markup, `javascript:` ) { |
| 50 | t.Fatalf("unsafe markup: %s" , markup) |
| 51 | } |
| 52 | } |