diff --git a/README.md b/README.md index e4b934d..d2465f0 100644 --- a/README.md +++ b/README.md @@ -57,6 +57,8 @@ users: - regex: false allow: false path: /some/file + - path: /public/access/ + modify: true ``` There are more ways to customize how you run WebDAV through flags and environment variables. Please run `webdav --help` for more information on that. diff --git a/cmd/config.go b/cmd/config.go index 710248d..8fcd459 100644 --- a/cmd/config.go +++ b/cmd/config.go @@ -14,7 +14,7 @@ import ( "golang.org/x/net/webdav" ) -func parseRules(raw []interface{}) []*lib.Rule { +func parseRules(raw []interface{}, defaultModify bool) []*lib.Rule { rules := []*lib.Rule{} for _, v := range raw { @@ -22,6 +22,7 @@ func parseRules(raw []interface{}) []*lib.Rule { rule := &lib.Rule{ Regex: false, Allow: false, + Modify: defaultModify, Path: "", } @@ -33,6 +34,13 @@ func parseRules(raw []interface{}) []*lib.Rule { rule.Allow = allow } + if modify, ok := r["modify"].(bool); ok { + rule.Modify = modify + if modify { + rule.Allow = true + } + } + path, ok := r["path"].(string) if !ok { continue @@ -110,7 +118,7 @@ func parseUsers(raw []interface{}, c *lib.Config) { } if rules, ok := u["rules"].([]interface{}); ok { - user.Rules = parseRules(rules) + user.Rules = append(c.User.Rules, parseRules(rules, user.Modify)...) } user.Handler = &webdav.Handler{ @@ -186,7 +194,7 @@ func readConfig(flags *pflag.FlagSet) *lib.Config { rawRules := v.Get("rules") if rules, ok := rawRules.([]interface{}); ok { - cfg.User.Rules = parseRules(rules) + cfg.User.Rules = parseRules(rules, cfg.User.Modify) } rawUsers := v.Get("users") diff --git a/lib/user.go b/lib/user.go index 6636322..8b853a2 100755 --- a/lib/user.go +++ b/lib/user.go @@ -11,6 +11,7 @@ import ( type Rule struct { Regex bool Allow bool + Modify bool Path string Regexp *regexp.Regexp } @@ -26,23 +27,24 @@ type User struct { } // Allowed checks if the user has permission to access a directory/file -func (u User) Allowed(url string) bool { +func (u User) Allowed(url string, noModification bool) bool { var rule *Rule i := len(u.Rules) - 1 for i >= 0 { rule = u.Rules[i] + isAllowed := rule.Allow && (noModification || rule.Modify) if rule.Regex { if rule.Regexp.MatchString(url) { - return rule.Allow + return isAllowed } } else if strings.HasPrefix(url, rule.Path) { - return rule.Allow + return isAllowed } i-- } - return true + return noModification || u.Modify } diff --git a/lib/webdav.go b/lib/webdav.go index e8a864f..5b47624 100755 --- a/lib/webdav.go +++ b/lib/webdav.go @@ -102,7 +102,9 @@ func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) { } // Checks for user permissions relatively to this PATH. - if !u.Allowed(r.URL.Path) { + noModification := r.Method == "GET" || r.Method == "HEAD" || + r.Method == "OPTIONS" || r.Method == "PROPFIND" + if !u.Allowed(r.URL.Path, noModification) { w.WriteHeader(http.StatusForbidden) return } @@ -111,15 +113,6 @@ func (c *Config) ServeHTTP(w http.ResponseWriter, r *http.Request) { w = newResponseWriterNoBody(w) } - // If this request modified the files and the user doesn't have permission - // to do so, return forbidden. - if (r.Method == "PUT" || r.Method == "POST" || r.Method == "MKCOL" || - r.Method == "DELETE" || r.Method == "COPY" || r.Method == "MOVE") && - !u.Modify { - w.WriteHeader(http.StatusForbidden) - return - } - // Excerpt from RFC4918, section 9.4: // // GET, when applied to a collection, may return the contents of an