summaryrefslogtreecommitdiffstats
path: root/api/file.go
diff options
context:
space:
mode:
authorHarrison Healey <harrisonmhealey@gmail.com>2016-05-05 16:35:03 -0400
committerChristopher Speller <crspeller@gmail.com>2016-05-05 16:35:03 -0400
commitd2ddf40f56191c1770c3ca93d747a7f1b749f26c (patch)
tree9cd5d9ac9fc5b9da21fba8df9990c5f927801272 /api/file.go
parent696ffb4745bec6306f88c5693b8ded89a47f5de7 (diff)
downloadchat-d2ddf40f56191c1770c3ca93d747a7f1b749f26c.tar.gz
chat-d2ddf40f56191c1770c3ca93d747a7f1b749f26c.tar.bz2
chat-d2ddf40f56191c1770c3ca93d747a7f1b749f26c.zip
PLT-2600/PLT-2770 Added Get Public Link modal and added new API for public file links (#2892)
* Switched public file links to use a GetLinkModal * Separated getFile and the new getPublicFile api calls
Diffstat (limited to 'api/file.go')
-rw-r--r--api/file.go132
1 files changed, 82 insertions, 50 deletions
diff --git a/api/file.go b/api/file.go
index 82fcefc7b..ca2aeee20 100644
--- a/api/file.go
+++ b/api/file.go
@@ -61,10 +61,12 @@ func InitFile() {
l4g.Debug(utils.T("api.file.init.debug"))
BaseRoutes.Files.Handle("/upload", ApiUserRequired(uploadFile)).Methods("POST")
- BaseRoutes.Files.Handle("/get/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiAppHandlerTrustRequester(getFile)).Methods("GET")
- BaseRoutes.Files.Handle("/get_info/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiAppHandler(getFileInfo)).Methods("GET")
+ BaseRoutes.Files.Handle("/get/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiUserRequiredTrustRequester(getFile)).Methods("GET")
+ BaseRoutes.Files.Handle("/get_info/{channel_id:[A-Za-z0-9]+}/{user_id:[A-Za-z0-9]+}/{filename:([A-Za-z0-9]+/)?.+(\\.[A-Za-z0-9]{3,})?}", ApiUserRequired(getFileInfo)).Methods("GET")
BaseRoutes.Files.Handle("/get_public_link", ApiUserRequired(getPublicLink)).Methods("POST")
BaseRoutes.Files.Handle("/get_export", ApiUserRequired(getExport)).Methods("GET")
+
+ 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,})?}", ApiAppHandlerTrustRequesterIndependent(getPublicFile)).Methods("GET")
}
func uploadFile(c *Context, w http.ResponseWriter, r *http.Request) {
@@ -349,72 +351,104 @@ func getFileInfo(c *Context, w http.ResponseWriter, r *http.Request) {
}
func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
- if len(utils.Cfg.FileSettings.DriverName) == 0 {
- c.Err = model.NewLocAppError("uploadFile", "api.file.upload_file.storage.app_error", nil, "")
- c.Err.StatusCode = http.StatusNotImplemented
- return
- }
-
params := mux.Vars(r)
+ teamId := c.TeamId
channelId := params["channel_id"]
- if len(channelId) != 26 {
- c.SetInvalidParam("getFile", "channel_id")
+ userId := params["user_id"]
+ filename := params["filename"]
+
+ if !c.HasPermissionsToChannel(Srv.Store.Channel().CheckPermissionsTo(teamId, channelId, userId), "getFile") {
return
}
- userId := params["user_id"]
- if len(userId) != 26 {
- c.SetInvalidParam("getFile", "user_id")
+ if err, bytes := getFileData(teamId, channelId, userId, filename); err != nil {
+ c.Err = err
+ return
+ } else if err := writeFileResponse(filename, bytes, w, r); err != nil {
+ c.Err = err
return
}
+}
+func getPublicFile(c *Context, w http.ResponseWriter, r *http.Request) {
+ params := mux.Vars(r)
+
+ teamId := params["team_id"]
+ channelId := params["channel_id"]
+ userId := params["user_id"]
filename := params["filename"]
- if len(filename) == 0 {
- c.SetInvalidParam("getFile", "filename")
- return
- }
hash := r.URL.Query().Get("h")
data := r.URL.Query().Get("d")
- teamId := r.URL.Query().Get("t")
-
- cchan := Srv.Store.Channel().CheckPermissionsTo(c.TeamId, channelId, c.Session.UserId)
- path := ""
- if len(teamId) == 26 {
- path = "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
- } else {
- path = "teams/" + c.TeamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
+ if !utils.Cfg.FileSettings.EnablePublicLink {
+ c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_disabled.app_error", nil, "")
+ c.Err.StatusCode = http.StatusNotImplemented
+ return
}
- fileData := make(chan []byte)
- getFileAndForget(path, fileData)
-
- if len(hash) > 0 && len(data) > 0 && len(teamId) == 26 {
- if !utils.Cfg.FileSettings.EnablePublicLink {
- c.Err = model.NewLocAppError("getFile", "api.file.get_file.public_disabled.app_error", nil, "")
- return
- }
-
+ if len(hash) > 0 && len(data) > 0 {
if !model.ComparePassword(hash, fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt)) {
- c.Err = model.NewLocAppError("getFile", "api.file.get_file.public_invalid.app_error", nil, "")
+ c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "")
+ c.Err.StatusCode = http.StatusBadRequest
return
}
- } else if !c.HasPermissionsToChannel(cchan, "getFile") {
+ } else {
+ c.Err = model.NewLocAppError("getPublicFile", "api.file.get_file.public_invalid.app_error", nil, "")
+ c.Err.StatusCode = http.StatusBadRequest
return
}
- f := <-fileData
-
- if f == nil {
- c.Err = model.NewLocAppError("getFile", "api.file.get_file.not_found.app_error", nil, "path="+path)
- c.Err.StatusCode = http.StatusNotFound
+ if err, bytes := getFileData(teamId, channelId, userId, filename); err != nil {
+ c.Err = err
+ return
+ } else if err := writeFileResponse(filename, bytes, w, r); err != nil {
+ c.Err = err
return
}
+}
+
+func getFileData(teamId string, channelId string, userId string, filename string) (*model.AppError, []byte) {
+ if len(utils.Cfg.FileSettings.DriverName) == 0 {
+ err := model.NewLocAppError("getFileData", "api.file.upload_file.storage.app_error", nil, "")
+ err.StatusCode = http.StatusNotImplemented
+ return err, nil
+ }
+
+ if len(teamId) != 26 {
+ return NewInvalidParamError("getFileData", "team_id"), nil
+ }
+
+ if len(channelId) != 26 {
+ return NewInvalidParamError("getFileData", "channel_id"), nil
+ }
+
+ if len(userId) != 26 {
+ return NewInvalidParamError("getFileData", "user_id"), nil
+ }
+
+ if len(filename) == 0 {
+ return NewInvalidParamError("getFileData", "filename"), nil
+ }
+ path := "teams/" + teamId + "/channels/" + channelId + "/users/" + userId + "/" + filename
+
+ fileChan := make(chan []byte)
+ getFileAndForget(path, fileChan)
+
+ if bytes := <-fileChan; bytes == nil {
+ err := model.NewLocAppError("writeFileResponse", "api.file.get_file.not_found.app_error", nil, "path="+path)
+ err.StatusCode = http.StatusNotFound
+ return err, nil
+ } else {
+ return nil, bytes
+ }
+}
+
+func writeFileResponse(filename string, bytes []byte, w http.ResponseWriter, r *http.Request) *model.AppError {
w.Header().Set("Cache-Control", "max-age=2592000, public")
- w.Header().Set("Content-Length", strconv.Itoa(len(f)))
+ w.Header().Set("Content-Length", strconv.Itoa(len(bytes)))
w.Header().Del("Content-Type") // Content-Type will be set automatically by the http writer
// attach extra headers to trigger a download on IE, Edge, and Safari
@@ -426,7 +460,6 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Disposition", "attachment;filename=\""+filePart+"\"")
if bname == "Edge" || bname == "Internet Explorer" || bname == "Safari" {
- // trim off anything before the final / so we just get the file's name
w.Header().Set("Content-Type", "application/octet-stream")
}
@@ -434,7 +467,9 @@ func getFile(c *Context, w http.ResponseWriter, r *http.Request) {
w.Header().Set("X-Frame-Options", "DENY")
w.Header().Set("Content-Security-Policy", "Frame-ancestors 'none'")
- w.Write(f)
+ w.Write(bytes)
+
+ return nil
}
func getFileAndForget(path string, fileData chan []byte) {
@@ -458,7 +493,7 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
if !utils.Cfg.FileSettings.EnablePublicLink {
c.Err = model.NewLocAppError("getPublicLink", "api.file.get_public_link.disabled.app_error", nil, "")
- c.Err.StatusCode = http.StatusForbidden
+ c.Err.StatusCode = http.StatusNotImplemented
return
}
@@ -488,16 +523,13 @@ func getPublicLink(c *Context, w http.ResponseWriter, r *http.Request) {
data := model.MapToJson(newProps)
hash := model.HashPassword(fmt.Sprintf("%v:%v", data, utils.Cfg.FileSettings.PublicLinkSalt))
- url := fmt.Sprintf("%s/files/get/%s/%s/%s?d=%s&h=%s&t=%s", c.GetSiteURL()+model.API_URL_SUFFIX, channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash), c.TeamId)
+ url := fmt.Sprintf("%s/public/files/get/%s/%s/%s/%s?d=%s&h=%s", c.GetSiteURL()+model.API_URL_SUFFIX, c.TeamId, channelId, userId, filename, url.QueryEscape(data), url.QueryEscape(hash))
if !c.HasPermissionsToChannel(cchan, "getPublicLink") {
return
}
- rData := make(map[string]string)
- rData["public_link"] = url
-
- w.Write([]byte(model.MapToJson(rData)))
+ w.Write([]byte(url))
}
func getExport(c *Context, w http.ResponseWriter, r *http.Request) {