Files
appwrite/tests/e2e/Services/Project/PoliciesBase.php
Matej Bačo 5eb4c6b310 Fix tests
2026-05-11 18:38:30 +02:00

1187 lines
44 KiB
PHP

<?php
namespace Tests\E2E\Services\Project;
use Tests\E2E\Client;
use Utopia\Database\Query;
trait PoliciesBase
{
// =========================================================================
// Get Policy
// =========================================================================
public function testGetPolicy(): void
{
$expectedFields = [
'password-dictionary' => ['enabled'],
'password-history' => ['total'],
'password-personal-data' => ['enabled'],
'session-alert' => ['enabled'],
'session-duration' => ['duration'],
'session-invalidation' => ['enabled'],
'session-limit' => ['total'],
'user-limit' => ['total'],
'membership-privacy' => ['userId', 'userEmail', 'userPhone', 'userName', 'userMFA'],
];
foreach ($expectedFields as $policyId => $fields) {
$response = $this->getPolicy($policyId);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame($policyId, $response['body']['$id']);
foreach ($fields as $field) {
$this->assertArrayHasKey($field, $response['body']);
}
}
}
public function testGetPolicyMatchesListPolicies(): void
{
$list = $this->listPolicies();
$this->assertSame(200, $list['headers']['status-code']);
$byId = [];
foreach ($list['body']['policies'] as $policy) {
$byId[$policy['$id']] = $policy;
}
foreach (\array_keys($byId) as $policyId) {
$response = $this->getPolicy($policyId);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame($byId[$policyId], $response['body']);
}
}
public function testGetPolicyReflectsUpdates(): void
{
$this->updatePasswordDictionaryPolicy(true);
$this->updatePasswordHistoryPolicy(5);
$this->updateSessionDurationPolicy(3600);
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => false,
'userName' => true,
'userMFA' => true,
]);
$passwordDictionary = $this->getPolicy('password-dictionary');
$passwordHistory = $this->getPolicy('password-history');
$sessionDuration = $this->getPolicy('session-duration');
$membershipPrivacy = $this->getPolicy('membership-privacy');
$this->assertSame(200, $passwordDictionary['headers']['status-code']);
$this->assertSame(true, $passwordDictionary['body']['enabled']);
$this->assertSame(200, $passwordHistory['headers']['status-code']);
$this->assertSame(5, $passwordHistory['body']['total']);
$this->assertSame(200, $sessionDuration['headers']['status-code']);
$this->assertSame(3600, $sessionDuration['body']['duration']);
$this->assertSame(200, $membershipPrivacy['headers']['status-code']);
$this->assertSame(true, $membershipPrivacy['body']['userId']);
$this->assertSame(true, $membershipPrivacy['body']['userEmail']);
$this->assertSame(false, $membershipPrivacy['body']['userPhone']);
$this->assertSame(true, $membershipPrivacy['body']['userName']);
$this->assertSame(true, $membershipPrivacy['body']['userMFA']);
// Cleanup
$this->updatePasswordDictionaryPolicy(false);
$this->updatePasswordHistoryPolicy(null);
$this->updateSessionDurationPolicy(31536000);
$this->updateMembershipPrivacyPolicy([
'userId' => false,
'userEmail' => false,
'userPhone' => false,
'userName' => false,
'userMFA' => false,
]);
}
public function testGetPolicyWithoutAuthentication(): void
{
$response = $this->getPolicy('password-dictionary', authenticated: false);
$this->assertSame(401, $response['headers']['status-code']);
}
public function testGetPolicyInvalidPolicyId(): void
{
$response = $this->getPolicy('invalid-policy');
$this->assertSame(400, $response['headers']['status-code']);
}
// =========================================================================
// List Policies
// =========================================================================
public function testListPolicies(): void
{
$response = $this->listPolicies();
$this->assertSame(200, $response['headers']['status-code']);
$this->assertArrayHasKey('policies', $response['body']);
$this->assertArrayHasKey('total', $response['body']);
$this->assertIsArray($response['body']['policies']);
$this->assertIsInt($response['body']['total']);
$this->assertSame(9, $response['body']['total']);
$this->assertCount(9, $response['body']['policies']);
$policyIds = \array_column($response['body']['policies'], '$id');
$this->assertContains('password-dictionary', $policyIds);
$this->assertContains('password-history', $policyIds);
$this->assertContains('password-personal-data', $policyIds);
$this->assertContains('session-alert', $policyIds);
$this->assertContains('session-duration', $policyIds);
$this->assertContains('session-invalidation', $policyIds);
$this->assertContains('session-limit', $policyIds);
$this->assertContains('user-limit', $policyIds);
$this->assertContains('membership-privacy', $policyIds);
}
public function testListPoliciesResponseModel(): void
{
$response = $this->listPolicies();
$this->assertSame(200, $response['headers']['status-code']);
foreach ($response['body']['policies'] as $policy) {
$this->assertArrayHasKey('$id', $policy);
}
$byId = [];
foreach ($response['body']['policies'] as $policy) {
$byId[$policy['$id']] = $policy;
}
$this->assertArrayHasKey('enabled', $byId['password-dictionary']);
$this->assertArrayHasKey('total', $byId['password-history']);
$this->assertArrayHasKey('enabled', $byId['password-personal-data']);
$this->assertArrayHasKey('enabled', $byId['session-alert']);
$this->assertArrayHasKey('duration', $byId['session-duration']);
$this->assertArrayHasKey('enabled', $byId['session-invalidation']);
$this->assertArrayHasKey('total', $byId['session-limit']);
$this->assertArrayHasKey('total', $byId['user-limit']);
$this->assertArrayHasKey('userId', $byId['membership-privacy']);
$this->assertArrayHasKey('userEmail', $byId['membership-privacy']);
$this->assertArrayHasKey('userPhone', $byId['membership-privacy']);
$this->assertArrayHasKey('userName', $byId['membership-privacy']);
$this->assertArrayHasKey('userMFA', $byId['membership-privacy']);
}
public function testListPoliciesReflectsUpdates(): void
{
$this->updatePasswordDictionaryPolicy(true);
$this->updatePasswordHistoryPolicy(5);
$this->updateSessionDurationPolicy(3600);
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => false,
'userName' => true,
'userMFA' => true,
]);
$response = $this->listPolicies();
$this->assertSame(200, $response['headers']['status-code']);
$byId = [];
foreach ($response['body']['policies'] as $policy) {
$byId[$policy['$id']] = $policy;
}
$this->assertSame(true, $byId['password-dictionary']['enabled']);
$this->assertSame(5, $byId['password-history']['total']);
$this->assertSame(3600, $byId['session-duration']['duration']);
$this->assertSame(true, $byId['membership-privacy']['userId']);
$this->assertSame(true, $byId['membership-privacy']['userEmail']);
$this->assertSame(false, $byId['membership-privacy']['userPhone']);
$this->assertSame(true, $byId['membership-privacy']['userName']);
$this->assertSame(true, $byId['membership-privacy']['userMFA']);
// Cleanup
$this->updatePasswordDictionaryPolicy(false);
$this->updatePasswordHistoryPolicy(null);
$this->updateSessionDurationPolicy(31536000);
$this->updateMembershipPrivacyPolicy([
'userId' => false,
'userEmail' => false,
'userPhone' => false,
'userName' => false,
'userMFA' => false,
]);
}
public function testListPoliciesTotalFalse(): void
{
$response = $this->listPolicies(total: false);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(0, $response['body']['total']);
$this->assertCount(9, $response['body']['policies']);
}
public function testListPoliciesWithLimit(): void
{
$response = $this->listPolicies([
Query::limit(1)->toString(),
]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertCount(1, $response['body']['policies']);
$this->assertSame(9, $response['body']['total']);
}
public function testListPoliciesWithOffset(): void
{
$listAll = $this->listPolicies();
$this->assertSame(200, $listAll['headers']['status-code']);
$listOffset = $this->listPolicies([
Query::offset(1)->toString(),
]);
$this->assertSame(200, $listOffset['headers']['status-code']);
$this->assertCount(\count($listAll['body']['policies']) - 1, $listOffset['body']['policies']);
$this->assertSame($listAll['body']['total'], $listOffset['body']['total']);
}
public function testListPoliciesWithoutAuthentication(): void
{
$response = $this->listPolicies(authenticated: false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Password Dictionary Policy
// =========================================================================
public function testUpdatePasswordDictionaryPolicyEnable(): void
{
$response = $this->updatePasswordDictionaryPolicy(true);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(true, $response['body']['authPasswordDictionary']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(true, $project['body']['authPasswordDictionary']);
// Cleanup
$this->updatePasswordDictionaryPolicy(false);
}
public function testUpdatePasswordDictionaryPolicyDisable(): void
{
$this->updatePasswordDictionaryPolicy(true);
$response = $this->updatePasswordDictionaryPolicy(false);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authPasswordDictionary']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(false, $project['body']['authPasswordDictionary']);
}
public function testUpdatePasswordDictionaryPolicyIdempotent(): void
{
$first = $this->updatePasswordDictionaryPolicy(true);
$this->assertSame(200, $first['headers']['status-code']);
$this->assertSame(true, $first['body']['authPasswordDictionary']);
$second = $this->updatePasswordDictionaryPolicy(true);
$this->assertSame(200, $second['headers']['status-code']);
$this->assertSame(true, $second['body']['authPasswordDictionary']);
// Cleanup
$this->updatePasswordDictionaryPolicy(false);
}
public function testUpdatePasswordDictionaryPolicyWithoutAuth(): void
{
$response = $this->updatePasswordDictionaryPolicy(true, false);
$this->assertSame(401, $response['headers']['status-code']);
}
public function testUpdatePasswordDictionaryPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-dictionary', $this->buildHeaders(), [
'enabled' => 'not-a-boolean',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordDictionaryPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-dictionary', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
// =========================================================================
// Password History Policy
// =========================================================================
public function testUpdatePasswordHistoryPolicyEnable(): void
{
$response = $this->updatePasswordHistoryPolicy(5);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(5, $response['body']['authPasswordHistory']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(5, $project['body']['authPasswordHistory']);
// Cleanup (disable by setting total to null which maps to 0)
$this->updatePasswordHistoryPolicy(null);
}
public function testUpdatePasswordHistoryPolicyMin(): void
{
$response = $this->updatePasswordHistoryPolicy(1);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(1, $response['body']['authPasswordHistory']);
// Cleanup
$this->updatePasswordHistoryPolicy(null);
}
public function testUpdatePasswordHistoryPolicyMax(): void
{
$response = $this->updatePasswordHistoryPolicy(5000);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(5000, $response['body']['authPasswordHistory']);
// Cleanup
$this->updatePasswordHistoryPolicy(null);
}
public function testUpdatePasswordHistoryPolicyDisable(): void
{
$this->updatePasswordHistoryPolicy(5);
$response = $this->updatePasswordHistoryPolicy(null);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(0, $response['body']['authPasswordHistory']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(0, $project['body']['authPasswordHistory']);
}
public function testUpdatePasswordHistoryPolicyBelowMin(): void
{
$response = $this->updatePasswordHistoryPolicy(0);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordHistoryPolicyAboveMax(): void
{
$response = $this->updatePasswordHistoryPolicy(5001);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordHistoryPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-history', $this->buildHeaders(), [
'total' => 'not-a-number',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordHistoryPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-history', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordHistoryPolicyWithoutAuth(): void
{
$response = $this->updatePasswordHistoryPolicy(5, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Password Personal Data Policy
// =========================================================================
public function testUpdatePasswordPersonalDataPolicyEnable(): void
{
$response = $this->updatePasswordPersonalDataPolicy(true);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(true, $response['body']['authPersonalDataCheck']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(true, $project['body']['authPersonalDataCheck']);
// Cleanup
$this->updatePasswordPersonalDataPolicy(false);
}
public function testUpdatePasswordPersonalDataPolicyDisable(): void
{
$this->updatePasswordPersonalDataPolicy(true);
$response = $this->updatePasswordPersonalDataPolicy(false);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authPersonalDataCheck']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(false, $project['body']['authPersonalDataCheck']);
}
public function testUpdatePasswordPersonalDataPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-personal-data', $this->buildHeaders(), [
'enabled' => 'not-a-boolean',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordPersonalDataPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/password-personal-data', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdatePasswordPersonalDataPolicyWithoutAuth(): void
{
$response = $this->updatePasswordPersonalDataPolicy(true, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Session Alert Policy
// =========================================================================
public function testUpdateSessionAlertPolicyEnable(): void
{
$response = $this->updateSessionAlertPolicy(true);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(true, $response['body']['authSessionAlerts']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(true, $project['body']['authSessionAlerts']);
// Cleanup
$this->updateSessionAlertPolicy(false);
}
public function testUpdateSessionAlertPolicyDisable(): void
{
$this->updateSessionAlertPolicy(true);
$response = $this->updateSessionAlertPolicy(false);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authSessionAlerts']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(false, $project['body']['authSessionAlerts']);
}
public function testUpdateSessionAlertPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-alert', $this->buildHeaders(), [
'enabled' => 'not-a-boolean',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionAlertPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-alert', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionAlertPolicyWithoutAuth(): void
{
$response = $this->updateSessionAlertPolicy(true, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Session Duration Policy
// =========================================================================
public function testUpdateSessionDurationPolicy(): void
{
$response = $this->updateSessionDurationPolicy(3600);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(3600, $response['body']['authDuration']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(3600, $project['body']['authDuration']);
// Cleanup (reset to default 1 year)
$this->updateSessionDurationPolicy(31536000);
}
public function testUpdateSessionDurationPolicyMin(): void
{
$response = $this->updateSessionDurationPolicy(5);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(5, $response['body']['authDuration']);
// Cleanup
$this->updateSessionDurationPolicy(31536000);
}
public function testUpdateSessionDurationPolicyMax(): void
{
$response = $this->updateSessionDurationPolicy(31536000);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(31536000, $response['body']['authDuration']);
}
public function testUpdateSessionDurationPolicyBelowMin(): void
{
$response = $this->updateSessionDurationPolicy(4);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionDurationPolicyAboveMax(): void
{
$response = $this->updateSessionDurationPolicy(31536001);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionDurationPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-duration', $this->buildHeaders(), [
'duration' => 'not-a-number',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionDurationPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-duration', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionDurationPolicyWithoutAuth(): void
{
$response = $this->updateSessionDurationPolicy(3600, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Session Invalidation Policy
// =========================================================================
public function testUpdateSessionInvalidationPolicyEnable(): void
{
$response = $this->updateSessionInvalidationPolicy(true);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(true, $response['body']['authInvalidateSessions']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(true, $project['body']['authInvalidateSessions']);
// Cleanup
$this->updateSessionInvalidationPolicy(false);
}
public function testUpdateSessionInvalidationPolicyDisable(): void
{
$this->updateSessionInvalidationPolicy(true);
$response = $this->updateSessionInvalidationPolicy(false);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authInvalidateSessions']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(false, $project['body']['authInvalidateSessions']);
}
public function testUpdateSessionInvalidationPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-invalidation', $this->buildHeaders(), [
'enabled' => 'not-a-boolean',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionInvalidationPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-invalidation', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionInvalidationPolicyWithoutAuth(): void
{
$response = $this->updateSessionInvalidationPolicy(true, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Session Limit Policy
// =========================================================================
public function testUpdateSessionLimitPolicy(): void
{
$response = $this->updateSessionLimitPolicy(5);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(5, $response['body']['authSessionsLimit']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(5, $project['body']['authSessionsLimit']);
// Cleanup (reset to default)
$this->updateSessionLimitPolicy(10);
}
public function testUpdateSessionLimitPolicyMin(): void
{
$response = $this->updateSessionLimitPolicy(1);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(1, $response['body']['authSessionsLimit']);
// Cleanup
$this->updateSessionLimitPolicy(10);
}
public function testUpdateSessionLimitPolicyMax(): void
{
$response = $this->updateSessionLimitPolicy(5000);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(5000, $response['body']['authSessionsLimit']);
// Cleanup
$this->updateSessionLimitPolicy(10);
}
public function testUpdateSessionLimitPolicyDisable(): void
{
$response = $this->updateSessionLimitPolicy(null);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(0, $response['body']['authSessionsLimit']);
// Cleanup
$this->updateSessionLimitPolicy(10);
}
public function testUpdateSessionLimitPolicyBelowMin(): void
{
$response = $this->updateSessionLimitPolicy(0);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionLimitPolicyAboveMax(): void
{
$response = $this->updateSessionLimitPolicy(5001);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionLimitPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-limit', $this->buildHeaders(), [
'total' => 'not-a-number',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionLimitPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/session-limit', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateSessionLimitPolicyWithoutAuth(): void
{
$response = $this->updateSessionLimitPolicy(5, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// User Limit Policy
// =========================================================================
public function testUpdateUserLimitPolicy(): void
{
$response = $this->updateUserLimitPolicy(100);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(100, $response['body']['authLimit']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(100, $project['body']['authLimit']);
// Cleanup
$this->updateUserLimitPolicy(null);
}
public function testUpdateUserLimitPolicyMin(): void
{
$response = $this->updateUserLimitPolicy(1);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(1, $response['body']['authLimit']);
// Cleanup
$this->updateUserLimitPolicy(null);
}
public function testUpdateUserLimitPolicyMax(): void
{
$response = $this->updateUserLimitPolicy(5000);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(5000, $response['body']['authLimit']);
// Cleanup
$this->updateUserLimitPolicy(null);
}
public function testUpdateUserLimitPolicyDisable(): void
{
$this->updateUserLimitPolicy(100);
$response = $this->updateUserLimitPolicy(null);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(0, $response['body']['authLimit']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(0, $project['body']['authLimit']);
}
public function testUpdateUserLimitPolicyBelowMin(): void
{
$response = $this->updateUserLimitPolicy(0);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateUserLimitPolicyAboveMax(): void
{
$response = $this->updateUserLimitPolicy(5001);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateUserLimitPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/user-limit', $this->buildHeaders(), [
'total' => 'not-a-number',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateUserLimitPolicyMissingParam(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/user-limit', $this->buildHeaders(), []);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateUserLimitPolicyWithoutAuth(): void
{
$response = $this->updateUserLimitPolicy(100, false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Membership Privacy Policy
// =========================================================================
public function testUpdateMembershipPrivacyPolicyAllEnabled(): void
{
$response = $this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertNotEmpty($response['body']['$id']);
$this->assertSame(true, $response['body']['authMembershipsUserId']);
$this->assertSame(true, $response['body']['authMembershipsUserEmail']);
$this->assertSame(true, $response['body']['authMembershipsUserPhone']);
$this->assertSame(true, $response['body']['authMembershipsUserName']);
$this->assertSame(true, $response['body']['authMembershipsMfa']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(true, $project['body']['authMembershipsUserId']);
$this->assertSame(true, $project['body']['authMembershipsUserEmail']);
$this->assertSame(true, $project['body']['authMembershipsUserPhone']);
$this->assertSame(true, $project['body']['authMembershipsUserName']);
$this->assertSame(true, $project['body']['authMembershipsMfa']);
}
public function testUpdateMembershipPrivacyPolicyAllDisabled(): void
{
$response = $this->updateMembershipPrivacyPolicy([
'userId' => false,
'userEmail' => false,
'userPhone' => false,
'userName' => false,
'userMFA' => false,
]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authMembershipsUserId']);
$this->assertSame(false, $response['body']['authMembershipsUserEmail']);
$this->assertSame(false, $response['body']['authMembershipsUserPhone']);
$this->assertSame(false, $response['body']['authMembershipsUserName']);
$this->assertSame(false, $response['body']['authMembershipsMfa']);
$project = $this->getProjectDocument();
$this->assertSame(200, $project['headers']['status-code']);
$this->assertSame(false, $project['body']['authMembershipsUserId']);
$this->assertSame(false, $project['body']['authMembershipsUserEmail']);
$this->assertSame(false, $project['body']['authMembershipsUserPhone']);
$this->assertSame(false, $project['body']['authMembershipsUserName']);
$this->assertSame(false, $project['body']['authMembershipsMfa']);
// Cleanup (restore defaults)
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
}
public function testUpdateMembershipPrivacyPolicyMixed(): void
{
$response = $this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => false,
'userPhone' => true,
'userName' => false,
'userMFA' => true,
]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(true, $response['body']['authMembershipsUserId']);
$this->assertSame(false, $response['body']['authMembershipsUserEmail']);
$this->assertSame(true, $response['body']['authMembershipsUserPhone']);
$this->assertSame(false, $response['body']['authMembershipsUserName']);
$this->assertSame(true, $response['body']['authMembershipsMfa']);
// Cleanup
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
}
public function testUpdateMembershipPrivacyPolicyIndividualFields(): void
{
// Start from a known baseline where every field is enabled
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
$fields = [
'userId' => 'authMembershipsUserId',
'userEmail' => 'authMembershipsUserEmail',
'userPhone' => 'authMembershipsUserPhone',
'userName' => 'authMembershipsUserName',
'userMFA' => 'authMembershipsMfa',
];
// Each field can be toggled individually without clobbering the others
foreach ($fields as $param => $attribute) {
$response = $this->updateMembershipPrivacyPolicy([$param => false]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body'][$attribute]);
foreach ($fields as $otherParam => $otherAttribute) {
if ($otherParam === $param) {
continue;
}
$this->assertSame(true, $response['body'][$otherAttribute], $otherAttribute . ' should be untouched while only ' . $param . ' was updated');
}
// Restore the field before the next iteration
$restore = $this->updateMembershipPrivacyPolicy([$param => true]);
$this->assertSame(200, $restore['headers']['status-code']);
$this->assertSame(true, $restore['body'][$attribute]);
}
}
public function testUpdateMembershipPrivacyPolicyMultipleFields(): void
{
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
$response = $this->updateMembershipPrivacyPolicy([
'userId' => false,
'userPhone' => false,
]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authMembershipsUserId']);
$this->assertSame(false, $response['body']['authMembershipsUserPhone']);
$this->assertSame(true, $response['body']['authMembershipsUserEmail']);
$this->assertSame(true, $response['body']['authMembershipsUserName']);
$this->assertSame(true, $response['body']['authMembershipsMfa']);
// Cleanup
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
}
public function testUpdateMembershipPrivacyPolicyEmptyBody(): void
{
// PATCH with no fields should be a no-op, leaving state unchanged
$this->updateMembershipPrivacyPolicy([
'userId' => false,
'userEmail' => false,
'userPhone' => false,
'userName' => false,
'userMFA' => false,
]);
$response = $this->updateMembershipPrivacyPolicy([]);
$this->assertSame(200, $response['headers']['status-code']);
$this->assertSame(false, $response['body']['authMembershipsUserId']);
$this->assertSame(false, $response['body']['authMembershipsUserEmail']);
$this->assertSame(false, $response['body']['authMembershipsUserPhone']);
$this->assertSame(false, $response['body']['authMembershipsUserName']);
$this->assertSame(false, $response['body']['authMembershipsMfa']);
// Cleanup
$this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
]);
}
public function testUpdateMembershipPrivacyPolicyInvalidType(): void
{
$response = $this->client->call(Client::METHOD_PATCH, '/project/policies/membership-privacy', $this->buildHeaders(), [
'userId' => 'not-a-boolean',
]);
$this->assertSame(400, $response['headers']['status-code']);
}
public function testUpdateMembershipPrivacyPolicyWithoutAuth(): void
{
$response = $this->updateMembershipPrivacyPolicy([
'userId' => true,
'userEmail' => true,
'userPhone' => true,
'userName' => true,
'userMFA' => true,
], false);
$this->assertSame(401, $response['headers']['status-code']);
}
// =========================================================================
// Helpers
// =========================================================================
protected function buildHeaders(bool $authenticated = true): array
{
$headers = [
'content-type' => 'application/json',
'x-appwrite-project' => $this->getProject()['$id'],
];
if ($authenticated) {
$headers = array_merge($headers, $this->getHeaders(), [
'x-appwrite-response-format' => '1.9.4',
]);
}
return $headers;
}
protected function getProjectDocument(): array
{
return $this->client->call(Client::METHOD_GET, '/projects/' . $this->getProject()['$id'], [
'content-type' => 'application/json',
'x-appwrite-project' => 'console',
'cookie' => 'a_session_console=' . $this->getRoot()['session'],
'x-appwrite-response-format' => '1.9.4',
]);
}
protected function listPolicies(?array $queries = null, ?bool $total = null, bool $authenticated = true): mixed
{
$params = [];
if ($queries !== null) {
$params['queries'] = $queries;
}
if ($total !== null) {
$params['total'] = $total;
}
return $this->client->call(Client::METHOD_GET, '/project/policies', $this->buildHeaders($authenticated), $params);
}
protected function getPolicy(string $policyId, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_GET, '/project/policies/' . $policyId, $this->buildHeaders($authenticated));
}
protected function updatePasswordDictionaryPolicy(bool $enabled, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/password-dictionary', $this->buildHeaders($authenticated), [
'enabled' => $enabled,
]);
}
protected function updatePasswordHistoryPolicy(?int $total, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/password-history', $this->buildHeaders($authenticated), [
'total' => $total,
]);
}
protected function updatePasswordPersonalDataPolicy(bool $enabled, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/password-personal-data', $this->buildHeaders($authenticated), [
'enabled' => $enabled,
]);
}
protected function updateSessionAlertPolicy(bool $enabled, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/session-alert', $this->buildHeaders($authenticated), [
'enabled' => $enabled,
]);
}
protected function updateSessionDurationPolicy(int $duration, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/session-duration', $this->buildHeaders($authenticated), [
'duration' => $duration,
]);
}
protected function updateSessionInvalidationPolicy(bool $enabled, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/session-invalidation', $this->buildHeaders($authenticated), [
'enabled' => $enabled,
]);
}
protected function updateSessionLimitPolicy(?int $total, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/session-limit', $this->buildHeaders($authenticated), [
'total' => $total,
]);
}
protected function updateUserLimitPolicy(?int $total, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/user-limit', $this->buildHeaders($authenticated), [
'total' => $total,
]);
}
/**
* @param array<string, bool> $params
*/
protected function updateMembershipPrivacyPolicy(array $params, bool $authenticated = true): mixed
{
return $this->client->call(Client::METHOD_PATCH, '/project/policies/membership-privacy', $this->buildHeaders($authenticated), $params);
}
}