diff options
Diffstat (limited to 'api/file.go')
-rw-r--r-- | api/file.go | 333 |
1 files changed, 0 insertions, 333 deletions
diff --git a/api/file.go b/api/file.go deleted file mode 100644 index 63432eda5..000000000 --- a/api/file.go +++ /dev/null @@ -1,333 +0,0 @@ -// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. -// See License.txt for license information. - -package api - -import ( - "net/http" - "net/url" - "strconv" - "strings" - - "github.com/gorilla/mux" - "github.com/mattermost/mattermost-server/app" - "github.com/mattermost/mattermost-server/model" - "github.com/mattermost/mattermost-server/utils" -) - -const ( - PREVIEW_IMAGE_TYPE = "image/jpeg" - THUMBNAIL_IMAGE_TYPE = "image/jpeg" -) - -var UNSAFE_CONTENT_TYPES = [...]string{ - "application/javascript", - "application/ecmascript", - "text/javascript", - "text/ecmascript", - "application/x-javascript", - "text/html", -} - -func (api *API) InitFile() { - api.BaseRoutes.TeamFiles.Handle("/upload", api.ApiUserRequired(uploadFile)).Methods("POST") - - api.BaseRoutes.NeedFile.Handle("/get", api.ApiUserRequiredTrustRequester(getFile)).Methods("GET") - api.BaseRoutes.NeedFile.Handle("/get_thumbnail", api.ApiUserRequiredTrustRequester(getFileThumbnail)).Methods("GET") - api.BaseRoutes.NeedFile.Handle("/get_preview", api.ApiUserRequiredTrustRequester(getFilePreview)).Methods("GET") - api.BaseRoutes.NeedFile.Handle("/get_info", api.ApiUserRequired(getFileInfo)).Methods("GET") - api.BaseRoutes.NeedFile.Handle("/get_public_link", api.ApiUserRequired(getPublicLink)).Methods("GET") - - api.BaseRoutes.Public.Handle("/files/{file_id:[A-Za-z0-9]+}/get", api.ApiAppHandlerTrustRequesterIndependent(getPublicFile)).Methods("GET") - api.BaseRoutes.Public.Handle("/files/get/{team_id:[A-Za-z0-9]+}/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:(?:[A-Za-z0-9]+/)?.+(?:\\.[A-Za-z0-9]{3,})?}", api.ApiAppHandlerTrustRequesterIndependent(getPublicFileOld)).Methods("GET") -} - -func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) { - if !*c.App.Config().FileSettings.EnableFileAttachments { - c.Err = model.NewAppError("uploadFile", "api.file.attachments.disabled.app_error", nil, "", http.StatusNotImplemented) - return - } - - if r.ContentLength > *c.App.Config().FileSettings.MaxFileSize { - c.Err = model.NewAppError("uploadFile", "api.file.upload_file.too_large.app_error", nil, "", http.StatusRequestEntityTooLarge) - return - } - - if err := r.ParseMultipartForm(*c.App.Config().FileSettings.MaxFileSize); err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - return - } - - m := r.MultipartForm - - props := m.Value - if len(props["channel_id"]) == 0 { - c.SetInvalidParam("uploadFile", "channel_id") - return - } - channelId := props["channel_id"][0] - if len(channelId) == 0 { - c.SetInvalidParam("uploadFile", "channel_id") - return - } - - if !c.App.SessionHasPermissionToChannel(c.Session, channelId, model.PERMISSION_UPLOAD_FILE) { - c.SetPermissionError(model.PERMISSION_UPLOAD_FILE) - return - } - - resStruct, err := c.App.UploadMultipartFiles(c.TeamId, channelId, c.Session.UserId, m.File["files"], m.Value["client_ids"]) - if err != nil { - c.Err = err - return - } - - w.Write([]byte(resStruct.ToJson())) -} - -func getFile(c *Context, w http.ResponseWriter, r *http.Request) { - info, err := getFileInfoForRequest(c, r, true) - if err != nil { - c.Err = err - return - } - - if data, err := c.App.ReadFile(info.Path); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusNotFound - } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil { - c.Err = err - return - } -} - -func getFileThumbnail(c *Context, w http.ResponseWriter, r *http.Request) { - info, err := getFileInfoForRequest(c, r, true) - if err != nil { - c.Err = err - return - } - - if info.ThumbnailPath == "" { - c.Err = model.NewAppError("getFileThumbnail", "api.file.get_file_thumbnail.no_thumbnail.app_error", nil, "file_id="+info.Id, http.StatusBadRequest) - return - } - - if data, err := c.App.ReadFile(info.ThumbnailPath); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusNotFound - } else if err := writeFileResponse(info.Name, THUMBNAIL_IMAGE_TYPE, data, w, r); err != nil { - c.Err = err - return - } -} - -func getFilePreview(c *Context, w http.ResponseWriter, r *http.Request) { - info, err := getFileInfoForRequest(c, r, true) - if err != nil { - c.Err = err - return - } - - if info.PreviewPath == "" { - c.Err = model.NewAppError("getFilePreview", "api.file.get_file_preview.no_preview.app_error", nil, "file_id="+info.Id, http.StatusBadRequest) - return - } - - if data, err := c.App.ReadFile(info.PreviewPath); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusNotFound - } else if err := writeFileResponse(info.Name, PREVIEW_IMAGE_TYPE, data, w, r); err != nil { - c.Err = err - return - } -} - -func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) { - info, err := getFileInfoForRequest(c, r, true) - if err != nil { - c.Err = err - return - } - - w.Header().Set("Cache-Control", "max-age=2592000, public") - - w.Write([]byte(info.ToJson())) -} - -func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.Config().FileSettings.EnablePublicLink { - c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_disabled.app_error", nil, "", http.StatusNotImplemented) - return - } - - info, err := getFileInfoForRequest(c, r, false) - if err != nil { - c.Err = err - return - } - - hash := r.URL.Query().Get("h") - - if len(hash) > 0 { - correctHash := app.GeneratePublicLinkHash(info.Id, *c.App.Config().FileSettings.PublicLinkSalt) - - if hash != correctHash { - c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest) - utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey()) - return - } - } else { - c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest) - utils.RenderWebAppError(w, r, c.Err, c.App.AsymmetricSigningKey()) - return - } - - if data, err := c.App.ReadFile(info.Path); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusNotFound - } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil { - c.Err = err - return - } -} - -func getFileInfoForRequest(c *Context, r *http.Request, requireFileVisible bool) (*model.FileInfo, *model.AppError) { - if len(*c.App.Config().FileSettings.DriverName) == 0 { - return nil, model.NewAppError("getFileInfoForRequest", "api.file.get_info_for_request.storage.app_error", nil, "", http.StatusNotImplemented) - } - - params := mux.Vars(r) - - fileId := params["file_id"] - if len(fileId) != 26 { - return nil, NewInvalidParamError("getFileInfoForRequest", "file_id") - } - - info, err := c.App.GetFileInfo(fileId) - if err != nil { - return nil, err - } - - // only let users access files visible in a channel, unless they're the one who uploaded the file - if info.CreatorId != c.Session.UserId { - if len(info.PostId) == 0 { - err := model.NewAppError("getFileInfoForRequest", "api.file.get_file_info_for_request.no_post.app_error", nil, "file_id="+fileId, http.StatusBadRequest) - return nil, err - } - - if requireFileVisible { - if !c.App.SessionHasPermissionToChannelByPost(c.Session, info.PostId, model.PERMISSION_READ_CHANNEL) { - c.SetPermissionError(model.PERMISSION_READ_CHANNEL) - return nil, c.Err - } - } - } - - return info, nil -} - -func getPublicFileOld(c *Context, w http.ResponseWriter, r *http.Request) { - if len(*c.App.Config().FileSettings.DriverName) == 0 { - c.Err = model.NewAppError("getPublicFile", "api.file.get_public_file_old.storage.app_error", nil, "", http.StatusNotImplemented) - return - } else if !c.App.Config().FileSettings.EnablePublicLink { - c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_disabled.app_error", nil, "", http.StatusNotImplemented) - return - } - - params := mux.Vars(r) - - teamId := params["team_id"] - channelId := params["channel_id"] - userId := params["user_id"] - filename := params["filename"] - - hash := r.URL.Query().Get("h") - - if len(hash) > 0 { - correctHash := app.GeneratePublicLinkHash(filename, *c.App.Config().FileSettings.PublicLinkSalt) - - if hash != correctHash { - c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest) - http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect) - return - } - } else { - c.Err = model.NewAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "", http.StatusBadRequest) - http.Redirect(w, r, c.GetSiteURLHeader()+"/error?message="+utils.T(c.Err.Message), http.StatusTemporaryRedirect) - return - } - - path := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename - - var info *model.FileInfo - if result := <-c.App.Srv.Store.FileInfo().GetByPath(path); result.Err != nil { - c.Err = result.Err - return - } else { - info = result.Data.(*model.FileInfo) - } - - if len(info.PostId) == 0 { - c.Err = model.NewAppError("getPublicFileOld", "api.file.get_public_file_old.no_post.app_error", nil, "file_id="+info.Id, http.StatusBadRequest) - return - } - - if data, err := c.App.ReadFile(info.Path); err != nil { - c.Err = err - c.Err.StatusCode = http.StatusNotFound - } else if err := writeFileResponse(info.Name, info.MimeType, data, w, r); err != nil { - c.Err = err - return - } -} - -func writeFileResponse(filename string, contentType string, bytes []byte, w http.ResponseWriter, r *http.Request) *model.AppError { - w.Header().Set("Cache-Control", "max-age=2592000, private") - w.Header().Set("Content-Length", strconv.Itoa(len(bytes))) - w.Header().Set("X-Content-Type-Options", "nosniff") - - if contentType == "" { - contentType = "application/octet-stream" - } else { - for _, unsafeContentType := range UNSAFE_CONTENT_TYPES { - if strings.HasPrefix(contentType, unsafeContentType) { - contentType = "text/plain" - break - } - } - } - - w.Header().Set("Content-Type", contentType) - - w.Header().Set("Content-Disposition", "attachment;filename=\""+filename+"\"; filename*=UTF-8''"+url.QueryEscape(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'") - - w.Write(bytes) - - return nil -} - -func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) { - if !c.App.Config().FileSettings.EnablePublicLink { - c.Err = model.NewAppError("getPublicLink", "api.file.get_public_link.disabled.app_error", nil, "", http.StatusNotImplemented) - return - } - - info, err := getFileInfoForRequest(c, r, true) - if err != nil { - c.Err = err - return - } - - if len(info.PostId) == 0 { - c.Err = model.NewAppError("getPublicLink", "api.file.get_public_link.no_post.app_error", nil, "file_id="+info.Id, http.StatusBadRequest) - return - } - - w.Write([]byte(model.StringToJson(c.App.GeneratePublicLinkV3(c.GetSiteURLHeader(), info)))) -} |