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  }