github.com/mattermost/mattermost-server/v5@v5.39.3/api4/upload.go (about) 1 // Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. 2 // See LICENSE.txt for license information. 3 4 package api4 5 6 import ( 7 "errors" 8 "io" 9 "mime/multipart" 10 "net/http" 11 12 "github.com/mattermost/mattermost-server/v5/audit" 13 "github.com/mattermost/mattermost-server/v5/model" 14 ) 15 16 func (api *API) InitUpload() { 17 api.BaseRoutes.Uploads.Handle("", api.ApiSessionRequired(createUpload)).Methods("POST") 18 api.BaseRoutes.Upload.Handle("", api.ApiSessionRequired(getUpload)).Methods("GET") 19 api.BaseRoutes.Upload.Handle("", api.ApiSessionRequired(uploadData)).Methods("POST") 20 } 21 22 func createUpload(c *Context, w http.ResponseWriter, r *http.Request) { 23 if !*c.App.Config().FileSettings.EnableFileAttachments { 24 c.Err = model.NewAppError("createUpload", 25 "api.file.attachments.disabled.app_error", 26 nil, "", http.StatusNotImplemented) 27 return 28 } 29 30 us := model.UploadSessionFromJson(r.Body) 31 if us == nil { 32 c.SetInvalidParam("upload") 33 return 34 } 35 36 // these are not supported for client uploads; shared channels only. 37 us.RemoteId = "" 38 us.ReqFileId = "" 39 40 auditRec := c.MakeAuditRecord("createUpload", audit.Fail) 41 defer c.LogAuditRec(auditRec) 42 auditRec.AddMeta("upload", us) 43 44 if us.Type == model.UploadTypeImport { 45 if !c.IsSystemAdmin() { 46 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 47 return 48 } 49 } else { 50 if !c.App.SessionHasPermissionToChannel(*c.AppContext.Session(), us.ChannelId, model.PERMISSION_UPLOAD_FILE) { 51 c.SetPermissionError(model.PERMISSION_UPLOAD_FILE) 52 return 53 } 54 us.Type = model.UploadTypeAttachment 55 } 56 57 us.Id = model.NewId() 58 if c.AppContext.Session().UserId != "" { 59 us.UserId = c.AppContext.Session().UserId 60 } 61 us, err := c.App.CreateUploadSession(us) 62 if err != nil { 63 c.Err = err 64 return 65 } 66 67 auditRec.Success() 68 w.WriteHeader(http.StatusCreated) 69 w.Write([]byte(us.ToJson())) 70 } 71 72 func getUpload(c *Context, w http.ResponseWriter, r *http.Request) { 73 c.RequireUploadId() 74 if c.Err != nil { 75 return 76 } 77 78 us, err := c.App.GetUploadSession(c.Params.UploadId) 79 if err != nil { 80 c.Err = err 81 return 82 } 83 84 if us.UserId != c.AppContext.Session().UserId && !c.IsSystemAdmin() { 85 c.Err = model.NewAppError("getUpload", "api.upload.get_upload.forbidden.app_error", nil, "", http.StatusForbidden) 86 return 87 } 88 89 w.Write([]byte(us.ToJson())) 90 } 91 92 func uploadData(c *Context, w http.ResponseWriter, r *http.Request) { 93 if !*c.App.Config().FileSettings.EnableFileAttachments { 94 c.Err = model.NewAppError("uploadData", "api.file.attachments.disabled.app_error", 95 nil, "", http.StatusNotImplemented) 96 return 97 } 98 99 c.RequireUploadId() 100 if c.Err != nil { 101 return 102 } 103 104 auditRec := c.MakeAuditRecord("uploadData", audit.Fail) 105 defer c.LogAuditRec(auditRec) 106 auditRec.AddMeta("upload_id", c.Params.UploadId) 107 108 us, err := c.App.GetUploadSession(c.Params.UploadId) 109 if err != nil { 110 c.Err = err 111 return 112 } 113 114 if us.Type == model.UploadTypeImport { 115 if !c.IsSystemAdmin() { 116 c.SetPermissionError(model.PERMISSION_MANAGE_SYSTEM) 117 return 118 } 119 } else { 120 if us.UserId != c.AppContext.Session().UserId || !c.App.SessionHasPermissionToChannel(*c.AppContext.Session(), us.ChannelId, model.PERMISSION_UPLOAD_FILE) { 121 c.SetPermissionError(model.PERMISSION_UPLOAD_FILE) 122 return 123 } 124 } 125 126 info, err := doUploadData(c, us, r) 127 if err != nil { 128 c.Err = err 129 return 130 } 131 132 auditRec.Success() 133 134 if info == nil { 135 w.WriteHeader(http.StatusNoContent) 136 return 137 } 138 139 w.Write([]byte(info.ToJson())) 140 } 141 142 func doUploadData(c *Context, us *model.UploadSession, r *http.Request) (*model.FileInfo, *model.AppError) { 143 boundary, parseErr := parseMultipartRequestHeader(r) 144 if parseErr != nil && !errors.Is(parseErr, http.ErrNotMultipart) { 145 return nil, model.NewAppError("uploadData", "api.upload.upload_data.invalid_content_type", 146 nil, parseErr.Error(), http.StatusBadRequest) 147 } 148 149 var rd io.Reader 150 if boundary != "" { 151 mr := multipart.NewReader(r.Body, boundary) 152 p, partErr := mr.NextPart() 153 if partErr != nil { 154 return nil, model.NewAppError("uploadData", "api.upload.upload_data.multipart_error", 155 nil, partErr.Error(), http.StatusBadRequest) 156 } 157 rd = p 158 } else { 159 if r.ContentLength > (us.FileSize - us.FileOffset) { 160 return nil, model.NewAppError("uploadData", "api.upload.upload_data.invalid_content_length", 161 nil, "", http.StatusBadRequest) 162 } 163 rd = r.Body 164 } 165 166 return c.App.UploadData(c.AppContext, us, rd) 167 }