fix file naming sanitisation
This commit is contained in:
@@ -1,6 +1,7 @@
|
|||||||
package file
|
package file
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"ResendIt/internal/util"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -77,27 +78,12 @@ func (h *Handler) View(c *gin.Context) {
|
|||||||
c.HTML(http.StatusOK, "fileNotFound.html", nil)
|
c.HTML(http.StatusOK, "fileNotFound.html", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
name := util.SafeFilename(record.Filename)
|
||||||
c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, record.Filename))
|
c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
|
||||||
c.Header("X-Content-Type-Options", "nosniff")
|
c.Header("X-Content-Type-Options", "nosniff")
|
||||||
c.File(record.Path)
|
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 {
|
func isXSSRisk(filename string) bool {
|
||||||
ext := filepath.Ext(filename)
|
ext := filepath.Ext(filename)
|
||||||
switch ext {
|
switch ext {
|
||||||
@@ -116,8 +102,8 @@ func (h *Handler) Download(c *gin.Context) {
|
|||||||
c.HTML(http.StatusOK, "fileNotFound.html", nil)
|
c.HTML(http.StatusOK, "fileNotFound.html", nil)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
name := util.SafeFilename(record.Filename)
|
||||||
c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, record.Filename))
|
c.Header("Content-Disposition", fmt.Sprintf(`inline; filename="%s"`, name))
|
||||||
c.Header("X-Content-Type-Options", "nosniff")
|
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-Security-Policy", "default-src 'none'; img-src 'self'; media-src 'self'; script-src 'none'; style-src 'none';")
|
||||||
//c.Header("Content-Type", "application/octet-stream")
|
//c.Header("Content-Type", "application/octet-stream")
|
||||||
|
|||||||
@@ -26,8 +26,8 @@ func (h *Handler) UploadMulti(c *gin.Context) {
|
|||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "missing files"})
|
c.JSON(http.StatusBadRequest, gin.H{"error": "missing files"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(files) > 10 {
|
if len(files) > 50 {
|
||||||
c.JSON(http.StatusBadRequest, gin.H{"error": "too many files (max 10)"})
|
c.JSON(http.StatusBadRequest, gin.H{"error": "too many files (max 50)"})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,11 +3,9 @@ package file
|
|||||||
import (
|
import (
|
||||||
"ResendIt/internal/util"
|
"ResendIt/internal/util"
|
||||||
"archive/zip"
|
"archive/zip"
|
||||||
"crypto/rand"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/big"
|
|
||||||
"mime/multipart"
|
"mime/multipart"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"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)
|
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 {
|
func cuteZipName(fileCount int) string {
|
||||||
adjective := util.RandomAdjective()
|
adjective := util.RandomAdjective()
|
||||||
verb := util.RandomVerb()
|
verb := util.RandomVerb()
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package util
|
package util
|
||||||
|
|
||||||
import "fmt"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
func HumanSize(size int64) string {
|
func HumanSize(size int64) string {
|
||||||
const unit = 1024
|
const unit = 1024
|
||||||
@@ -17,3 +20,24 @@ func HumanSize(size int64) string {
|
|||||||
"KMGTPE"[exp],
|
"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)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user