Move some of auth settings to project policies

This commit is contained in:
Matej Bačo
2026-04-21 13:11:42 +02:00
parent 7568964b7c
commit 4317ee5617
10 changed files with 565 additions and 268 deletions
-265
View File
@@ -218,82 +218,6 @@ Http::patch('/v1/projects/:projectId/auth/memberships-privacy')
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/limit')
->desc('Update project users limit')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updateAuthLimit',
description: '/docs/references/projects/update-auth-limit.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('limit', false, new Range(0, APP_LIMIT_USERS), 'Set the max number of users allowed in this project. Use 0 for unlimited.')
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, int $limit, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['limit'] = $limit;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/duration')
->desc('Update project authentication duration')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updateAuthDuration',
description: '/docs/references/projects/update-auth-duration.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('duration', 31536000, new Range(0, 31536000), 'Project session length in seconds. Max length: 31536000 seconds.')
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, int $duration, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['duration'] = $duration;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/:method')
->desc('Update project auth method status. Use this endpoint to enable or disable a given auth method for this project.')
->groups(['api', 'projects'])
@@ -335,158 +259,6 @@ Http::patch('/v1/projects/:projectId/auth/:method')
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/password-history')
->desc('Update authentication password history. Use this endpoint to set the number of password history to save and 0 to disable password history.')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updateAuthPasswordHistory',
description: '/docs/references/projects/update-auth-password-history.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('limit', 0, new Range(0, APP_LIMIT_USER_PASSWORD_HISTORY), 'Set the max number of passwords to store in user history. User can\'t choose a new password that is already stored in the password history list. Max number of passwords allowed in history is' . APP_LIMIT_USER_PASSWORD_HISTORY . '. Default value is 0')
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, int $limit, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['passwordHistory'] = $limit;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/password-dictionary')
->desc('Update authentication password dictionary status. Use this endpoint to enable or disable the dicitonary check for user password')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updateAuthPasswordDictionary',
description: '/docs/references/projects/update-auth-password-dictionary.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('enabled', false, new Boolean(false), 'Set whether or not to enable checking user\'s password against most commonly used passwords. Default is false.')
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['passwordDictionary'] = $enabled;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/personal-data')
->desc('Update personal data check')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updatePersonalDataCheck',
description: '/docs/references/projects/update-personal-data-check.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('enabled', false, new Boolean(false), 'Set whether or not to check a password for similarity with personal data. Default is false.')
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['personalDataCheck'] = $enabled;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/max-sessions')
->desc('Update project user sessions limit')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updateAuthSessionsLimit',
description: '/docs/references/projects/update-auth-sessions-limit.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('limit', false, new Range(1, APP_LIMIT_USER_SESSIONS_MAX), 'Set the max number of users allowed in this project. Value allowed is between 1-' . APP_LIMIT_USER_SESSIONS_MAX . '. Default is ' . APP_LIMIT_USER_SESSIONS_DEFAULT)
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, int $limit, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['maxSessions'] = $limit;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
Http::patch('/v1/projects/:projectId/auth/mock-numbers')
->desc('Update the mock numbers for the project')
->groups(['api', 'projects'])
@@ -1050,40 +822,3 @@ Http::delete('/v1/projects/:projectId/templates/email')
'message' => $template['message']
]), Response::MODEL_EMAIL_TEMPLATE);
});
Http::patch('/v1/projects/:projectId/auth/session-invalidation')
->desc('Update invalidate session option of the project')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk', new Method(
namespace: 'projects',
group: 'auth',
name: 'updateSessionInvalidation',
description: '/docs/references/projects/update-session-invalidation.md',
auth: [AuthType::ADMIN],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
]
))
->param('projectId', '', fn (Database $dbForPlatform) => new UID($dbForPlatform->getAdapter()->getMaxUIDLength()), 'Project unique ID.', false, ['dbForPlatform'])
->param('enabled', false, new Boolean(), 'Update authentication session invalidation status. Use this endpoint to enable or disable session invalidation on password change')
->inject('response')
->inject('dbForPlatform')
->action(function (string $projectId, bool $enabled, Response $response, Database $dbForPlatform) {
$project = $dbForPlatform->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$auths = $project->getAttribute('auths', []);
$auths['invalidateSessions'] = $enabled;
$dbForPlatform->updateDocument('projects', $project->getId(), $project
->setAttribute('auths', $auths));
$response->dynamic($project, Response::MODEL_PROJECT);
});
-2
View File
@@ -24,8 +24,6 @@ const APP_MODE_ADMIN = 'admin';
const APP_PAGING_LIMIT = 12;
const APP_LIMIT_COUNT = 5000;
const APP_LIMIT_USERS = 10_000;
const APP_LIMIT_USER_PASSWORD_HISTORY = 20;
const APP_LIMIT_USER_SESSIONS_MAX = 100;
const APP_LIMIT_USER_SESSIONS_DEFAULT = 10;
const APP_LIMIT_ANTIVIRUS = 20_000_000; //20MB
const APP_LIMIT_ENCRYPTION = 20_000_000; //20MB
@@ -0,0 +1,78 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\PasswordDictionary;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Boolean;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectPasswordDictionaryPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/password-dictionary')
->httpAlias('/v1/projects/:projectId/auth/password-dictionary')
->desc('Update password dictionary policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.password-dictionary.update')
->label('audits.event', 'policies.password-dictionary.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updatePasswordDictionaryPolicy',
description: <<<EOT
Updating this policy allows you to control if new passwords are checked against most common passwords dictionary. When enabled, and user changes their password, password must not be contained in the dictionary.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('enabled', null, new Boolean(), 'Toggle password dictionary policy. Set to true if you want password change to block passwords in the dictionary, or false to allow them. When changing this policy, existing passwords remain valid.')
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
bool $enabled,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
$auths['passwordDictionary'] = $enabled;
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -0,0 +1,84 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\PasswordHistory;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
use Utopia\Validator\Range;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectPasswordHistoryPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/password-history')
->httpAlias('/v1/projects/:projectId/auth/password-history')
->desc('Update password history policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.password-history.update')
->label('audits.event', 'policies.password-history.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updatePasswordHistoryPolicy',
description: <<<EOT
Updates one of password strength policies. Based on total length configured, previous password hashes are stored, and users cannot choose a new password that is already stored in the passwird history list, when updating an user password, or setting new one through password recovery.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('total', null, new Nullable(new Range(1, APP_LIMIT_COUNT), 'Set the password history length per user. Value can be between 1 and ' . APP_LIMIT_COUNT . ', or null to disable the limit.'))
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
int $total,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
if (\is_null($total)) {
$auths['passwordHistory'] = 0;
} else {
$auths['passwordHistory'] = $total;
}
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -0,0 +1,78 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\PasswordPersonalData;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Boolean;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectPasswordPersonalDataPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/password-personal-data')
->httpAlias('/v1/projects/:projectId/auth/personal-data')
->desc('Update password personal data policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.password-personal-data.update')
->label('audits.event', 'policies.password-personal-data.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updatePasswordPersonalDataPolicy',
description: <<<EOT
Updating this policy allows you to control if password strength is checked against personal data. When enabled, and user sets or changes their password, the password must not contain user ID, name, email or phone number.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('enabled', null, new Boolean(), 'Toggle password personal data policy. Set to true if you want to block passwords including user\'s personal data, or false to allow it. When changing this policy, existing passwords remain valid.')
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
bool $enabled,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
$auths['personalDataCheck'] = $enabled;
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -0,0 +1,78 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\SessionDuration;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Range;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectSessionDurationPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/session-duration')
->httpAlias('/v1/projects/:projectId/auth/duration')
->desc('Update session duration policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.session-duration.update')
->label('audits.event', 'policies.session-duration.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updateSessionDurationPolicy',
description: <<<EOT
Update maximum duration how long sessions created within a project should stay active for.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('duration', null, new Range(60, 31536000), 'Maximum session length in seconds. Minium allowed value is 60 seconds, and maximum is 1 year, which is 31536000 seconds.')
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
int $duration,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
$auths['duration'] = $duration;
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -0,0 +1,78 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\SessionInvalidation;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Boolean;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectSessionInvalidationPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/session-invalidation')
->httpAlias('/v1/projects/:projectId/auth/session-invalidation')
->desc('Update session invalidation policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.session-invalidation.update')
->label('audits.event', 'policies.session-invalidation.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updateSessionInvalidationPolicy',
description: <<<EOT
Updating this policy allows you to control if existing sessions should be invalidated when a password of a user is changed. When enabled, and user changes their password, they will be logged out of all their devices.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('enabled', null, new Boolean(), 'Toggle session invalidation policy. Set to true if you want password change to invalidate all sessions of an user, or false to keep sessions active.')
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
bool $enabled,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
$auths['invalidateSessions'] = $enabled;
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -0,0 +1,84 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\SessionLimit;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
use Utopia\Validator\Range;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectSessionLimitPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/session-limit')
->httpAlias('/v1/projects/:projectId/auth/max-sessions')
->desc('Update session limit policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.session-limit.update')
->label('audits.event', 'policies.session-limit.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updateSessionLimitPolicy',
description: <<<EOT
Update the maximum number of sessions allowed per user. When the limit is hit, the oldest session will be deleted to make room for new one.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('total', null, new Nullable(new Range(1, APP_LIMIT_COUNT), 'Set the maximum number of sessions allowed per user. Value can be between 1 and ' . APP_LIMIT_COUNT . ', or null to disable the limit.'))
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
int $total,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
if (\is_null($total)) {
$auths['maxSessions'] = 0;
} else {
$auths['maxSessions'] = $total;
}
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -0,0 +1,84 @@
<?php
namespace Appwrite\Platform\Modules\Project\Http\Project\Policies\UserLimit;
use Appwrite\Platform\Action;
use Appwrite\SDK\AuthType;
use Appwrite\SDK\Method;
use Appwrite\SDK\Response as SDKResponse;
use Appwrite\Utopia\Response;
use Utopia\Database\Database;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Utopia\Platform\Scope\HTTP;
use Utopia\Validator\Nullable;
use Utopia\Validator\Range;
class Update extends Action
{
use HTTP;
public static function getName()
{
return 'updateProjectUserLimitPolicy';
}
public function __construct()
{
$this
->setHttpMethod(Action::HTTP_REQUEST_METHOD_PATCH)
->setHttpPath('/v1/project/policies/user-limit')
->httpAlias('/v1/projects/:projectId/auth/limit')
->desc('Update user limit policy')
->groups(['api', 'project'])
->label('scope', 'policies.write')
->label('event', 'policies.user-limit.update')
->label('audits.event', 'policies.user-limit.update')
->label('audits.resource', 'project/{response.$id}')
->label('sdk', new Method(
namespace: 'project',
group: 'policies',
name: 'updateUserLimitPolicy',
description: <<<EOT
Update the maximum number of users in the project. When the limit is hit or amount of existing users already exceeded the limit, all users remain active, but new user sign up will be prohibited.
EOT,
auth: [AuthType::ADMIN, AuthType::KEY],
responses: [
new SDKResponse(
code: Response::STATUS_CODE_OK,
model: Response::MODEL_PROJECT,
)
],
))
->param('total', null, new Nullable(new Range(1, APP_LIMIT_COUNT), 'Set the maximum number of users allowed in the project. Value can be between 1 and ' . APP_LIMIT_COUNT . ', or null to disable the limit.'))
->inject('response')
->inject('dbForPlatform')
->inject('project')
->inject('authorization')
->callback($this->action(...));
}
public function action(
int $total,
Response $response,
Database $dbForPlatform,
Document $project,
Authorization $authorization,
): void {
$auths = $project->getAttribute('auths', []);
if (\is_null($total)) {
$auths['limit'] = 0;
} else {
$auths['limit'] = $total;
}
$updates = new Document([
'auths' => $auths,
]);
$project = $authorization->skip(fn () => $dbForPlatform->updateDocument('projects', $project->getId(), $updates));
$response->dynamic($project, Response::MODEL_PROJECT);
}
}
@@ -107,7 +107,7 @@ class Create extends Action
$auth = Config::getParam('auth', []);
$auths = [
'limit' => 0,
'maxSessions' => APP_LIMIT_USER_SESSIONS_DEFAULT,
'maxSessions' => 0,
'passwordHistory' => 0,
'passwordDictionary' => false,
'duration' => TOKEN_EXPIRATION_LOGIN_LONG,