From 2d0b90c967b24ba4558540d9db985b121b77f455 Mon Sep 17 00:00:00 2001
From: Lunny Xiao <xiaolunwen@gmail.com>
Date: Sat, 17 Aug 2019 18:10:17 +0800
Subject: [PATCH] Fix upload file type check (#7890)

* fix upload file type check

* make the function simple and added tests

* Update comment as per @silverwind
---
 modules/upload/filetype.go      | 17 +++++-------
 modules/upload/filetype_test.go | 47 +++++++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+), 10 deletions(-)
 create mode 100644 modules/upload/filetype_test.go

diff --git a/modules/upload/filetype.go b/modules/upload/filetype.go
index 1ec7324ed3..2ab326d116 100644
--- a/modules/upload/filetype.go
+++ b/modules/upload/filetype.go
@@ -31,19 +31,16 @@ func (err ErrFileTypeForbidden) Error() string {
 func VerifyAllowedContentType(buf []byte, allowedTypes []string) error {
 	fileType := http.DetectContentType(buf)
 
-	allowed := false
 	for _, t := range allowedTypes {
 		t := strings.Trim(t, " ")
-		if t == "*/*" || t == fileType {
-			allowed = true
-			break
+
+		if t == "*/*" || t == fileType ||
+			// Allow directives after type, like 'text/plain; charset=utf-8'
+			strings.HasPrefix(fileType, t+";") {
+			return nil
 		}
 	}
 
-	if !allowed {
-		log.Info("Attachment with type %s blocked from upload", fileType)
-		return ErrFileTypeForbidden{Type: fileType}
-	}
-
-	return nil
+	log.Info("Attachment with type %s blocked from upload", fileType)
+	return ErrFileTypeForbidden{Type: fileType}
 }
diff --git a/modules/upload/filetype_test.go b/modules/upload/filetype_test.go
new file mode 100644
index 0000000000..f93a1c5cc3
--- /dev/null
+++ b/modules/upload/filetype_test.go
@@ -0,0 +1,47 @@
+// Copyright 2019 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package upload
+
+import (
+	"bytes"
+	"compress/gzip"
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestUpload(t *testing.T) {
+	testContent := []byte(`This is a plain text file.`)
+	var b bytes.Buffer
+	w := gzip.NewWriter(&b)
+	w.Write(testContent)
+	w.Close()
+
+	kases := []struct {
+		data         []byte
+		allowedTypes []string
+		err          error
+	}{
+		{
+			data:         testContent,
+			allowedTypes: []string{"text/plain"},
+			err:          nil,
+		},
+		{
+			data:         testContent,
+			allowedTypes: []string{"application/x-gzip"},
+			err:          ErrFileTypeForbidden{"text/plain; charset=utf-8"},
+		},
+		{
+			data:         b.Bytes(),
+			allowedTypes: []string{"application/x-gzip"},
+			err:          nil,
+		},
+	}
+
+	for _, kase := range kases {
+		assert.Equal(t, kase.err, VerifyAllowedContentType(kase.data, kase.allowedTypes))
+	}
+}