diff --git a/server/subsonic/helpers.go b/server/subsonic/helpers.go index 0e387fafc..70a85bc57 100644 --- a/server/subsonic/helpers.go +++ b/server/subsonic/helpers.go @@ -7,6 +7,7 @@ import ( "fmt" "mime" "net/http" + "slices" "sort" "strings" @@ -485,6 +486,7 @@ func getUserAccessibleLibraries(ctx context.Context) []model.Library { // selectedMusicFolderIds retrieves the music folder IDs from the request parameters. // If no IDs are provided, it returns all libraries the user has access to (based on the user found in the context). // If the parameter is required and not present, it returns an error. +// Invalid library IDs (those the user doesn't have access to) are silently filtered out. func selectedMusicFolderIds(r *http.Request, required bool) ([]int, error) { p := req.Params(r) musicFolderIds, err := p.Ints("musicFolderId") @@ -494,11 +496,21 @@ func selectedMusicFolderIds(r *http.Request, required bool) ([]int, error) { return nil, err } + // Get user's accessible libraries for validation + libraries := getUserAccessibleLibraries(r.Context()) + accessibleLibraryIds := slice.Map(libraries, func(lib model.Library) int { return lib.ID }) + if len(musicFolderIds) > 0 { - return musicFolderIds, nil + // Validate and filter out invalid library IDs + validIds := make([]int, 0, len(musicFolderIds)) + for _, id := range musicFolderIds { + if slices.Contains(accessibleLibraryIds, id) { + validIds = append(validIds, id) + } + } + return validIds, nil } // If no musicFolderId is provided, return all libraries the user has access to. - libraries := getUserAccessibleLibraries(r.Context()) - return slice.Map(libraries, func(lib model.Library) int { return lib.ID }), nil + return accessibleLibraryIds, nil } diff --git a/server/subsonic/helpers_test.go b/server/subsonic/helpers_test.go index 9ebfd3750..2f388217a 100644 --- a/server/subsonic/helpers_test.go +++ b/server/subsonic/helpers_test.go @@ -203,6 +203,24 @@ var _ = Describe("helpers", func() { Expect(err).ToNot(HaveOccurred()) Expect(ids).To(Equal([]int{2})) // Only valid ID is returned }) + + It("should filter out library IDs the user doesn't have access to", func() { + r := httptest.NewRequest("GET", "/test?musicFolderId=1&musicFolderId=5&musicFolderId=2&musicFolderId=99", nil) + r = r.WithContext(ctx) + + ids, err := selectedMusicFolderIds(r, false) + Expect(err).ToNot(HaveOccurred()) + Expect(ids).To(Equal([]int{1, 2})) // Only accessible libraries (1, 2) are returned, 5 and 99 are filtered out + }) + + It("should return empty slice when user has no access to any of the requested libraries", func() { + r := httptest.NewRequest("GET", "/test?musicFolderId=99&musicFolderId=100", nil) + r = r.WithContext(ctx) + + ids, err := selectedMusicFolderIds(r, false) + Expect(err).ToNot(HaveOccurred()) + Expect(ids).To(Equal([]int{})) // No accessible libraries in the request + }) }) Context("when musicFolderId parameter is not provided", func() {