From 9bc219271cb932645a7cd5a1c742b6a1afff5e57 Mon Sep 17 00:00:00 2001 From: Henrique Dias Date: Fri, 17 Oct 2025 17:10:24 +0200 Subject: [PATCH] fix: additive permissions --- lib/handler_test.go | 47 ++++++++++++++++++++++++++++++++++++++++++++- lib/permissions.go | 4 +++- 2 files changed, 49 insertions(+), 2 deletions(-) diff --git a/lib/handler_test.go b/lib/handler_test.go index d805e94..0bcaec7 100644 --- a/lib/handler_test.go +++ b/lib/handler_test.go @@ -217,7 +217,7 @@ users: }) } -func TestServerRules(t *testing.T) { +func TestServerRulesRestrictive(t *testing.T) { t.Parallel() dir := makeTestDirectory(t, map[string][]byte{ @@ -292,6 +292,51 @@ users: require.ErrorContains(t, err, "403") } +func TestServerRulesAdditive(t *testing.T) { + t.Parallel() + + dir := makeTestDirectory(t, map[string][]byte{ + "foo.txt": []byte("foo"), + "bar.js": []byte("foo js"), + "a/foo.js": []byte("foo js"), + "a/foo.txt": []byte("foo txt"), + "b/foo.txt": []byte("foo b"), + }) + + srv := makeTestServer(t, fmt.Sprintf(` +directory: %s +permissions: none + +users: + - username: basic + password: basic + rules: + - regex: "^.+.js$" + permissions: R + - path: "/a/foo.txt" + permissions: CRU + - path: "/b/" + permissions: D +`, dir)) + + client := gowebdav.NewClient(srv.URL, "basic", "basic") + + _, err := client.ReadDir("/") + require.ErrorContains(t, err, "403") + + err = client.Write("/foo.txt", []byte("new"), 0666) + require.ErrorContains(t, err, "403") + + err = client.Write("/new.txt", []byte("new"), 0666) + require.ErrorContains(t, err, "403") + + err = client.Copy("/bar.js", "/a/foo.txt", true) + require.NoError(t, err) + + err = client.Remove("/b/foo.txt") + require.NoError(t, err) +} + func TestServerRulesPrefix(t *testing.T) { t.Parallel() diff --git a/lib/permissions.go b/lib/permissions.go index 2870a35..8d1d67a 100644 --- a/lib/permissions.go +++ b/lib/permissions.go @@ -56,9 +56,11 @@ func (p UserPermissions) Allowed(r *request, fileExists func(string) bool) bool // we fail immediately. If no rule matches, we check the global permissions. if r.method == "COPY" || r.method == "MOVE" { dst := r.destination + ruleMatched := false for i := len(p.Rules) - 1; i >= 0; i-- { if p.Rules[i].Matches(dst) { + ruleMatched = true if !p.Rules[i].Permissions.AllowedDestination(r, fileExists) { return false } @@ -68,7 +70,7 @@ func (p UserPermissions) Allowed(r *request, fileExists func(string) bool) bool } } - if !p.Permissions.AllowedDestination(r, fileExists) { + if !ruleMatched && !p.Permissions.AllowedDestination(r, fileExists) { return false } }