Merge pull request #11979 from appwrite/fix-membership-privacy

Fix: membership privacy bug on production
This commit is contained in:
Matej Bačo
2026-04-23 10:47:54 +02:00
committed by GitHub
4 changed files with 76 additions and 10 deletions
+5
View File
@@ -34,6 +34,11 @@ $console = [
'legalAddress' => '',
'legalTaxId' => '',
'auths' => [
'membershipsUserName' => true,
'membershipsUserEmail' => true,
'membershipsMfa' => true,
'membershipsUserId' => true,
'membershipsUserPhone' => true,
'mockNumbers' => [],
'invites' => System::getEnv('_APP_CONSOLE_INVITES', 'enabled') === 'enabled',
'limit' => (System::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
@@ -70,12 +70,13 @@ class Get extends Action
throw new Exception(Exception::MEMBERSHIP_NOT_FOUND);
}
// Default should be "false", but existing projects already rely on this being "true"
$membershipsPrivacy = [
'userName' => $project->getAttribute('auths', [])['membershipsUserName'] ?? false,
'userEmail' => $project->getAttribute('auths', [])['membershipsUserEmail'] ?? false,
'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? false,
'userId' => $project->getAttribute('auths', [])['membershipsUserId'] ?? false,
'userPhone' => $project->getAttribute('auths', [])['membershipsUserPhone'] ?? false,
'userName' => $project->getAttribute('auths', [])['membershipsUserName'] ?? true,
'userEmail' => $project->getAttribute('auths', [])['membershipsUserEmail'] ?? true,
'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true,
'userId' => $project->getAttribute('auths', [])['membershipsUserId'] ?? true,
'userPhone' => $project->getAttribute('auths', [])['membershipsUserPhone'] ?? true,
];
$roles = $authorization->getRoles();
@@ -123,12 +123,13 @@ class XList extends Action
$memberships = array_filter($memberships, fn (Document $membership) => !empty($membership->getAttribute('userId')));
// Default should be "false", but existing projects already rely on this being "true"
$membershipsPrivacy = [
'userName' => $project->getAttribute('auths', [])['membershipsUserName'] ?? false,
'userEmail' => $project->getAttribute('auths', [])['membershipsUserEmail'] ?? false,
'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? false,
'userId' => $project->getAttribute('auths', [])['membershipsUserId'] ?? false,
'userPhone' => $project->getAttribute('auths', [])['membershipsUserPhone'] ?? false,
'userName' => $project->getAttribute('auths', [])['membershipsUserName'] ?? true,
'userEmail' => $project->getAttribute('auths', [])['membershipsUserEmail'] ?? true,
'mfa' => $project->getAttribute('auths', [])['membershipsMfa'] ?? true,
'userId' => $project->getAttribute('auths', [])['membershipsUserId'] ?? true,
'userPhone' => $project->getAttribute('auths', [])['membershipsUserPhone'] ?? true,
];
$roles = $authorization->getRoles();
@@ -14,6 +14,65 @@ class TeamsConsoleClientTest extends Scope
use ProjectConsole;
use SideClient;
public function testConsoleMembershipPrivacyDefaults(): void
{
$teamData = $this->createTeamHelper();
$membershipData = $this->createAndAcceptMembershipHelper($teamData['teamUid'], $teamData['teamName']);
$teamUid = $teamData['teamUid'];
$projectId = $this->getProject()['$id'];
$owner = $this->getUser();
$memberHeaders = [
'origin' => 'http://localhost',
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
'cookie' => 'a_session_' . $projectId . '=' . $membershipData['session'],
];
$ownerMemberships = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', array_merge([
'content-type' => 'application/json',
'x-appwrite-project' => $projectId,
], $this->getHeaders()));
$this->assertEquals(200, $ownerMemberships['headers']['status-code']);
$this->assertEquals(2, $ownerMemberships['body']['total']);
$ownerMembershipsByUser = [];
foreach ($ownerMemberships['body']['memberships'] as $membership) {
$ownerMembershipsByUser[$membership['userId']] = $membership;
}
$this->assertArrayHasKey($owner['$id'], $ownerMembershipsByUser);
$this->assertContains('owner', $ownerMembershipsByUser[$owner['$id']]['roles']);
$this->assertArrayHasKey($membershipData['userUid'], $ownerMembershipsByUser);
$this->assertNotContains('owner', $ownerMembershipsByUser[$membershipData['userUid']]['roles']);
$this->assertSame($membershipData['userUid'], $ownerMembershipsByUser[$membershipData['userUid']]['userId']);
$this->assertSame($membershipData['name'], $ownerMembershipsByUser[$membershipData['userUid']]['userName']);
$this->assertSame($membershipData['email'], $ownerMembershipsByUser[$membershipData['userUid']]['userEmail']);
$this->assertFalse($ownerMembershipsByUser[$membershipData['userUid']]['mfa']);
$memberMemberships = $this->client->call(Client::METHOD_GET, '/teams/' . $teamUid . '/memberships', $memberHeaders);
$this->assertEquals(200, $memberMemberships['headers']['status-code']);
$this->assertEquals(2, $memberMemberships['body']['total']);
$memberMembershipsByUser = [];
foreach ($memberMemberships['body']['memberships'] as $membership) {
$memberMembershipsByUser[$membership['userId']] = $membership;
}
$this->assertArrayHasKey($owner['$id'], $memberMembershipsByUser);
$this->assertSame($owner['$id'], $memberMembershipsByUser[$owner['$id']]['userId']);
$this->assertSame($owner['name'], $memberMembershipsByUser[$owner['$id']]['userName']);
$this->assertSame($owner['email'], $memberMembershipsByUser[$owner['$id']]['userEmail']);
$this->assertFalse($memberMembershipsByUser[$owner['$id']]['mfa']);
$this->assertContains('owner', $memberMembershipsByUser[$owner['$id']]['roles']);
$this->assertArrayHasKey($membershipData['userUid'], $memberMembershipsByUser);
$this->assertNotContains('owner', $memberMembershipsByUser[$membershipData['userUid']]['roles']);
}
public function testTeamCreateMembershipConsole(): void
{
$teamData = $this->createTeamHelper();