- Restructure handlers into file_commands/file_queries/file_handlers - Add gRPC auth client, JWT middleware, rate limiting, request ID - Add common utilities: logger, sanitizer, s3_errors - Add unit tests for config, mediator, auth, request_id, sanitize - Add proto definitions and generated code - Remove old web UI pages - Add .dockerignore and .env.example
109 lines
2.9 KiB
Go
109 lines
2.9 KiB
Go
package common
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SanitizeObjectKey
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestSanitizeObjectKey_ValidInput(t *testing.T) {
|
|
keys := []string{"folder/file.txt", "file.csv", "a/b/c/d.json"}
|
|
for _, key := range keys {
|
|
if err := SanitizeObjectKey(key); err != nil {
|
|
t.Errorf("expected nil for key %q, got error: %v", key, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSanitizeObjectKey_PathTraversal(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
key string
|
|
}{
|
|
{"double dot", "../etc/passwd"},
|
|
{"double dot middle", "a/../b"},
|
|
{"double slash", "folder//file.txt"},
|
|
{"leading slash", "/absolute/path"},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err := SanitizeObjectKey(tc.key)
|
|
if err == nil {
|
|
t.Errorf("expected error for key %q, got nil", tc.key)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SanitizeBucketName
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestSanitizeBucketName_Valid(t *testing.T) {
|
|
names := []string{"my-bucket", "bucket123", "a1b", "my.bucket.name"}
|
|
for _, name := range names {
|
|
if err := SanitizeBucketName(name); err != nil {
|
|
t.Errorf("expected nil for bucket %q, got error: %v", name, err)
|
|
}
|
|
}
|
|
}
|
|
|
|
func TestSanitizeBucketName_Invalid(t *testing.T) {
|
|
cases := []struct {
|
|
name string
|
|
input string
|
|
}{
|
|
{"uppercase", "MyBucket"},
|
|
{"too short", "ab"},
|
|
{"starts with hyphen", "-bucket"},
|
|
{"starts with dot", ".bucket"},
|
|
{"contains underscore", "my_bucket"},
|
|
{"empty", ""},
|
|
}
|
|
for _, tc := range cases {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
err := SanitizeBucketName(tc.input)
|
|
if err == nil {
|
|
t.Errorf("expected error for bucket %q, got nil", tc.input)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestSanitizeBucketName_TooLong(t *testing.T) {
|
|
longName := strings.Repeat("a", 64)
|
|
if err := SanitizeBucketName(longName); err == nil {
|
|
t.Error("expected error for bucket name > 63 chars, got nil")
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SanitizeFilename
|
|
// ---------------------------------------------------------------------------
|
|
|
|
func TestSanitizeFilename_RemovesCRLF(t *testing.T) {
|
|
input := "file\r\nname.txt"
|
|
got := SanitizeFilename(input)
|
|
if strings.Contains(got, "\r") || strings.Contains(got, "\n") {
|
|
t.Errorf("expected \\r and \\n removed, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeFilename_EscapesQuotes(t *testing.T) {
|
|
input := `some"file.txt`
|
|
got := SanitizeFilename(input)
|
|
if strings.Contains(got, `"`) && !strings.Contains(got, `\"`) {
|
|
t.Errorf("expected quotes escaped, got %q", got)
|
|
}
|
|
}
|
|
|
|
func TestSanitizeFilename_CleanInput(t *testing.T) {
|
|
input := "clean-file.txt"
|
|
if got := SanitizeFilename(input); got != input {
|
|
t.Errorf("expected %q, got %q", input, got)
|
|
}
|
|
}
|