From 5a726cda188b0b47ddd7b746342c99b2cdeb51ce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 22:10:24 +0000 Subject: [PATCH 1/2] Fix hidden album disclosure in photo album list Co-authored-by: ildyria <627094+ildyria@users.noreply.github.com> --- .../Controllers/Gallery/PhotoController.php | 22 +++++++++++++++++- tests/Feature_v2/Photo/GetPhotoAlbumsTest.php | 23 +++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/app/Http/Controllers/Gallery/PhotoController.php b/app/Http/Controllers/Gallery/PhotoController.php index 6916487b628..a0dcadb57b6 100644 --- a/app/Http/Controllers/Gallery/PhotoController.php +++ b/app/Http/Controllers/Gallery/PhotoController.php @@ -42,6 +42,7 @@ use App\Jobs\ExtractZip; use App\Jobs\ProcessImageJob; use App\Jobs\WatermarkerJob; +use App\Models\Extensions\BaseAlbum; use App\Models\Photo; use App\Models\SizeVariant; use App\Models\Tag; @@ -325,7 +326,26 @@ public function albums(GetPhotoAlbumsRequest $request): Collection $album_policy = resolve(AlbumPolicy::class); return $photo->albums - ->filter(fn ($album) => $album_policy->canAccess($user, $album)) + ->filter(function ($album) use ($album_policy, $user) { + if (!$album instanceof BaseAlbum) { + return $album_policy->canAccess($user, $album); + } + + // Owner always sees their albums in the list + if ($album_policy->isOwner($user, $album)) { + return true; + } + + // Explicitly shared albums are visible to the shared user + if ($album->current_user_permissions() !== null) { + return true; + } + + // Public albums are only shown if not link-required (hidden from listings) + return $album->public_permissions() !== null && + $album->public_permissions()->is_link_required === false && + ($album->public_permissions()->password === null || $album_policy->isUnlocked($album)); + }) ->values() ->map(fn ($album) => new PhotoAlbumResource($album)); } diff --git a/tests/Feature_v2/Photo/GetPhotoAlbumsTest.php b/tests/Feature_v2/Photo/GetPhotoAlbumsTest.php index 6b1babda064..b7163779f0b 100644 --- a/tests/Feature_v2/Photo/GetPhotoAlbumsTest.php +++ b/tests/Feature_v2/Photo/GetPhotoAlbumsTest.php @@ -18,6 +18,7 @@ namespace Tests\Feature_v2\Photo; +use App\Models\AccessPermission; use App\Models\Album; use App\Models\Photo; use Tests\Feature_v2\Base\BaseApiWithDataTest; @@ -104,4 +105,26 @@ public function testPhotoWithNoAlbumsReturnsEmptyArray(): void $response->assertJsonCount(0); $response->assertExactJson([]); } + + /** + * S-018-08: Hidden (link-required) albums are not shown to non-owners. + * + * Regression test for https://github.com/LycheeOrg/Lychee/discussions/4355 + */ + public function testHiddenAlbumNotShownToNonOwner(): void + { + // photo4 is in album4 (public+visible). Also place it in a new hidden album. + $hiddenAlbum = Album::factory()->as_root()->owned_by($this->userLocked)->create(); + // Public permission with is_link_required=true (hidden from listings) + AccessPermission::factory()->public()->for_album($hiddenAlbum)->create(); + $this->photo4->albums()->syncWithoutDetaching([$hiddenAlbum->id]); + + // A guest user should only see album4 (the visible one), NOT the hidden album + $response = $this->getJson('Photo/' . $this->photo4->id . '/albums'); + $this->assertOk($response); + + $response->assertJsonCount(1); + $response->assertJsonFragment(['id' => $this->album4->id]); + $response->assertJsonMissing(['id' => $hiddenAlbum->id]); + } } From 597bceef495faeb1090738d1ff4b099ae2e09f04 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 31 May 2026 22:11:31 +0000 Subject: [PATCH 2/2] Refactor: cache public_permissions() result in albums filter Co-authored-by: ildyria <627094+ildyria@users.noreply.github.com> --- app/Http/Controllers/Gallery/PhotoController.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/app/Http/Controllers/Gallery/PhotoController.php b/app/Http/Controllers/Gallery/PhotoController.php index a0dcadb57b6..40fb71dfb5f 100644 --- a/app/Http/Controllers/Gallery/PhotoController.php +++ b/app/Http/Controllers/Gallery/PhotoController.php @@ -342,9 +342,11 @@ public function albums(GetPhotoAlbumsRequest $request): Collection } // Public albums are only shown if not link-required (hidden from listings) - return $album->public_permissions() !== null && - $album->public_permissions()->is_link_required === false && - ($album->public_permissions()->password === null || $album_policy->isUnlocked($album)); + $public_perm = $album->public_permissions(); + + return $public_perm !== null && + $public_perm->is_link_required === false && + ($public_perm->password === null || $album_policy->isUnlocked($album)); }) ->values() ->map(fn ($album) => new PhotoAlbumResource($album));