feat: add im tenant db routing and chapter seven flows
This commit is contained in:
+55
-7
@@ -18,6 +18,7 @@ import (
|
||||
"mime"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -131,12 +132,6 @@ func largeFileServeHTTP(wrt http.ResponseWriter, req *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
if req.Method == http.MethodHead {
|
||||
wrt.WriteHeader(http.StatusOK)
|
||||
logs.Info.Println("media serve: completed", req.Method, "uid=", uid)
|
||||
return
|
||||
}
|
||||
|
||||
fd, rsc, err := mh.Download(tenantID, req.URL.String())
|
||||
if err != nil {
|
||||
writeHttpResponse(decodeStoreError(err, "", now, nil), err)
|
||||
@@ -145,7 +140,15 @@ func largeFileServeHTTP(wrt http.ResponseWriter, req *http.Request) {
|
||||
|
||||
defer rsc.Close()
|
||||
|
||||
if err = authorizeLargeFileDownload(tenantID, uid, req.URL.String(), fd); err != nil {
|
||||
writeHttpResponse(decodeStoreError(err, "", now, nil), err)
|
||||
return
|
||||
}
|
||||
|
||||
wrt.Header().Set("Content-Type", fd.MimeType)
|
||||
if fd.ETag != "" {
|
||||
wrt.Header().Set("ETag", strconv.Quote(fd.ETag))
|
||||
}
|
||||
asAttachment, _ := strconv.ParseBool(req.URL.Query().Get("asatt"))
|
||||
// Force download for html files as a security measure.
|
||||
asAttachment = asAttachment ||
|
||||
@@ -159,7 +162,7 @@ func largeFileServeHTTP(wrt http.ResponseWriter, req *http.Request) {
|
||||
strings.HasPrefix(fd.MimeType, "multipart/") ||
|
||||
strings.HasPrefix(fd.MimeType, "text/")
|
||||
if asAttachment {
|
||||
wrt.Header().Set("Content-Disposition", "attachment")
|
||||
wrt.Header().Set("Content-Disposition", contentDispositionAttachment(fd))
|
||||
}
|
||||
|
||||
http.ServeContent(wrt, req, "", fd.UpdatedAt, rsc)
|
||||
@@ -415,6 +418,11 @@ func (*grpcNodeServer) LargeFileServe(req *pbx.FileDownReq, stream pbx.Node_Larg
|
||||
|
||||
defer rsc.Close()
|
||||
|
||||
if err = authorizeLargeFileDownload(tenantID, uid, req.GetUri(), fd); err != nil {
|
||||
writeResponse(decodeStoreError(err, msgID, now, nil), err)
|
||||
return nil
|
||||
}
|
||||
|
||||
resp.Code = http.StatusOK
|
||||
resp.Text = http.StatusText(http.StatusOK)
|
||||
resp.Meta.Name = fd.Location
|
||||
@@ -445,6 +453,46 @@ func (*grpcNodeServer) LargeFileServe(req *pbx.FileDownReq, stream pbx.Node_Larg
|
||||
return err
|
||||
}
|
||||
|
||||
func authorizeLargeFileDownload(tenantID types.TenantID, uid types.Uid, rawURL string, fd *types.FileDef) error {
|
||||
if fd == nil {
|
||||
return types.ErrNotFound
|
||||
}
|
||||
fid := fd.Uid()
|
||||
if fid.IsZero() && rawURL != "" && store.Store != nil {
|
||||
fid = store.Store.GetMediaHandler().GetIdFromUrl(rawURL)
|
||||
}
|
||||
if fid.IsZero() || fd.TenantID != tenantID || fd.Status != types.UploadCompleted {
|
||||
return types.ErrNotFound
|
||||
}
|
||||
allowed, err := store.Files.UserHasAccess(tenantID, fid.String(), uid)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !allowed {
|
||||
return types.ErrPermissionDenied
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func contentDispositionAttachment(fd *types.FileDef) string {
|
||||
name := strings.TrimSpace(filepath.Base(fd.Location))
|
||||
if name == "." || name == "/" || name == string(filepath.Separator) {
|
||||
name = fd.Uid().String()
|
||||
}
|
||||
clean := strings.Map(func(r rune) rune {
|
||||
switch {
|
||||
case r < 32 || r == 127 || r == '"' || r == '\\' || r == '/' || r == ':':
|
||||
return -1
|
||||
default:
|
||||
return r
|
||||
}
|
||||
}, name)
|
||||
if clean == "" {
|
||||
clean = fd.Uid().String()
|
||||
}
|
||||
return mime.FormatMediaType("attachment", map[string]string{"filename": clean})
|
||||
}
|
||||
|
||||
// LargeFileReceive is the gRPC equivalent of LargeFileReceiveHTTP.
|
||||
func (*grpcNodeServer) LargeFileReceive(stream pbx.Node_LargeFileReceiveServer) error {
|
||||
now := types.TimeNow()
|
||||
|
||||
Reference in New Issue
Block a user