diff --git a/internal/file/handlers.go b/internal/file/handlers.go index 3bba5b9..e0c17d7 100644 --- a/internal/file/handlers.go +++ b/internal/file/handlers.go @@ -1,6 +1,7 @@ package file import ( + "ResendIt/internal/util" "fmt" "net/http" "path/filepath" @@ -77,27 +78,12 @@ func (h *Handler) View(c *gin.Context) { c.HTML(http.StatusOK, "fileNotFound.html", nil) return } - - c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, record.Filename)) + name := util.SafeFilename(record.Filename) + c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) c.Header("X-Content-Type-Options", "nosniff") c.File(record.Path) } -func safeFilename(name string) string { - // keep it simple: drop control chars and quotes - out := make([]rune, 0, len(name)) - for _, r := range name { - if r < 32 || r == 127 || r == '"' || r == '\\' { - continue - } - out = append(out, r) - } - if len(out) == 0 { - return "file" - } - return string(out) -} - func isXSSRisk(filename string) bool { ext := filepath.Ext(filename) switch ext { @@ -116,8 +102,8 @@ func (h *Handler) Download(c *gin.Context) { c.HTML(http.StatusOK, "fileNotFound.html", nil) return } - - c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, record.Filename)) + name := util.SafeFilename(record.Filename) + c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name)) c.Header("X-Content-Type-Options", "nosniff") //c.Header("Content-Security-Policy", "default-src 'none'; img-src 'self'; media-src 'self'; script-src 'none'; style-src 'none';") //c.Header("Content-Type", "application/octet-stream") diff --git a/internal/file/upload_multi.go b/internal/file/upload_multi.go index a240d0b..4729705 100644 --- a/internal/file/upload_multi.go +++ b/internal/file/upload_multi.go @@ -26,8 +26,8 @@ func (h *Handler) UploadMulti(c *gin.Context) { c.JSON(http.StatusBadRequest, gin.H{"error": "missing files"}) return } - if len(files) > 10 { - c.JSON(http.StatusBadRequest, gin.H{"error": "too many files (max 10)"}) + if len(files) > 50 { + c.JSON(http.StatusBadRequest, gin.H{"error": "too many files (max 50)"}) return } diff --git a/internal/file/zip.go b/internal/file/zip.go index 51b6e80..5a9bcb2 100644 --- a/internal/file/zip.go +++ b/internal/file/zip.go @@ -3,11 +3,9 @@ package file import ( "ResendIt/internal/util" "archive/zip" - "crypto/rand" "errors" "fmt" "io" - "math/big" "mime/multipart" "os" "path/filepath" @@ -39,17 +37,6 @@ func dedupeName(name string, seen map[string]int) string { return fmt.Sprintf("%s (%d)%s", base, seen[name], ext) } -func randIndex(n int) int { - if n <= 0 { - return 0 - } - x, err := rand.Int(rand.Reader, big.NewInt(int64(n))) - if err != nil { - return 0 - } - return int(x.Int64()) -} - func cuteZipName(fileCount int) string { adjective := util.RandomAdjective() verb := util.RandomVerb() diff --git a/internal/util/util.go b/internal/util/util.go index 8acfc8d..d545b0d 100644 --- a/internal/util/util.go +++ b/internal/util/util.go @@ -1,6 +1,9 @@ package util -import "fmt" +import ( + "fmt" + "strings" +) func HumanSize(size int64) string { const unit = 1024 @@ -17,3 +20,24 @@ func HumanSize(size int64) string { "KMGTPE"[exp], ) } + +func SafeFilename(name string) string { + name = strings.TrimSpace(name) + + out := make([]rune, 0, len(name)) + for _, r := range name { + // block control chars (incl CR/LF/TAB), DEL, quotes, backslash + if r < 32 || r == 127 || r == '"' || r == '\\' { + continue + } + out = append(out, r) + } + if len(out) == 0 { + return "file" + } + // optional: cap length + if len(out) > 200 { + out = out[:200] + } + return string(out) +}