package api
import (
"strings"
"testing"
"craftdesign.group/quarry/internal/oltp"
)
// The type comes from the BYTES, never from what the upload claimed.
// This image is served from the forge's own origin to every reader of
// every page it appears on, so the uploader's word for it is not
// evidence.
func TestTheTypeIsReadFromTheBytes(t *testing.T) {
for _, c := range []struct {
name string
raw string
want string
}{
{"png", "\x89PNG\r\n\x1a\nrest", "image/png"},
{"jpeg", "\xff\xd8\xff\xe0rest", "image/jpeg"},
{"gif87", "GIF87arest", "image/gif"},
{"gif89", "GIF89arest", "image/gif"},
{"webp", "RIFF\x00\x00\x00\x00WEBPVP8 ", "image/webp"},
} {
got, err := sniffAvatar([]byte(c.raw))
if err != nil || got != c.want {
t.Errorf("FAIL: %s sniffed as %q (err=%v), want %q", c.name, got, err, c.want)
}
}
}
// SVG is a document: it can carry script and fetch from other hosts,
// and it would be served from the forge's own origin. Refused, and
// the refusal is not an accident of the magic table.
func TestAnSVGIsNotAnImageHere(t *testing.T) {
for _, raw := range []string{
`<svg xmlns="http://www.w3.org/2000/svg"><script>alert(1)</script></svg>`,
"<?xml version=\"1.0\"?><svg/>",
} {
if got, err := sniffAvatar([]byte(raw)); err == nil {
t.Errorf("FAIL: an SVG was accepted as %q", got)
}
}
}
// RIFF alone is a container; only the WEBP form of it is an image a
// browser draws. A RIFF that is something else (a WAV, say) must not
// be stored as an image/webp the forge then serves.
func TestARIFFThatIsNotWebPIsRefused(t *testing.T) {
wav := "RIFF\x00\x00\x00\x00WAVEfmt "
if got, err := sniffAvatar([]byte(wav)); err == nil {
t.Errorf("FAIL: a WAV was accepted as %q", got)
}
}
// Anything unrecognised is refused rather than stored as some default.
func TestUnrecognisedBytesAreRefused(t *testing.T) {
for _, raw := range []string{"", "hello", "\x00\x01\x02\x03"} {
if _, err := sniffAvatar([]byte(raw)); err == nil {
t.Errorf("FAIL: %q was accepted", raw)
}
}
}
// The digest is in the key, so replacing a mark writes a NEW object
// rather than overwriting one a reader may be mid-fetch of — and a
// cache can never hold the wrong image for a key it already has.
func TestTheKeyCarriesTheDigest(t *testing.T) {
a := avatarKey(oltp.AvatarRepo, "quarry", strings.Repeat("a", 64))
b := avatarKey(oltp.AvatarRepo, "quarry", strings.Repeat("b", 64))
if a == b {
t.Errorf("FAIL: two different images share a key: %s", a)
}
if !strings.HasPrefix(a, "avatars/repo/quarry/") {
t.Errorf("FAIL: key = %q", a)
}
// A team and a repository of one name do not collide.
if avatarKey(oltp.AvatarTeam, "quarry", strings.Repeat("a", 64)) == a {
t.Errorf("FAIL: a team and a repository share a key")
}
}