From 7dbf7a3528234b2a9ee9c4115e8ecf58d258ca51 Mon Sep 17 00:00:00 2001 From: kodareef5 Date: Sat, 4 Apr 2026 15:56:55 -0400 Subject: [PATCH] fix: check share owner permissions on public share access (#5888) --- http/public.go | 4 ++++ http/public_test.go | 37 ++++++++++++++++++++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/http/public.go b/http/public.go index 596a03c9..29679be8 100644 --- a/http/public.go +++ b/http/public.go @@ -33,6 +33,10 @@ var withHashFile = func(fn handleFunc) handleFunc { return errToStatus(err), err } + if !user.Perm.Share || !user.Perm.Download { + return http.StatusForbidden, nil + } + d.user = user file, err := files.NewFileInfo(&files.FileOptions{ diff --git a/http/public_test.go b/http/public_test.go index 9a9c7f2e..ea38ce51 100644 --- a/http/public_test.go +++ b/http/public_test.go @@ -23,38 +23,66 @@ func TestPublicShareHandlerAuthentication(t *testing.T) { testCases := map[string]struct { share *share.Link req *http.Request + sharePerm bool + downloadPerm bool expectedStatusCode int }{ "Public share, no auth required": { share: &share.Link{Hash: "h", UserID: 1}, req: newHTTPRequest(t), + sharePerm: true, + downloadPerm: true, expectedStatusCode: 200, }, "Private share, no auth provided, 401": { share: &share.Link{Hash: "h", UserID: 1, PasswordHash: passwordBcrypt, Token: "123"}, req: newHTTPRequest(t), + sharePerm: true, + downloadPerm: true, expectedStatusCode: 401, }, "Private share, authentication via token": { share: &share.Link{Hash: "h", UserID: 1, PasswordHash: passwordBcrypt, Token: "123"}, req: newHTTPRequest(t, func(r *http.Request) { r.URL.RawQuery = "token=123" }), + sharePerm: true, + downloadPerm: true, expectedStatusCode: 200, }, "Private share, authentication via invalid token, 401": { share: &share.Link{Hash: "h", UserID: 1, PasswordHash: passwordBcrypt, Token: "123"}, req: newHTTPRequest(t, func(r *http.Request) { r.URL.RawQuery = "token=1234" }), + sharePerm: true, + downloadPerm: true, expectedStatusCode: 401, }, "Private share, authentication via password": { share: &share.Link{Hash: "h", UserID: 1, PasswordHash: passwordBcrypt, Token: "123"}, req: newHTTPRequest(t, func(r *http.Request) { r.Header.Set("X-SHARE-PASSWORD", "password") }), + sharePerm: true, + downloadPerm: true, expectedStatusCode: 200, }, "Private share, authentication via invalid password, 401": { share: &share.Link{Hash: "h", UserID: 1, PasswordHash: passwordBcrypt, Token: "123"}, req: newHTTPRequest(t, func(r *http.Request) { r.Header.Set("X-SHARE-PASSWORD", "wrong-password") }), + sharePerm: true, + downloadPerm: true, expectedStatusCode: 401, }, + "Share owner lost share permission, 403": { + share: &share.Link{Hash: "h", UserID: 1}, + req: newHTTPRequest(t), + sharePerm: false, + downloadPerm: true, + expectedStatusCode: 403, + }, + "Share owner lost download permission, 403": { + share: &share.Link{Hash: "h", UserID: 1}, + req: newHTTPRequest(t), + sharePerm: true, + downloadPerm: false, + expectedStatusCode: 403, + }, } for name, tc := range testCases { @@ -82,7 +110,14 @@ func TestPublicShareHandlerAuthentication(t *testing.T) { if err := storage.Share.Save(tc.share); err != nil { t.Fatalf("failed to save share: %v", err) } - if err := storage.Users.Save(&users.User{Username: "username", Password: "pw"}); err != nil { + if err := storage.Users.Save(&users.User{ + Username: "username", + Password: "pw", + Perm: users.Permissions{ + Share: tc.sharePerm, + Download: tc.downloadPerm, + }, + }); err != nil { t.Fatalf("failed to save user: %v", err) } if err := storage.Settings.Save(&settings.Settings{Key: []byte("key")}); err != nil {