Initial commit of Descrybe v2 without local scratch artifacts.
Drop one-shot tmp/axe scripts and agent i18n scratch so the Gitea tree is deployable.
This commit is contained in:
@@ -0,0 +1,152 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user