1
0
mirror of https://github.com/mattermost/focalboard.git synced 2024-12-21 13:38:56 +02:00

copy safe writeFileResponse into personal server/desktop (#4654)

* copy safe writeFileResponse into personal server/desktop

* lint fix

---------

Co-authored-by: Mattermost Build <build@mattermost.com>
This commit is contained in:
Scott Bishel 2023-03-22 13:28:23 -06:00 committed by GitHub
parent 3fa0e08219
commit d8e1fb4832
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -8,6 +8,8 @@ import (
"errors" "errors"
"io" "io"
"net/http" "net/http"
"net/url"
"strconv"
"strings" "strings"
"time" "time"
@ -20,9 +22,30 @@ import (
mmModel "github.com/mattermost/mattermost-server/v6/model" mmModel "github.com/mattermost/mattermost-server/v6/model"
"github.com/mattermost/mattermost-server/v6/shared/mlog" "github.com/mattermost/mattermost-server/v6/shared/mlog"
"github.com/mattermost/mattermost-server/v6/shared/web"
) )
var UnsafeContentTypes = [...]string{
"application/javascript",
"application/ecmascript",
"text/javascript",
"text/ecmascript",
"application/x-javascript",
"text/html",
}
var MediaContentTypes = [...]string{
"image/jpeg",
"image/png",
"image/bmp",
"image/gif",
"image/tiff",
"video/avi",
"video/mpeg",
"video/mp4",
"audio/mpeg",
"audio/wav",
}
// FileUploadResponse is the response to a file upload // FileUploadResponse is the response to a file upload
// swagger:model // swagger:model
type FileUploadResponse struct { type FileUploadResponse struct {
@ -145,10 +168,74 @@ func (a *API) handleServeFile(w http.ResponseWriter, r *http.Request) {
} }
defer fileReader.Close() defer fileReader.Close()
web.WriteFileResponse(filename, fileInfo.MimeType, fileInfo.Size, time.Now(), "", fileReader, false, w, r) mimeType := ""
var fileSize int64
if fileInfo != nil {
mimeType = fileInfo.MimeType
fileSize = fileInfo.Size
}
writeFileResponse(filename, mimeType, fileSize, time.Now(), "", fileReader, false, w, r)
auditRec.Success() auditRec.Success()
} }
func writeFileResponse(filename string, contentType string, contentSize int64,
lastModification time.Time, webserverMode string, fileReader io.ReadSeeker, forceDownload bool, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Cache-Control", "private, no-cache")
w.Header().Set("X-Content-Type-Options", "nosniff")
if contentSize > 0 {
contentSizeStr := strconv.Itoa(int(contentSize))
if webserverMode == "gzip" {
w.Header().Set("X-Uncompressed-Content-Length", contentSizeStr)
} else {
w.Header().Set("Content-Length", contentSizeStr)
}
}
if contentType == "" {
contentType = "application/octet-stream"
} else {
for _, unsafeContentType := range UnsafeContentTypes {
if strings.HasPrefix(contentType, unsafeContentType) {
contentType = "text/plain"
break
}
}
}
w.Header().Set("Content-Type", contentType)
var toDownload bool
if forceDownload {
toDownload = true
} else {
isMediaType := false
for _, mediaContentType := range MediaContentTypes {
if strings.HasPrefix(contentType, mediaContentType) {
isMediaType = true
break
}
}
toDownload = !isMediaType
}
filename = url.PathEscape(filename)
if toDownload {
w.Header().Set("Content-Disposition", "attachment;filename=\""+filename+"\"; filename*=UTF-8''"+filename)
} else {
w.Header().Set("Content-Disposition", "inline;filename=\""+filename+"\"; filename*=UTF-8''"+filename)
}
// prevent file links from being embedded in iframes
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Content-Security-Policy", "Frame-ancestors 'none'")
http.ServeContent(w, r, filename, lastModification, fileReader)
}
func (a *API) getFileInfo(w http.ResponseWriter, r *http.Request) { func (a *API) getFileInfo(w http.ResponseWriter, r *http.Request) {
// swagger:operation GET /files/teams/{teamID}/{boardID}/{filename}/info getFile // swagger:operation GET /files/teams/{teamID}/{boardID}/{filename}/info getFile
// //