package attach_test import ( "bytes" "encoding/binary" "hash/crc32" "image" "image/color" "image/gif" "image/jpeg" "image/png" "testing" "git.golem15.com/golem15/summercms/modules/lagoon/attach" ) // guardWebP is a 16x12 lossless WebP. var guardWebP = []byte{ 0x52, 0x49, 0x46, 0x46, 0x2a, 0x00, 0x00, 0x00, 0x57, 0x45, 0x42, 0x50, 0x56, 0x50, 0x38, 0x4c, 0x1d, 0x00, 0x00, 0x00, 0x2f, 0x0f, 0xc0, 0x02, 0x00, 0x0f, 0x70, 0x14, 0xfb, 0x53, 0xd0, 0x5e, 0x88, 0x7b, 0xfe, 0x83, 0x07, 0x62, 0xc1, 0x64, 0xfe, 0xd2, 0xbd, 0x21, 0x44, 0xf4, 0x3f, 0x74, 0x01, 0x00, } func guardGIF(t *testing.T) []byte { t.Helper() var buf bytes.Buffer if err := gif.Encode(&buf, image.NewPaletted(image.Rect(0, 0, 3, 2), []color.Color{color.Black, color.White}), nil); err != nil { t.Fatal(err) } return buf.Bytes() } func guardJPEG(t *testing.T) []byte { t.Helper() var buf bytes.Buffer if err := jpeg.Encode(&buf, image.NewRGBA(image.Rect(0, 0, 3, 2)), nil); err != nil { t.Fatal(err) } return buf.Bytes() } // pngHeader is a PNG signature and a valid IHDR chunk for w x h, the part // image.DecodeConfig reads, without pixel data. func pngHeader(w, h uint32) []byte { var ihdr bytes.Buffer ihdr.WriteString("IHDR") _ = binary.Write(&ihdr, binary.BigEndian, w) _ = binary.Write(&ihdr, binary.BigEndian, h) ihdr.Write([]byte{8, 0, 0, 0, 0}) // 8-bit grayscale, no interlace var out bytes.Buffer out.Write([]byte("\x89PNG\r\n\x1a\n")) _ = binary.Write(&out, binary.BigEndian, uint32(13)) out.Write(ihdr.Bytes()) _ = binary.Write(&out, binary.BigEndian, crc32.ChecksumIEEE(ihdr.Bytes())) return out.Bytes() } // TestIsAllowedImageAccepts the four formats the thumbnailer decodes, and // an image exactly at the pixel ceiling. func TestIsAllowedImageAccepts(t *testing.T) { var p bytes.Buffer if err := png.Encode(&p, image.NewRGBA(image.Rect(0, 0, 2, 2))); err != nil { t.Fatal(err) } for name, data := range map[string][]byte{ "png": p.Bytes(), "gif": guardGIF(t), "jpeg": guardJPEG(t), "webp": guardWebP, "at the ceiling": pngHeader(4096, 4096), "one tall column": pngHeader(1, 4096*4096), } { if !attach.IsAllowedImage(data) { t.Errorf("%s refused", name) } } if attach.MaxImagePixels != 4096*4096 { t.Fatalf("MaxImagePixels = %d", attach.MaxImagePixels) } } // TestIsAllowedImageRefuses SVG, HTML, a GIF signature followed by script, // a truncated PNG, empty input, an image over 4096x4096 pixels, a zero-size // image and a BMP (a real image the thumbnailer does not decode). func TestIsAllowedImageRefuses(t *testing.T) { var p bytes.Buffer if err := png.Encode(&p, image.NewRGBA(image.Rect(0, 0, 8, 8))); err != nil { t.Fatal(err) } bmp := append([]byte("BM"), make([]byte, 60)...) for name, data := range map[string][]byte{ "svg": []byte(``), "html": []byte(""), "gif polyglot": []byte("GIF89a"), "png polyglot": append([]byte("\x89PNG\r\n\x1a\n"), []byte("")...), "truncated png": p.Bytes()[:20], "empty": nil, "over the ceiling": pngHeader(4097, 4096), "huge": pngHeader(100000, 100000), "zero width": pngHeader(0, 10), "bmp": bmp, "text": []byte("just text"), } { if attach.IsAllowedImage(data) { t.Errorf("%s accepted", name) } } }