diff --git a/backend/webdav/webdav.go b/backend/webdav/webdav.go index f3e2ee905..62f58ed17 100644 --- a/backend/webdav/webdav.go +++ b/backend/webdav/webdav.go @@ -40,6 +40,7 @@ import ( "github.com/rclone/rclone/lib/rest" ntlmssp "github.com/Azure/go-ntlmssp" + "github.com/icholy/digest" ) const ( @@ -409,6 +410,24 @@ func (o *Object) filePath() string { return o.fs.filePath(o.remote) } +// checkForDigestAuth issues an unauthenticated request to the server to +// determine if 'Digest' is among the supported authentication schemes. +// Multiple challenges may be specified in a single response header +// or provided in separate headers in the same response. +// +// See https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/WWW-Authenticate +func checkForDigestAuth(url string) bool { + resp, err := http.Get(url) + if err == nil { + for _, challenge := range resp.Header["Www-Authenticate"] { + if strings.Contains(challenge, "Digest") { + return true + } + } + } + return false +} + // NewFs constructs an Fs from the path, container:path func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, error) { // Parse config into Options struct @@ -482,6 +501,18 @@ func NewFs(ctx context.Context, name, root string, m configmap.Mapper) (fs.Fs, e rt: ntlmssp.Negotiator{RoundTripper: t}, } } + if opt.Vendor == "other" { + // If available, prefer Digest authentication. + if checkForDigestAuth(opt.URL) { + fs.Debugf(nil, "using Digest authentication scheme") + client.Transport = &digest.Transport{ + Jar: client.Jar, + Username: opt.User, + Password: opt.Pass, + } + } + } + f.srv = rest.NewClient(client).SetRoot(u.String()) f.features = (&fs.Features{ diff --git a/go.mod b/go.mod index b9b03e310..ad587f479 100644 --- a/go.mod +++ b/go.mod @@ -222,6 +222,7 @@ require ( github.com/Microsoft/go-winio v0.6.1 // indirect github.com/ProtonMail/go-crypto v1.1.3 github.com/golang-jwt/jwt/v4 v4.5.1 + github.com/icholy/digest v1.0.1 github.com/pkg/xattr v0.4.10 golang.org/x/mobile v0.0.0-20240716161057-1ad2df20a8b6 golang.org/x/term v0.27.0 diff --git a/go.sum b/go.sum index 70ad47b58..93c653d04 100644 --- a/go.sum +++ b/go.sum @@ -375,6 +375,8 @@ github.com/henrybear327/go-proton-api v1.0.0 h1:zYi/IbjLwFAW7ltCeqXneUGJey0TN//X github.com/henrybear327/go-proton-api v1.0.0/go.mod h1:w63MZuzufKcIZ93pwRgiOtxMXYafI8H74D77AxytOBc= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/icholy/digest v1.0.1 h1:HBhK5/Ab2Z4rHgw6n5UooxcJpLSeMR+TuD5rkvRc7Z8= +github.com/icholy/digest v1.0.1/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8=