Implement Variable Session Duration
This commit is contained in:
parent
1b0abf4643
commit
d34359fd49
14 changed files with 58 additions and 20 deletions
|
@ -633,6 +633,17 @@ $collections = [
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'filters' => [],
|
'filters' => [],
|
||||||
],
|
],
|
||||||
|
[
|
||||||
|
'$id' => ID::custom('sessionDuration'),
|
||||||
|
'type' => Database::VAR_INTEGER,
|
||||||
|
'format' => '',
|
||||||
|
'size' => 32,
|
||||||
|
'signed' => true,
|
||||||
|
'required' => false,
|
||||||
|
'default' => 525600, // 1 Year
|
||||||
|
'array' => false,
|
||||||
|
'filters' => [],
|
||||||
|
],
|
||||||
[
|
[
|
||||||
'$id' => ID::custom('services'),
|
'$id' => ID::custom('services'),
|
||||||
'type' => Database::VAR_STRING,
|
'type' => Database::VAR_STRING,
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -165,10 +165,11 @@ App::post('/v1/account/sessions/email')
|
||||||
->inject('request')
|
->inject('request')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('project')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->action(function (string $email, string $password, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Event $events) {
|
->action(function (string $email, string $password, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) {
|
||||||
|
|
||||||
$email = \strtolower($email);
|
$email = \strtolower($email);
|
||||||
$protocol = $request->getProtocol();
|
$protocol = $request->getProtocol();
|
||||||
|
@ -185,9 +186,11 @@ App::post('/v1/account/sessions/email')
|
||||||
throw new Exception(Exception::USER_BLOCKED); // User is in status blocked
|
throw new Exception(Exception::USER_BLOCKED); // User is in status blocked
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sessionDuration = ($project->getAttribute('sessionDuration', null) * 60) ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||||
|
|
||||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||||
$record = $geodb->get($request->getIP());
|
$record = $geodb->get($request->getIP());
|
||||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
$expire = DateTime::addSeconds(new \DateTime(), $sessionDuration);
|
||||||
$secret = Auth::tokenGenerator();
|
$secret = Auth::tokenGenerator();
|
||||||
$session = new Document(array_merge(
|
$session = new Document(array_merge(
|
||||||
[
|
[
|
||||||
|
@ -525,10 +528,11 @@ App::get('/v1/account/sessions/oauth2/:provider/redirect')
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create session token, verify user account and update OAuth2 ID and Access Token
|
// Create session token, verify user account and update OAuth2 ID and Access Token
|
||||||
|
$sessionDuration = ($project->getAttribute('sessionDuration', null) * 60) ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||||
$record = $geodb->get($request->getIP());
|
$record = $geodb->get($request->getIP());
|
||||||
$secret = Auth::tokenGenerator();
|
$secret = Auth::tokenGenerator();
|
||||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
$expire = DateTime::addSeconds(new \DateTime(), $sessionDuration);
|
||||||
|
|
||||||
$session = new Document(array_merge([
|
$session = new Document(array_merge([
|
||||||
'$id' => ID::unique(),
|
'$id' => ID::unique(),
|
||||||
|
@ -759,10 +763,11 @@ App::put('/v1/account/sessions/magic-url')
|
||||||
->inject('request')
|
->inject('request')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('project')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Event $events) {
|
->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) {
|
||||||
|
|
||||||
/** @var Utopia\Database\Document $user */
|
/** @var Utopia\Database\Document $user */
|
||||||
|
|
||||||
|
@ -778,10 +783,11 @@ App::put('/v1/account/sessions/magic-url')
|
||||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sessionDuration = ($project->getAttribute('sessionDuration', null) * 60) ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||||
$record = $geodb->get($request->getIP());
|
$record = $geodb->get($request->getIP());
|
||||||
$secret = Auth::tokenGenerator();
|
$secret = Auth::tokenGenerator();
|
||||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
$expire = DateTime::addSeconds(new \DateTime(), $sessionDuration);
|
||||||
|
|
||||||
$session = new Document(array_merge(
|
$session = new Document(array_merge(
|
||||||
[
|
[
|
||||||
|
@ -996,10 +1002,11 @@ App::put('/v1/account/sessions/phone')
|
||||||
->inject('request')
|
->inject('request')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('project')
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Locale $locale, Reader $geodb, Event $events) {
|
->action(function (string $userId, string $secret, Request $request, Response $response, Database $dbForProject, Document $project, Locale $locale, Reader $geodb, Event $events) {
|
||||||
|
|
||||||
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
|
$user = Authorization::skip(fn() => $dbForProject->getDocument('users', $userId));
|
||||||
|
|
||||||
|
@ -1013,10 +1020,11 @@ App::put('/v1/account/sessions/phone')
|
||||||
throw new Exception(Exception::USER_INVALID_TOKEN);
|
throw new Exception(Exception::USER_INVALID_TOKEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$sessionDuration = ($project->getAttribute('sessionDuration', null) * 60) ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||||
$record = $geodb->get($request->getIP());
|
$record = $geodb->get($request->getIP());
|
||||||
$secret = Auth::tokenGenerator();
|
$secret = Auth::tokenGenerator();
|
||||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
$expire = DateTime::addSeconds(new \DateTime(), $sessionDuration);
|
||||||
|
|
||||||
$session = new Document(array_merge(
|
$session = new Document(array_merge(
|
||||||
[
|
[
|
||||||
|
@ -1164,11 +1172,11 @@ App::post('/v1/account/sessions/anonymous')
|
||||||
])));
|
])));
|
||||||
|
|
||||||
// Create session token
|
// Create session token
|
||||||
|
$sessionDuration = ($project->getAttribute('sessionDuration', null) * 60) ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||||
$record = $geodb->get($request->getIP());
|
$record = $geodb->get($request->getIP());
|
||||||
$secret = Auth::tokenGenerator();
|
$secret = Auth::tokenGenerator();
|
||||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
$expire = DateTime::addSeconds(new \DateTime(), $sessionDuration);
|
||||||
|
|
||||||
$session = new Document(array_merge(
|
$session = new Document(array_merge(
|
||||||
[
|
[
|
||||||
|
|
|
@ -32,6 +32,7 @@ use Appwrite\Utopia\Database\Validator\Queries\Projects;
|
||||||
use Utopia\Validator\ArrayList;
|
use Utopia\Validator\ArrayList;
|
||||||
use Utopia\Validator\Boolean;
|
use Utopia\Validator\Boolean;
|
||||||
use Utopia\Validator\Hostname;
|
use Utopia\Validator\Hostname;
|
||||||
|
use Utopia\Validator\Integer;
|
||||||
use Utopia\Validator\Range;
|
use Utopia\Validator\Range;
|
||||||
use Utopia\Validator\Text;
|
use Utopia\Validator\Text;
|
||||||
use Utopia\Validator\WhiteList;
|
use Utopia\Validator\WhiteList;
|
||||||
|
@ -67,10 +68,11 @@ App::post('/v1/projects')
|
||||||
->param('legalCity', '', new Text(256), 'Project legal City. Max length: 256 chars.', true)
|
->param('legalCity', '', new Text(256), 'Project legal City. Max length: 256 chars.', true)
|
||||||
->param('legalAddress', '', new Text(256), 'Project legal Address. Max length: 256 chars.', true)
|
->param('legalAddress', '', new Text(256), 'Project legal Address. Max length: 256 chars.', true)
|
||||||
->param('legalTaxId', '', new Text(256), 'Project legal Tax ID. Max length: 256 chars.', true)
|
->param('legalTaxId', '', new Text(256), 'Project legal Tax ID. Max length: 256 chars.', true)
|
||||||
|
->param('sessionDuration', 525600, new Integer(), 'Session duration in minutes. Defaults to 1 year', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForConsole')
|
->inject('dbForConsole')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
->action(function (string $projectId, string $name, string $teamId, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole, Database $dbForProject) {
|
->action(function (string $projectId, string $name, string $teamId, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, int $sessionDuration, Response $response, Database $dbForConsole, Database $dbForProject) {
|
||||||
|
|
||||||
$team = $dbForConsole->getDocument('teams', $teamId);
|
$team = $dbForConsole->getDocument('teams', $teamId);
|
||||||
|
|
||||||
|
@ -112,6 +114,7 @@ App::post('/v1/projects')
|
||||||
'legalCity' => $legalCity,
|
'legalCity' => $legalCity,
|
||||||
'legalAddress' => $legalAddress,
|
'legalAddress' => $legalAddress,
|
||||||
'legalTaxId' => ID::custom($legalTaxId),
|
'legalTaxId' => ID::custom($legalTaxId),
|
||||||
|
'sessionDuration' => $sessionDuration,
|
||||||
'services' => new stdClass(),
|
'services' => new stdClass(),
|
||||||
'platforms' => null,
|
'platforms' => null,
|
||||||
'authProviders' => [],
|
'authProviders' => [],
|
||||||
|
@ -374,9 +377,10 @@ App::patch('/v1/projects/:projectId')
|
||||||
->param('legalCity', '', new Text(256), 'Project legal city. Max length: 256 chars.', true)
|
->param('legalCity', '', new Text(256), 'Project legal city. Max length: 256 chars.', true)
|
||||||
->param('legalAddress', '', new Text(256), 'Project legal address. Max length: 256 chars.', true)
|
->param('legalAddress', '', new Text(256), 'Project legal address. Max length: 256 chars.', true)
|
||||||
->param('legalTaxId', '', new Text(256), 'Project legal tax ID. Max length: 256 chars.', true)
|
->param('legalTaxId', '', new Text(256), 'Project legal tax ID. Max length: 256 chars.', true)
|
||||||
|
->param('sessionDuration', null, new Integer(true), 'Project session length in minutes. Max length: 525600 minutes.', true)
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('dbForConsole')
|
->inject('dbForConsole')
|
||||||
->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, Response $response, Database $dbForConsole) {
|
->action(function (string $projectId, string $name, string $description, string $logo, string $url, string $legalName, string $legalCountry, string $legalState, string $legalCity, string $legalAddress, string $legalTaxId, int $sessionDuration, Response $response, Database $dbForConsole) {
|
||||||
|
|
||||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||||
|
|
||||||
|
@ -384,6 +388,10 @@ App::patch('/v1/projects/:projectId')
|
||||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($sessionDuration < 0 || $sessionDuration > 525600) {
|
||||||
|
throw new Exception('Session length must be between 0 and 525600 minutes');
|
||||||
|
}
|
||||||
|
|
||||||
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
|
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
|
||||||
->setAttribute('name', $name)
|
->setAttribute('name', $name)
|
||||||
->setAttribute('description', $description)
|
->setAttribute('description', $description)
|
||||||
|
@ -395,6 +403,7 @@ App::patch('/v1/projects/:projectId')
|
||||||
->setAttribute('legalCity', $legalCity)
|
->setAttribute('legalCity', $legalCity)
|
||||||
->setAttribute('legalAddress', $legalAddress)
|
->setAttribute('legalAddress', $legalAddress)
|
||||||
->setAttribute('legalTaxId', $legalTaxId)
|
->setAttribute('legalTaxId', $legalTaxId)
|
||||||
|
->setAttribute('sessionDuration', $sessionDuration)
|
||||||
->setAttribute('search', implode(' ', [$projectId, $name])));
|
->setAttribute('search', implode(' ', [$projectId, $name])));
|
||||||
|
|
||||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
$response->dynamic($project, Response::MODEL_PROJECT);
|
||||||
|
|
|
@ -677,9 +677,10 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||||
->inject('response')
|
->inject('response')
|
||||||
->inject('user')
|
->inject('user')
|
||||||
->inject('dbForProject')
|
->inject('dbForProject')
|
||||||
|
->inject('project')
|
||||||
->inject('geodb')
|
->inject('geodb')
|
||||||
->inject('events')
|
->inject('events')
|
||||||
->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Reader $geodb, Event $events) {
|
->action(function (string $teamId, string $membershipId, string $userId, string $secret, Request $request, Response $response, Document $user, Database $dbForProject, Document $project, Reader $geodb, Event $events) {
|
||||||
$protocol = $request->getProtocol();
|
$protocol = $request->getProtocol();
|
||||||
|
|
||||||
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
$membership = $dbForProject->getDocument('memberships', $membershipId);
|
||||||
|
@ -731,7 +732,8 @@ App::patch('/v1/teams/:teamId/memberships/:membershipId/status')
|
||||||
|
|
||||||
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
$detector = new Detector($request->getUserAgent('UNKNOWN'));
|
||||||
$record = $geodb->get($request->getIP());
|
$record = $geodb->get($request->getIP());
|
||||||
$expire = DateTime::addSeconds(new \DateTime(), Auth::TOKEN_EXPIRATION_LOGIN_LONG);
|
$sessionDuration = ($project->getAttribute('sessionDuration', null) * 60) ?? Auth::TOKEN_EXPIRATION_LOGIN_LONG;
|
||||||
|
$expire = DateTime::addSeconds(new \DateTime(), $sessionDuration);
|
||||||
$secret = Auth::tokenGenerator();
|
$secret = Auth::tokenGenerator();
|
||||||
$session = new Document(array_merge([
|
$session = new Document(array_merge([
|
||||||
'$id' => ID::unique(),
|
'$id' => ID::unique(),
|
||||||
|
|
|
@ -917,6 +917,7 @@ App::setResource('console', function () {
|
||||||
'legalCity' => '',
|
'legalCity' => '',
|
||||||
'legalAddress' => '',
|
'legalAddress' => '',
|
||||||
'legalTaxId' => '',
|
'legalTaxId' => '',
|
||||||
|
'sessionDuration' => 525600, // 1 Year in minutes
|
||||||
'auths' => [
|
'auths' => [
|
||||||
'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
'limit' => (App::getEnv('_APP_CONSOLE_WHITELIST_ROOT', 'enabled') === 'enabled') ? 1 : 0, // limit signup to 1 user
|
||||||
],
|
],
|
||||||
|
|
|
@ -99,7 +99,7 @@ $cli
|
||||||
{
|
{
|
||||||
(new Delete())
|
(new Delete())
|
||||||
->setType(DELETE_TYPE_SESSIONS)
|
->setType(DELETE_TYPE_SESSIONS)
|
||||||
->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * Auth::TOKEN_EXPIRATION_LOGIN_LONG))
|
->setDatetime(DateTime::addSeconds(new \DateTime(), -1 * Auth::TOKEN_EXPIRATION_LOGIN_LONG)) //TODO: Update to use project session expiration instead of default.
|
||||||
->trigger();
|
->trigger();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -101,6 +101,12 @@ class Project extends Model
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'example' => '131102020',
|
'example' => '131102020',
|
||||||
])
|
])
|
||||||
|
->addRule('sessionDuration', [
|
||||||
|
'type' => self::TYPE_STRING,
|
||||||
|
'description' => 'Session duration in minutes.',
|
||||||
|
'default' => '',
|
||||||
|
'example' => '30',
|
||||||
|
])
|
||||||
->addRule('authLimit', [
|
->addRule('authLimit', [
|
||||||
'type' => self::TYPE_INTEGER,
|
'type' => self::TYPE_INTEGER,
|
||||||
'description' => 'Max users allowed. 0 is unlimited.',
|
'description' => 'Max users allowed. 0 is unlimited.',
|
||||||
|
|
|
@ -53,6 +53,7 @@ trait ProjectCustom
|
||||||
'legalCity' => '',
|
'legalCity' => '',
|
||||||
'legalAddress' => '',
|
'legalAddress' => '',
|
||||||
'legalTaxId' => '',
|
'legalTaxId' => '',
|
||||||
|
'sessionDuration' => 525600
|
||||||
]);
|
]);
|
||||||
|
|
||||||
$this->assertEquals(201, $project['headers']['status-code']);
|
$this->assertEquals(201, $project['headers']['status-code']);
|
||||||
|
|
Loading…
Reference in a new issue