Skip to content

Commit

Permalink
adding sanitizer for user-provided mime type in uploads
Browse files Browse the repository at this point in the history
  • Loading branch information
or-else committed Jan 22, 2024
1 parent 33d75b0 commit 474fe78
Showing 1 changed file with 22 additions and 3 deletions.
25 changes: 22 additions & 3 deletions server/hdl_files.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import (
"errors"
"io"
"math/rand"
"mime"
"net/http"
"strconv"
"strings"
Expand All @@ -24,6 +25,11 @@ import (
"github.com/tinode/chat/server/store/types"
)

// Allowed mime types for user-provided Content-type field. Must be alphabetically sorted.
// Types not in the list are converted to "application/octet-stream".
// See https://www.iana.org/assignments/media-types/media-types.xhtml
var allowedMimeTypes = []string{"application", "audio", "font", "image", "text", "video"}

func largeFileServe(wrt http.ResponseWriter, req *http.Request) {
now := types.TimeNow()
enc := json.NewEncoder(wrt)
Expand Down Expand Up @@ -140,6 +146,11 @@ func largeFileServe(wrt http.ResponseWriter, req *http.Request) {
strings.Contains(fd.MimeType, "html") ||
strings.Contains(fd.MimeType, "xml") ||
strings.HasPrefix(fd.MimeType, "application/") ||
// The 'message', 'model', and 'multipart' cannot currently appear, but checked anyway in case
// DetectContentType changes its logic.
strings.HasPrefix(fd.MimeType, "message/") ||
strings.HasPrefix(fd.MimeType, "model/") ||
strings.HasPrefix(fd.MimeType, "multipart/") ||
strings.HasPrefix(fd.MimeType, "text/")
if asAttachment {
wrt.Header().Set("Content-Disposition", "attachment")
Expand Down Expand Up @@ -275,10 +286,18 @@ func largeFileReceive(wrt http.ResponseWriter, req *http.Request) {
}

mimeType := http.DetectContentType(buff)
// If DetectContentType fails, use client-provided content type.
// If DetectContentType fails, see if client-provided content type can be used.
if mimeType == "application/octet-stream" {
if contentType := header.Header.Get("Content-Type"); contentType != "" {
mimeType = strings.ToLower(contentType)
if userContentType, params, err := mime.ParseMediaType(header.Header.Get("Content-Type")); err == nil {
// Make sure the content-type is legit.
for _, allowed := range allowedMimeTypes {
if strings.HasPrefix(userContentType, allowed) {
if userContentType = mime.FormatMediaType(userContentType, params); userContentType != "" {
mimeType = userContentType
}
break
}
}
}
}

Expand Down

0 comments on commit 474fe78

Please sign in to comment.