Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
153 lines
3.9 KiB
Go
153 lines
3.9 KiB
Go
package company
|
|
|
|
import (
|
|
"bytes"
|
|
"image"
|
|
"image/png"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/security"
|
|
"github.com/google/uuid"
|
|
)
|
|
|
|
func TestValidateLogoURL_HostedAndHTTPS(t *testing.T) {
|
|
cid := uuid.MustParse("11111111-1111-1111-1111-111111111111")
|
|
name := "22222222-2222-2222-2222-222222222222.png"
|
|
|
|
got, err := ValidateLogoURL(BrandLogoURLPrefix+name, cid)
|
|
if err != nil || got != BrandLogoURLPrefix+name {
|
|
t.Fatalf("hosted: got=%q err=%v", got, err)
|
|
}
|
|
|
|
got, err = ValidateLogoURL("https://example.com/logo.png", cid)
|
|
if err != nil || !strings.HasPrefix(got, "https://") {
|
|
t.Fatalf("https: got=%q err=%v", got, err)
|
|
}
|
|
|
|
_, err = ValidateLogoURL(BrandLogoURLPrefix+"../etc/passwd", cid)
|
|
if err == nil {
|
|
t.Fatal("expected traversal reject")
|
|
}
|
|
|
|
_, err = ValidateLogoURL("/api/brand/logo/files/not-a-uuid.png", cid)
|
|
if err == nil {
|
|
t.Fatal("expected invalid name reject")
|
|
}
|
|
|
|
_, err = ValidateLogoURL("https://192.168.1.5/logo.png", cid)
|
|
if err == nil || !(err == security.ErrBlockedURL || err == security.ErrBlockedHost) {
|
|
t.Fatalf("expected blocked private host, got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSaveAndResolveBrandLogo(t *testing.T) {
|
|
dir := t.TempDir()
|
|
cid := uuid.New()
|
|
|
|
var buf bytes.Buffer
|
|
img := image.NewRGBA(image.Rect(0, 0, 8, 8))
|
|
if err := png.Encode(&buf, img); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
logoURL, abs, ct, size, err := SaveBrandLogo(dir, cid, "mark.png", "image/png", bytes.NewReader(buf.Bytes()))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if ct != "image/png" || size <= 0 {
|
|
t.Fatalf("ct=%s size=%d", ct, size)
|
|
}
|
|
name, ok := HostedLogoFilename(logoURL)
|
|
if !ok {
|
|
t.Fatalf("logoURL=%s", logoURL)
|
|
}
|
|
if _, err := os.Stat(abs); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
|
|
resolved, err := ResolveBrandLogoPath(dir, cid, name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if filepath.Clean(resolved) != filepath.Clean(abs) {
|
|
t.Fatalf("resolved=%s abs=%s", resolved, abs)
|
|
}
|
|
|
|
// Wrong company must not resolve another company's file via path tricks.
|
|
other := uuid.New()
|
|
_, err = ResolveBrandLogoPath(dir, other, name)
|
|
if err != nil {
|
|
// file simply missing for other company is fine; open should 404
|
|
}
|
|
_, _, err = OpenBrandLogo(dir, other, name)
|
|
if err != ErrLogoNotFound {
|
|
t.Fatalf("expected not found for other company, got %v", err)
|
|
}
|
|
|
|
// Reject path traversal names.
|
|
_, err = ResolveBrandLogoPath(dir, cid, "../../etc/passwd")
|
|
if err != ErrLogoInvalidName {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSaveBrandLogo_RejectsNonImage(t *testing.T) {
|
|
dir := t.TempDir()
|
|
_, _, _, _, err := SaveBrandLogo(dir, uuid.New(), "x.png", "image/png", strings.NewReader("not-an-image"))
|
|
if err != ErrLogoInvalidType {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
}
|
|
|
|
func TestSignAndVerifyPublicBrandLogo(t *testing.T) {
|
|
cid := uuid.New()
|
|
name := uuid.New().String() + ".png"
|
|
secret := "test-secret"
|
|
u, err := SignPublicBrandLogoURL("https://api.example.com", secret, cid, name, time.Hour)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(u, PublicBrandLogoPathPrefix) {
|
|
t.Fatalf("url=%s", u)
|
|
}
|
|
// Parse query
|
|
exp := time.Now().Add(time.Hour).Unix()
|
|
sig := signBrandLogo(secret, cid, name, exp)
|
|
// Use exact exp from signed URL
|
|
parts := strings.Split(u, "?")
|
|
if len(parts) != 2 {
|
|
t.Fatalf("url=%s", u)
|
|
}
|
|
q := map[string]string{}
|
|
for _, kv := range strings.Split(parts[1], "&") {
|
|
p := strings.SplitN(kv, "=", 2)
|
|
if len(p) == 2 {
|
|
q[p[0]] = p[1]
|
|
}
|
|
}
|
|
expVal := mustParseInt(t, q["exp"])
|
|
if err := VerifyPublicBrandLogoSig(secret, cid, name, expVal, q["sig"]); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if err := VerifyPublicBrandLogoSig(secret, cid, name, expVal, "deadbeef"); err != ErrLogoBadSig {
|
|
t.Fatalf("got %v", err)
|
|
}
|
|
_ = sig
|
|
}
|
|
|
|
func mustParseInt(t *testing.T, s string) int64 {
|
|
t.Helper()
|
|
var n int64
|
|
for _, c := range s {
|
|
if c < '0' || c > '9' {
|
|
t.Fatalf("bad int %q", s)
|
|
}
|
|
n = n*10 + int64(c-'0')
|
|
}
|
|
return n
|
|
}
|