mirror of
https://github.com/hacdias/webdav.git
synced 2026-09-21 19:10:42 +08:00
fix: refactoring previous fix in attempt to address ongoing issues
See #211 and #215
This commit is contained in:
+7
-13
@@ -2,7 +2,6 @@ package lib
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
@@ -116,21 +115,16 @@ func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
|
||||
zap.L().Info("user authorized", zap.String("username", username), zap.String("remote_address", remoteAddr))
|
||||
}
|
||||
|
||||
// Cleanup destination header if it's present by stripping out the prefix
|
||||
// and only keeping the path.
|
||||
if destination := r.Header.Get("Destination"); destination != "" {
|
||||
u, err := url.Parse(destination)
|
||||
if err == nil {
|
||||
destination = strings.TrimPrefix(u.Path, user.Prefix)
|
||||
if !strings.HasPrefix(destination, "/") {
|
||||
destination = "/" + destination
|
||||
}
|
||||
r.Header.Set("Destination", destination)
|
||||
}
|
||||
// Convert the HTTP request into an internal request type
|
||||
req, err := newRequest(r, h.user.Prefix)
|
||||
if err != nil {
|
||||
zap.L().Info("invalid request path or destination", zap.Error(err))
|
||||
http.Error(w, "Invalid request path or destination", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
// Checks for user permissions relatively to this PATH.
|
||||
allowed := user.Allowed(r, func(filename string) bool {
|
||||
allowed := user.Allowed(req, func(filename string) bool {
|
||||
_, err := user.FileSystem.Stat(r.Context(), filename)
|
||||
return !os.IsNotExist(err)
|
||||
})
|
||||
|
||||
+10
-11
@@ -3,7 +3,6 @@ package lib
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"path/filepath"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -51,12 +50,12 @@ type UserPermissions struct {
|
||||
}
|
||||
|
||||
// Allowed checks if the user has permission to access a directory/file
|
||||
func (p UserPermissions) Allowed(r *http.Request, fileExists func(string) bool) bool {
|
||||
func (p UserPermissions) Allowed(r *request, fileExists func(string) bool) bool {
|
||||
// For COPY and MOVE requests, we first check the permissions for the destination
|
||||
// path. As soon as a rule matches and does not allow the operation at the destination,
|
||||
// we fail immediately. If no rule matches, we check the global permissions.
|
||||
if r.Method == "COPY" || r.Method == "MOVE" {
|
||||
dst := r.Header.Get("Destination")
|
||||
if r.method == "COPY" || r.method == "MOVE" {
|
||||
dst := r.destination
|
||||
|
||||
for i := len(p.Rules) - 1; i >= 0; i-- {
|
||||
if p.Rules[i].Matches(dst) {
|
||||
@@ -77,7 +76,7 @@ func (p UserPermissions) Allowed(r *http.Request, fileExists func(string) bool)
|
||||
// Go through rules beginning from the last one, and check the permissions at
|
||||
// the source. The first matched rule returns.
|
||||
for i := len(p.Rules) - 1; i >= 0; i-- {
|
||||
if p.Rules[i].Matches(r.URL.Path) {
|
||||
if p.Rules[i].Matches(r.path) {
|
||||
return p.Rules[i].Permissions.Allowed(r, fileExists)
|
||||
}
|
||||
}
|
||||
@@ -142,8 +141,8 @@ func (p *Permissions) UnmarshalText(data []byte) error {
|
||||
|
||||
// Allowed returns whether this permission set has permissions to execute this
|
||||
// request in the source directory. This applies to all requests with all methods.
|
||||
func (p Permissions) Allowed(r *http.Request, fileExists func(string) bool) bool {
|
||||
switch r.Method {
|
||||
func (p Permissions) Allowed(r *request, fileExists func(string) bool) bool {
|
||||
switch r.method {
|
||||
case "GET", "HEAD", "OPTIONS", "POST", "PROPFIND":
|
||||
// Note: POST backend implementation just returns the same thing as GET.
|
||||
return p.Read
|
||||
@@ -152,7 +151,7 @@ func (p Permissions) Allowed(r *http.Request, fileExists func(string) bool) bool
|
||||
case "PROPPATCH":
|
||||
return p.Update
|
||||
case "PUT":
|
||||
if fileExists(r.URL.Path) {
|
||||
if fileExists(r.path) {
|
||||
return p.Update
|
||||
} else {
|
||||
return p.Create
|
||||
@@ -172,10 +171,10 @@ func (p Permissions) Allowed(r *http.Request, fileExists func(string) bool) bool
|
||||
|
||||
// AllowedDestination returns whether this permissions set has permissions to execute this
|
||||
// request in the destination directory. This only applies for COPY and MOVE requests.
|
||||
func (p Permissions) AllowedDestination(r *http.Request, fileExists func(string) bool) bool {
|
||||
switch r.Method {
|
||||
func (p Permissions) AllowedDestination(r *request, fileExists func(string) bool) bool {
|
||||
switch r.method {
|
||||
case "COPY", "MOVE":
|
||||
if fileExists(r.Header.Get("Destination")) {
|
||||
if fileExists(r.destination) {
|
||||
return p.Update
|
||||
} else {
|
||||
return p.Create
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
package lib
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type request struct {
|
||||
method string
|
||||
path string
|
||||
destination string
|
||||
}
|
||||
|
||||
func newRequest(r *http.Request, prefix string) (*request, error) {
|
||||
ctx := &request{
|
||||
method: r.Method,
|
||||
}
|
||||
|
||||
if destination := r.Header.Get("Destination"); destination != "" {
|
||||
u, err := url.Parse(destination)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid destination header")
|
||||
}
|
||||
|
||||
if prefix != "" {
|
||||
destination = strings.TrimPrefix(u.Path, prefix)
|
||||
if len(destination) >= len(u.Path) {
|
||||
return nil, errors.New("invalid url prefix")
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(destination, "/") {
|
||||
destination = "/" + destination
|
||||
}
|
||||
|
||||
ctx.destination = destination
|
||||
}
|
||||
|
||||
path := r.URL.Path
|
||||
|
||||
if prefix != "" {
|
||||
path = strings.TrimPrefix(r.URL.Path, prefix)
|
||||
if len(path) >= len(r.URL.Path) {
|
||||
return nil, errors.New("invalid url prefix")
|
||||
}
|
||||
}
|
||||
|
||||
if !strings.HasPrefix(path, "/") {
|
||||
path = "/" + path
|
||||
}
|
||||
|
||||
ctx.path = path
|
||||
|
||||
return ctx, nil
|
||||
}
|
||||
Reference in New Issue
Block a user