From 793bd11dcf217104aafffc63a426500b4fb93ec3 Mon Sep 17 00:00:00 2001 From: Gregor Vostrak Date: Mon, 18 May 2026 18:43:48 +0200 Subject: [PATCH] remove member, invitation, and owner email disclosure from Teams/Show inertia props The Teams/Show Inertia page serialized members, pending invitations, and the owner email into props using only a belongsToTeam authorization gate, while the corresponding API endpoints correctly enforced members:view and invitations:view. The serialized data was unused by the live UI (the TeamMemberManager partial that referenced it was orphaned), so dropping the fields removes the disclosure surface without functional impact. The owner card retains name and photo. --- app/Providers/JetstreamServiceProvider.php | 20 - .../Teams/Partials/TeamMemberManager.vue | 448 ------------------ .../Teams/Partials/UpdateTeamNameForm.vue | 3 - resources/js/types/models.d.ts | 4 +- resources/js/types/models.ts | 4 +- .../Endpoint/Web/TeamShowEndpointTest.php | 45 ++ 6 files changed, 47 insertions(+), 477 deletions(-) delete mode 100644 resources/js/Pages/Teams/Partials/TeamMemberManager.vue create mode 100644 tests/Unit/Endpoint/Web/TeamShowEndpointTest.php diff --git a/app/Providers/JetstreamServiceProvider.php b/app/Providers/JetstreamServiceProvider.php index 6a2fb0c4..cc8c3c96 100644 --- a/app/Providers/JetstreamServiceProvider.php +++ b/app/Providers/JetstreamServiceProvider.php @@ -304,28 +304,8 @@ class JetstreamServiceProvider extends ServiceProvider 'owner' => [ 'id' => $owner->getKey(), 'name' => $owner->name, - 'email' => $owner->email, 'profile_photo_url' => $owner->profile_photo_url, ], - 'users' => $teamModel->users->map(function (User $user): array { - return [ - 'id' => $user->getKey(), - 'name' => $user->name, - 'email' => $user->email, - 'profile_photo_url' => $user->profile_photo_url, - 'membership' => [ - 'id' => $user->membership->id, - 'role' => $user->membership->role, - ], - ]; - }), - 'team_invitations' => $teamModel->teamInvitations->map(function (OrganizationInvitation $invitation): array { - return [ - 'id' => $invitation->getKey(), - 'email' => $invitation->email, - 'role' => $invitation->role, - ]; - }), ], 'currencies' => array_map(function (Currency $currency): string { return $currency->getName(); diff --git a/resources/js/Pages/Teams/Partials/TeamMemberManager.vue b/resources/js/Pages/Teams/Partials/TeamMemberManager.vue deleted file mode 100644 index 70371b58..00000000 --- a/resources/js/Pages/Teams/Partials/TeamMemberManager.vue +++ /dev/null @@ -1,448 +0,0 @@ - - - diff --git a/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue b/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue index fbd77d53..fa71caac 100644 --- a/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue +++ b/resources/js/Pages/Teams/Partials/UpdateTeamNameForm.vue @@ -51,9 +51,6 @@ const updateTeamName = () => {
{{ team.owner.name }}
-
- {{ team.owner.email }} -
diff --git a/resources/js/types/models.d.ts b/resources/js/types/models.d.ts index 6ae380e6..3b6fbcd5 100644 --- a/resources/js/types/models.d.ts +++ b/resources/js/types/models.d.ts @@ -22,9 +22,7 @@ export interface Organization { currency: string; created_at: string | null; updated_at: string | null; - owner: User; - users: User[]; - team_invitations: OrganizationInvitation[]; + owner: Pick; } export interface OrganizationInvitation { id: string; diff --git a/resources/js/types/models.ts b/resources/js/types/models.ts index be753b61..6744f8ea 100644 --- a/resources/js/types/models.ts +++ b/resources/js/types/models.ts @@ -29,9 +29,7 @@ export interface Organization { created_at: string | null; updated_at: string | null; // relations - owner: User; - users: User[]; - team_invitations: OrganizationInvitation[]; + owner: Pick; } export interface OrganizationInvitation { diff --git a/tests/Unit/Endpoint/Web/TeamShowEndpointTest.php b/tests/Unit/Endpoint/Web/TeamShowEndpointTest.php new file mode 100644 index 00000000..3a2b892f --- /dev/null +++ b/tests/Unit/Endpoint/Web/TeamShowEndpointTest.php @@ -0,0 +1,45 @@ +createUserWithPermission([]); + OrganizationInvitation::factory()->forOrganization($data->organization)->create([ + 'email' => 'pending@example.com', + ]); + $this->actingAs($data->user); + + // Act + $response = $this->get('/teams/'.$data->organization->getKey()); + + // Assert + $response->assertOk(); + $response->assertInertia(fn (Assert $page) => $page + ->missing('team.users') + ->missing('team.team_invitations') + ->missing('team.owner.email') + ->has('team.owner.id') + ->has('team.owner.name') + ->has('team.owner.profile_photo_url') + ); + } +}