mirror of
https://github.com/filebrowser/filebrowser.git
synced 2026-07-17 16:36:49 +00:00
fix(share): delete exact directory share on trailing-slash delete (GHSA-pp88-jhwj-5qh5)
DeleteWithPathPrefix queried the share index with the raw path, so deleting a directory through a trailing-slash path (e.g. DELETE /api/resources/a/) only matched descendants like /a/child and missed the exact /a share, leaving it in storage. If the same path was later recreated, the stale public share re-exposed the new content. Normalize the path before the prefix query so the exact share and its descendants are both removed. Adds a regression test.
This commit is contained in:
parent
ec13054671
commit
f30fca636c
2 changed files with 42 additions and 3 deletions
|
|
@ -78,16 +78,17 @@ func (s shareBackend) Delete(hash string) error {
|
|||
}
|
||||
|
||||
func (s shareBackend) DeleteWithPathPrefix(pathPrefix string, userID uint) error {
|
||||
// Share paths are stored without a trailing slash
|
||||
prefix := strings.TrimRight(pathPrefix, "/")
|
||||
|
||||
var links []share.Link
|
||||
if err := s.db.Prefix("Path", pathPrefix, &links); err != nil {
|
||||
if err := s.db.Prefix("Path", prefix, &links); err != nil {
|
||||
if errors.Is(err, storm.ErrNotFound) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
prefix := strings.TrimRight(pathPrefix, "/")
|
||||
|
||||
var err error
|
||||
for _, link := range links {
|
||||
if link.UserID != userID {
|
||||
|
|
|
|||
|
|
@ -84,6 +84,44 @@ func TestDeleteWithPathPrefix(t *testing.T) {
|
|||
}
|
||||
}
|
||||
|
||||
// Regression for the trailing-slash delete leaving a stale share
|
||||
// (GHSA-pp88-jhwj-5qh5): deleting "/a/" must remove the exact "/a" share and its
|
||||
// descendants, not just the descendants. Siblings and other users are untouched.
|
||||
func TestDeleteWithPathPrefixTrailingSlash(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
s := newTestShareBackend(t)
|
||||
|
||||
links := []*share.Link{
|
||||
{Hash: "u1-a", Path: "/a", UserID: 1},
|
||||
{Hash: "u1-a-child", Path: "/a/child.txt", UserID: 1},
|
||||
{Hash: "u1-abc", Path: "/abc", UserID: 1}, // sibling sharing a byte prefix
|
||||
{Hash: "u2-a", Path: "/a", UserID: 2}, // other user, must remain
|
||||
}
|
||||
for _, l := range links {
|
||||
if err := s.Save(l); err != nil {
|
||||
t.Fatalf("failed to save link %s: %v", l.Hash, err)
|
||||
}
|
||||
}
|
||||
|
||||
// Delete with a trailing slash, as the resource delete handler does for a
|
||||
// directory request like DELETE /api/resources/a/.
|
||||
if err := s.DeleteWithPathPrefix("/a/", 1); err != nil {
|
||||
t.Fatalf("DeleteWithPathPrefix returned error: %v", err)
|
||||
}
|
||||
|
||||
got := remainingHashes(t, s)
|
||||
want := []string{"u1-abc", "u2-a"}
|
||||
if len(got) != len(want) {
|
||||
t.Fatalf("remaining hashes = %v, want %v", got, want)
|
||||
}
|
||||
for i := range want {
|
||||
if got[i] != want[i] {
|
||||
t.Fatalf("remaining hashes = %v, want %v", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDeleteWithPathPrefixNoMatch(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue