mirror of https://github.com/cloudreve/Cloudreve
feat(webdav): support setting download proxy
parent
ad6c6bcd93
commit
a1747073df
|
@ -116,6 +116,11 @@ func WebDAVAuth() gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 用户组已启用WebDAV代理?
|
||||||
|
if !expectedUser.Group.OptionsSerialized.WebDAVProxy {
|
||||||
|
webdav.UseProxy = false
|
||||||
|
}
|
||||||
|
|
||||||
c.Set("user", &expectedUser)
|
c.Set("user", &expectedUser)
|
||||||
c.Set("webdav", webdav)
|
c.Set("webdav", webdav)
|
||||||
c.Next()
|
c.Next()
|
||||||
|
|
|
@ -35,6 +35,7 @@ type GroupOption struct {
|
||||||
RedirectedSource bool `json:"redirected_source,omitempty"`
|
RedirectedSource bool `json:"redirected_source,omitempty"`
|
||||||
Aria2BatchSize int `json:"aria2_batch,omitempty"`
|
Aria2BatchSize int `json:"aria2_batch,omitempty"`
|
||||||
AdvanceDelete bool `json:"advance_delete,omitempty"`
|
AdvanceDelete bool `json:"advance_delete,omitempty"`
|
||||||
|
WebDAVProxy bool `json:"webdav_proxy,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// GetGroupByID 用ID获取用户组
|
// GetGroupByID 用ID获取用户组
|
||||||
|
|
|
@ -12,6 +12,7 @@ type Webdav struct {
|
||||||
UserID uint `gorm:"unique_index:password_only_on"` // 用户ID
|
UserID uint `gorm:"unique_index:password_only_on"` // 用户ID
|
||||||
Root string `gorm:"type:text"` // 根目录
|
Root string `gorm:"type:text"` // 根目录
|
||||||
Readonly bool `gorm:"type:bool"` // 是否只读
|
Readonly bool `gorm:"type:bool"` // 是否只读
|
||||||
|
UseProxy bool `gorm:"type:bool"` // 是否进行反代
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create 创建账户
|
// Create 创建账户
|
||||||
|
@ -41,7 +42,7 @@ func DeleteWebDAVAccountByID(id, uid uint) {
|
||||||
DB.Where("user_id = ? and id = ?", uid, id).Delete(&Webdav{})
|
DB.Where("user_id = ? and id = ?", uid, id).Delete(&Webdav{})
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebDAVAccountReadonlyByID 根据账户ID和UID更新账户的只读性
|
// UpdateWebDAVAccountByID 根据账户ID和UID更新账户
|
||||||
func UpdateWebDAVAccountReadonlyByID(id, uid uint, readonly bool) {
|
func UpdateWebDAVAccountByID(id, uid uint, updates map[string]interface{}) {
|
||||||
DB.Model(&Webdav{Model: gorm.Model{ID: id}, UserID: uid}).UpdateColumn("readonly", readonly)
|
DB.Model(&Webdav{Model: gorm.Model{ID: id}, UserID: uid}).Updates(updates)
|
||||||
}
|
}
|
||||||
|
|
|
@ -37,4 +37,8 @@ const (
|
||||||
SlaveSrcPath
|
SlaveSrcPath
|
||||||
// Webdav目标名称
|
// Webdav目标名称
|
||||||
WebdavDstName
|
WebdavDstName
|
||||||
|
// WebDAVCtx WebDAV
|
||||||
|
WebDAVCtx
|
||||||
|
// WebDAV反代Url
|
||||||
|
WebDAVProxyUrlCtx
|
||||||
)
|
)
|
||||||
|
|
|
@ -42,6 +42,7 @@ type group struct {
|
||||||
WebDAVEnabled bool `json:"webdav"`
|
WebDAVEnabled bool `json:"webdav"`
|
||||||
SourceBatchSize int `json:"sourceBatch"`
|
SourceBatchSize int `json:"sourceBatch"`
|
||||||
AdvanceDelete bool `json:"advanceDelete"`
|
AdvanceDelete bool `json:"advanceDelete"`
|
||||||
|
AllowWebDAVProxy bool `json:"allowWebDAVProxy"`
|
||||||
}
|
}
|
||||||
|
|
||||||
type tag struct {
|
type tag struct {
|
||||||
|
@ -100,6 +101,7 @@ func BuildUser(user model.User) User {
|
||||||
ShareDownload: user.Group.OptionsSerialized.ShareDownload,
|
ShareDownload: user.Group.OptionsSerialized.ShareDownload,
|
||||||
CompressEnabled: user.Group.OptionsSerialized.ArchiveTask,
|
CompressEnabled: user.Group.OptionsSerialized.ArchiveTask,
|
||||||
WebDAVEnabled: user.Group.WebDAVEnabled,
|
WebDAVEnabled: user.Group.WebDAVEnabled,
|
||||||
|
AllowWebDAVProxy: user.Group.OptionsSerialized.WebDAVProxy,
|
||||||
SourceBatchSize: user.Group.OptionsSerialized.SourceBatchSize,
|
SourceBatchSize: user.Group.OptionsSerialized.SourceBatchSize,
|
||||||
AdvanceDelete: user.Group.OptionsSerialized.AdvanceDelete,
|
AdvanceDelete: user.Group.OptionsSerialized.AdvanceDelete,
|
||||||
},
|
},
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"net/http/httputil"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
@ -241,6 +242,23 @@ func (h *Handler) handleOptions(w http.ResponseWriter, r *http.Request, fs *file
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var proxy = &httputil.ReverseProxy{
|
||||||
|
Director: func(request *http.Request) {
|
||||||
|
if target, ok := request.Context().Value(fsctx.WebDAVProxyUrlCtx).(*url.URL); ok {
|
||||||
|
request.URL.Scheme = target.Scheme
|
||||||
|
request.URL.Host = target.Host
|
||||||
|
request.URL.Path = target.Path
|
||||||
|
request.URL.RawPath = target.RawPath
|
||||||
|
request.URL.RawQuery = target.RawQuery
|
||||||
|
request.Host = target.Host
|
||||||
|
request.Header.Del("Authorization")
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ErrorHandler: func(writer http.ResponseWriter, request *http.Request, err error) {
|
||||||
|
writer.WriteHeader(http.StatusInternalServerError)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
// OK
|
// OK
|
||||||
func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request, fs *filesystem.FileSystem) (status int, err error) {
|
func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request, fs *filesystem.FileSystem) (status int, err error) {
|
||||||
defer fs.Recycle()
|
defer fs.Recycle()
|
||||||
|
@ -279,7 +297,23 @@ func (h *Handler) handleGetHeadPost(w http.ResponseWriter, r *http.Request, fs *
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if application, ok := r.Context().Value(fsctx.WebDAVCtx).(*model.Webdav); ok && application.UseProxy {
|
||||||
|
target, err := url.Parse(rs.URL)
|
||||||
|
if err != nil {
|
||||||
|
return http.StatusInternalServerError, err
|
||||||
|
}
|
||||||
|
|
||||||
|
r = r.Clone(context.WithValue(r.Context(), fsctx.WebDAVProxyUrlCtx, target))
|
||||||
|
// 忽略反向代理在传输错误时报错
|
||||||
|
defer func() {
|
||||||
|
if err := recover(); err != nil && err != http.ErrAbortHandler {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
proxy.ServeHTTP(w, r)
|
||||||
|
} else {
|
||||||
http.Redirect(w, r, rs.URL, 301)
|
http.Redirect(w, r, rs.URL, 301)
|
||||||
|
}
|
||||||
|
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package controllers
|
package controllers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"context"
|
||||||
model "github.com/cloudreve/Cloudreve/v3/models"
|
model "github.com/cloudreve/Cloudreve/v3/models"
|
||||||
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem"
|
||||||
|
"github.com/cloudreve/Cloudreve/v3/pkg/filesystem/fsctx"
|
||||||
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
"github.com/cloudreve/Cloudreve/v3/pkg/util"
|
||||||
"github.com/cloudreve/Cloudreve/v3/pkg/webdav"
|
"github.com/cloudreve/Cloudreve/v3/pkg/webdav"
|
||||||
"github.com/cloudreve/Cloudreve/v3/service/setting"
|
"github.com/cloudreve/Cloudreve/v3/service/setting"
|
||||||
|
@ -49,6 +51,9 @@ func ServeWebDAV(c *gin.Context) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 更新Context
|
||||||
|
c.Request = c.Request.WithContext(context.WithValue(c.Request.Context(), fsctx.WebDAVCtx, application))
|
||||||
}
|
}
|
||||||
|
|
||||||
handler.ServeHTTP(c.Writer, c.Request, fs)
|
handler.ServeHTTP(c.Writer, c.Request, fs)
|
||||||
|
@ -76,9 +81,9 @@ func DeleteWebDAVAccounts(c *gin.Context) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// UpdateWebDAVAccountsReadonly 更改WebDAV账户只读性
|
// UpdateWebDAVAccounts 更改WebDAV账户只读性和是否使用代理服务
|
||||||
func UpdateWebDAVAccountsReadonly(c *gin.Context) {
|
func UpdateWebDAVAccounts(c *gin.Context) {
|
||||||
var service setting.WebDAVAccountUpdateReadonlyService
|
var service setting.WebDAVAccountUpdateService
|
||||||
if err := c.ShouldBindJSON(&service); err == nil {
|
if err := c.ShouldBindJSON(&service); err == nil {
|
||||||
res := service.Update(c, CurrentUser(c))
|
res := service.Update(c, CurrentUser(c))
|
||||||
c.JSON(200, res)
|
c.JSON(200, res)
|
||||||
|
|
|
@ -721,8 +721,8 @@ func InitMasterRouter() *gin.Engine {
|
||||||
webdav.POST("accounts", controllers.CreateWebDAVAccounts)
|
webdav.POST("accounts", controllers.CreateWebDAVAccounts)
|
||||||
// 删除账号
|
// 删除账号
|
||||||
webdav.DELETE("accounts/:id", controllers.DeleteWebDAVAccounts)
|
webdav.DELETE("accounts/:id", controllers.DeleteWebDAVAccounts)
|
||||||
// 更新账号可读性
|
// 更新账号可读性和是否使用代理服务
|
||||||
webdav.PATCH("accounts", controllers.UpdateWebDAVAccountsReadonly)
|
webdav.PATCH("accounts", controllers.UpdateWebDAVAccounts)
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,10 +22,11 @@ type WebDAVAccountCreateService struct {
|
||||||
Name string `json:"name" binding:"required,min=1,max=255"`
|
Name string `json:"name" binding:"required,min=1,max=255"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebDAVAccountUpdateReadonlyService WebDAV 修改只读性服务
|
// WebDAVAccountUpdateService WebDAV 修改只读性和是否使用代理服务
|
||||||
type WebDAVAccountUpdateReadonlyService struct {
|
type WebDAVAccountUpdateService struct {
|
||||||
ID uint `json:"id" binding:"required,min=1"`
|
ID uint `json:"id" binding:"required,min=1"`
|
||||||
Readonly bool `json:"readonly"`
|
Readonly *bool `json:"readonly" binding:"required_without=UseProxy"`
|
||||||
|
UseProxy *bool `json:"use_proxy" binding:"required_without=Readonly"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// WebDAVMountCreateService WebDAV 挂载创建服务
|
// WebDAVMountCreateService WebDAV 挂载创建服务
|
||||||
|
@ -62,12 +63,17 @@ func (service *WebDAVAccountService) Delete(c *gin.Context, user *model.User) se
|
||||||
return serializer.Response{}
|
return serializer.Response{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update 修改WebDAV账户的只读性
|
// Update 修改WebDAV账户只读性和是否使用代理服务
|
||||||
func (service *WebDAVAccountUpdateReadonlyService) Update(c *gin.Context, user *model.User) serializer.Response {
|
func (service *WebDAVAccountUpdateService) Update(c *gin.Context, user *model.User) serializer.Response {
|
||||||
model.UpdateWebDAVAccountReadonlyByID(service.ID, user.ID, service.Readonly)
|
var updates = make(map[string]interface{})
|
||||||
return serializer.Response{Data: map[string]bool{
|
if service.Readonly != nil {
|
||||||
"readonly": service.Readonly,
|
updates["readonly"] = *service.Readonly
|
||||||
}}
|
}
|
||||||
|
if service.UseProxy != nil {
|
||||||
|
updates["use_proxy"] = *service.UseProxy
|
||||||
|
}
|
||||||
|
model.UpdateWebDAVAccountByID(service.ID, user.ID, updates)
|
||||||
|
return serializer.Response{Data: updates}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Accounts 列出WebDAV账号
|
// Accounts 列出WebDAV账号
|
||||||
|
|
Loading…
Reference in New Issue