From cf90ab5a9a188041eedadb8324de7340e5fb6991 Mon Sep 17 00:00:00 2001 From: HFO4 <912394456@qq.com> Date: Sat, 21 Dec 2019 18:32:13 +0800 Subject: [PATCH] Fix: unable to save office file in root directory of WebDAV --- middleware/auth.go | 45 +++++++++++++++++++++++++++++++++++ models/init.go | 2 +- pkg/webdav/file.go | 6 ++--- pkg/webdav/webdav.go | 24 ++++++++++--------- routers/controllers/webdav.go | 10 ++++---- routers/router.go | 27 ++++++++++----------- 6 files changed, 78 insertions(+), 36 deletions(-) diff --git a/middleware/auth.go b/middleware/auth.go index a9b2e8a..e5da46e 100644 --- a/middleware/auth.go +++ b/middleware/auth.go @@ -6,6 +6,7 @@ import ( "github.com/HFO4/cloudreve/pkg/serializer" "github.com/gin-contrib/sessions" "github.com/gin-gonic/gin" + "net/http" ) // SignRequired 验证请求签名 @@ -49,3 +50,47 @@ func AuthRequired() gin.HandlerFunc { c.Abort() } } + +// WebDAVAuth 验证WebDAV登录及权限 +func WebDAVAuth() gin.HandlerFunc { + return func(c *gin.Context) { + // OPTIONS 请求不需要鉴权,否则Windows10下无法保存文档 + if c.Request.Method == "OPTIONS" { + c.Next() + return + } + + username, password, ok := c.Request.BasicAuth() + if !ok { + c.Writer.Header()["WWW-Authenticate"] = []string{`Basic realm="cloudreve"`} + c.Status(http.StatusUnauthorized) + c.Abort() + return + } + + expectedUser, err := model.GetUserByEmail(username) + if err != nil { + c.Status(http.StatusUnauthorized) + c.Abort() + return + } + + // 密码正确? + ok, _ = expectedUser.CheckPassword(password) + if !ok { + c.Status(http.StatusUnauthorized) + c.Abort() + return + } + + // 用户组已启用WebDAV? + if !expectedUser.Group.WebDAVEnabled { + c.Status(http.StatusForbidden) + c.Abort() + return + } + + c.Set("user", &expectedUser) + c.Next() + } +} diff --git a/models/init.go b/models/init.go index c782745..bafc977 100644 --- a/models/init.go +++ b/models/init.go @@ -47,7 +47,7 @@ func Init() { // Debug模式下,输出所有 SQL 日志 if conf.SystemConfig.Debug { - db.LogMode(true) + db.LogMode(false) } //db.SetLogger(util.Log()) diff --git a/pkg/webdav/file.go b/pkg/webdav/file.go index cb20e23..a5241b0 100644 --- a/pkg/webdav/file.go +++ b/pkg/webdav/file.go @@ -32,17 +32,17 @@ func moveFiles(ctx context.Context, fs *filesystem.FileSystem, src FileInfo, dst folderIDs []uint ) if src.IsDir() { - fileIDs = []uint{src.(*model.Folder).ID} + folderIDs = []uint{src.(*model.Folder).ID} } else { - folderIDs = []uint{src.(*model.File).ID} + fileIDs = []uint{src.(*model.File).ID} } // 判断是否为重命名 if src.GetPosition() == path.Dir(dst) { err = fs.Rename( ctx, - fileIDs, folderIDs, + fileIDs, path.Base(dst), ) } else { diff --git a/pkg/webdav/webdav.go b/pkg/webdav/webdav.go index 8396fe7..08e11b1 100644 --- a/pkg/webdav/webdav.go +++ b/pkg/webdav/webdav.go @@ -35,8 +35,11 @@ func (h *Handler) stripPrefix(p string, uid uint) (string, int, error) { if h.Prefix == "" { return p, http.StatusOK, nil } - prefix := h.Prefix + strconv.FormatUint(uint64(uid), 10) + prefix := h.Prefix if r := strings.TrimPrefix(p, prefix); len(r) < len(p) { + if len(r) == 0 { + r = "/" + } return util.RemoveSlash(r), http.StatusOK, nil } return p, http.StatusNotFound, errPrefixMismatch @@ -164,9 +167,9 @@ func (h *Handler) confirmLocks(r *http.Request, src, dst string, fs *filesystem. if err != nil { continue } - if u.Host != r.Host { - continue - } + //if u.Host != r.Host { + // continue + //} lsrc, status, err = h.stripPrefix(u.Path, fs.User.ID) if err != nil { return nil, status, err @@ -381,9 +384,9 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil if err != nil { return http.StatusBadRequest, errInvalidDestination } - if u.Host != "" && u.Host != r.Host { - return http.StatusBadGateway, errInvalidDestination - } + //if u.Host != "" && u.Host != r.Host { + // return http.StatusBadGateway, errInvalidDestination + //} src, status, err := h.stripPrefix(r.URL.Path, fs.User.ID) if err != nil { @@ -436,7 +439,9 @@ func (h *Handler) handleCopyMove(w http.ResponseWriter, r *http.Request, fs *fil return copyFiles(ctx, fs, target, dst, r.Header.Get("Overwrite") != "F", depth, 0) } - release, status, err := h.confirmLocks(r, src, dst, fs) + // windows下,某些情况下(网盘根目录下)Office保存文件时附带的锁token只包含源文件, + // 此处暂时去除了对dst锁的检查 + release, status, err := h.confirmLocks(r, src, "", fs) if err != nil { return status, err } @@ -575,9 +580,6 @@ func (h *Handler) handleUnlock(w http.ResponseWriter, r *http.Request, fs *files // OK func (h *Handler) handlePropfind(w http.ResponseWriter, r *http.Request, fs *filesystem.FileSystem) (status int, err error) { reqPath, status, err := h.stripPrefix(r.URL.Path, fs.User.ID) - if reqPath == "" { - reqPath = "/" - } if err != nil { return status, err } diff --git a/routers/controllers/webdav.go b/routers/controllers/webdav.go index 1f2c785..1d72316 100644 --- a/routers/controllers/webdav.go +++ b/routers/controllers/webdav.go @@ -1,7 +1,6 @@ package controllers import ( - model "github.com/HFO4/cloudreve/models" "github.com/HFO4/cloudreve/pkg/filesystem" "github.com/HFO4/cloudreve/pkg/util" "github.com/HFO4/cloudreve/pkg/webdav" @@ -12,18 +11,17 @@ var handler *webdav.Handler func init() { handler = &webdav.Handler{ - Prefix: "/dav/", + Prefix: "/dav", LockSystem: make(map[uint]webdav.LockSystem), } } +// ServeWebDAV 处理WebDAV相关请求 func ServeWebDAV(c *gin.Context) { - // 测试用user - user, _ := model.GetUserByID(1) - c.Set("user", &user) fs, err := filesystem.NewFileSystemFromContext(c) if err != nil { - util.Log().Panic("%s", err) + util.Log().Warning("无法为WebDAV初始化文件系统,%s", err) + return } handler.ServeHTTP(c.Writer, c.Request, fs) diff --git a/routers/router.go b/routers/router.go index 4d364bd..abb7355 100644 --- a/routers/router.go +++ b/routers/router.go @@ -11,21 +11,18 @@ import ( // initWebDAV 初始化WebDAV相关路由 func initWebDAV(group *gin.RouterGroup) { { - group.Any("", func(context *gin.Context) { - context.Status(403) - context.Abort() - }) - - group.Any(":uid/*path", controllers.ServeWebDAV) - group.Any(":uid", controllers.ServeWebDAV) - group.Handle("PROPFIND", ":uid/*path", controllers.ServeWebDAV) - group.Handle("PROPFIND", ":uid", controllers.ServeWebDAV) - group.Handle("MKCOL", ":uid/*path", controllers.ServeWebDAV) - group.Handle("LOCK", ":uid/*path", controllers.ServeWebDAV) - group.Handle("UNLOCK", ":uid/*path", controllers.ServeWebDAV) - group.Handle("PROPPATCH", ":uid/*path", controllers.ServeWebDAV) - group.Handle("COPY", ":uid/*path", controllers.ServeWebDAV) - group.Handle("MOVE", ":uid/*path", controllers.ServeWebDAV) + group.Use(middleware.WebDAVAuth()) + + group.Any("/*path", controllers.ServeWebDAV) + group.Any("", controllers.ServeWebDAV) + group.Handle("PROPFIND", "/*path", controllers.ServeWebDAV) + group.Handle("PROPFIND", "", controllers.ServeWebDAV) + group.Handle("MKCOL", "/*path", controllers.ServeWebDAV) + group.Handle("LOCK", "/*path", controllers.ServeWebDAV) + group.Handle("UNLOCK", "/*path", controllers.ServeWebDAV) + group.Handle("PROPPATCH", "/*path", controllers.ServeWebDAV) + group.Handle("COPY", "/*path", controllers.ServeWebDAV) + group.Handle("MOVE", "/*path", controllers.ServeWebDAV) } }