fix: move user logic from general to api hook
This commit is contained in:
parent
ca650fce1b
commit
5193a97ddb
2 changed files with 159 additions and 158 deletions
|
@ -3,7 +3,6 @@
|
||||||
require_once __DIR__ . '/../init.php';
|
require_once __DIR__ . '/../init.php';
|
||||||
|
|
||||||
use Utopia\App;
|
use Utopia\App;
|
||||||
use Utopia\Database\Helpers\Role;
|
|
||||||
use Utopia\Locale\Locale;
|
use Utopia\Locale\Locale;
|
||||||
use Utopia\Logger\Logger;
|
use Utopia\Logger\Logger;
|
||||||
use Utopia\Logger\Log;
|
use Utopia\Logger\Log;
|
||||||
|
@ -15,7 +14,6 @@ use Appwrite\Utopia\View;
|
||||||
use Appwrite\Extend\Exception as AppwriteException;
|
use Appwrite\Extend\Exception as AppwriteException;
|
||||||
use Utopia\Config\Config;
|
use Utopia\Config\Config;
|
||||||
use Utopia\Domains\Domain;
|
use Utopia\Domains\Domain;
|
||||||
use Appwrite\Auth\Auth;
|
|
||||||
use Appwrite\Event\Certificate;
|
use Appwrite\Event\Certificate;
|
||||||
use Appwrite\Network\Validator\Origin;
|
use Appwrite\Network\Validator\Origin;
|
||||||
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
use Appwrite\Utopia\Response\Filters\V11 as ResponseV11;
|
||||||
|
@ -27,7 +25,6 @@ use Appwrite\Utopia\Response\Filters\V16 as ResponseV16;
|
||||||
use Appwrite\Utopia\Response\Filters\V17 as ResponseV17;
|
use Appwrite\Utopia\Response\Filters\V17 as ResponseV17;
|
||||||
use Utopia\CLI\Console;
|
use Utopia\CLI\Console;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Utopia\Database\DateTime;
|
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
use Utopia\Database\Query;
|
use Utopia\Database\Query;
|
||||||
use Utopia\Database\Validator\Authorization;
|
use Utopia\Database\Validator\Authorization;
|
||||||
|
@ -39,7 +36,6 @@ use Appwrite\Utopia\Request\Filters\V15 as RequestV15;
|
||||||
use Appwrite\Utopia\Request\Filters\V16 as RequestV16;
|
use Appwrite\Utopia\Request\Filters\V16 as RequestV16;
|
||||||
use Appwrite\Utopia\Request\Filters\V17 as RequestV17;
|
use Appwrite\Utopia\Request\Filters\V17 as RequestV17;
|
||||||
use Utopia\Validator\Text;
|
use Utopia\Validator\Text;
|
||||||
use Utopia\Validator\WhiteList;
|
|
||||||
|
|
||||||
Config::setParam('domainVerification', false);
|
Config::setParam('domainVerification', false);
|
||||||
Config::setParam('cookieDomain', 'localhost');
|
Config::setParam('cookieDomain', 'localhost');
|
||||||
|
@ -205,15 +201,11 @@ App::init()
|
||||||
->inject('console')
|
->inject('console')
|
||||||
->inject('project')
|
->inject('project')
|
||||||
->inject('dbForConsole')
|
->inject('dbForConsole')
|
||||||
->inject('user')
|
|
||||||
->inject('locale')
|
->inject('locale')
|
||||||
->inject('localeCodes')
|
->inject('localeCodes')
|
||||||
->inject('clients')
|
->inject('clients')
|
||||||
->inject('servers')
|
|
||||||
->inject('session')
|
|
||||||
->inject('mode')
|
|
||||||
->inject('queueForCertificates')
|
->inject('queueForCertificates')
|
||||||
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Document $user, Locale $locale, array $localeCodes, array $clients, array $servers, ?Document $session, string $mode, Certificate $queueForCertificates) {
|
->action(function (App $utopia, SwooleRequest $swooleRequest, Request $request, Response $response, Document $console, Document $project, Database $dbForConsole, Locale $locale, array $localeCodes, array $clients, Certificate $queueForCertificates) {
|
||||||
/*
|
/*
|
||||||
* Appwrite Router
|
* Appwrite Router
|
||||||
*/
|
*/
|
||||||
|
@ -453,140 +445,6 @@ App::init()
|
||||||
) {
|
) {
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_UNKNOWN_ORIGIN, $originValidator->getDescription());
|
throw new AppwriteException(AppwriteException::GENERAL_UNKNOWN_ORIGIN, $originValidator->getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* ACL Check
|
|
||||||
*/
|
|
||||||
$role = ($user->isEmpty())
|
|
||||||
? Role::guests()->toString()
|
|
||||||
: Role::users()->toString();
|
|
||||||
|
|
||||||
// Add user roles
|
|
||||||
$memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships');
|
|
||||||
|
|
||||||
if ($memberships) {
|
|
||||||
foreach ($memberships->getAttribute('roles', []) as $memberRole) {
|
|
||||||
switch ($memberRole) {
|
|
||||||
case 'owner':
|
|
||||||
$role = Auth::USER_ROLE_OWNER;
|
|
||||||
break;
|
|
||||||
case 'admin':
|
|
||||||
$role = Auth::USER_ROLE_ADMIN;
|
|
||||||
break;
|
|
||||||
case 'developer':
|
|
||||||
$role = Auth::USER_ROLE_DEVELOPER;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$roles = Config::getParam('roles', []);
|
|
||||||
$scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route
|
|
||||||
$scopes = $roles[$role]['scopes']; // Allowed scopes for user role
|
|
||||||
|
|
||||||
$authKey = $request->getHeader('x-appwrite-key', '');
|
|
||||||
|
|
||||||
if (!empty($authKey)) { // API Key authentication
|
|
||||||
// Check if given key match project API keys
|
|
||||||
$key = $project->find('secret', $authKey, 'keys');
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Try app auth when we have project key and no user
|
|
||||||
* Mock user to app and grant API key scopes in addition to default app scopes
|
|
||||||
*/
|
|
||||||
if ($key && $user->isEmpty()) {
|
|
||||||
$user = new Document([
|
|
||||||
'$id' => '',
|
|
||||||
'status' => true,
|
|
||||||
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
|
|
||||||
'password' => '',
|
|
||||||
'name' => $project->getAttribute('name', 'Untitled'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
$role = Auth::USER_ROLE_APPS;
|
|
||||||
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
|
|
||||||
|
|
||||||
$expire = $key->getAttribute('expire');
|
|
||||||
if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
|
|
||||||
throw new AppwriteException(AppwriteException::PROJECT_KEY_EXPIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
Authorization::setRole(Auth::USER_ROLE_APPS);
|
|
||||||
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
|
||||||
|
|
||||||
$accessedAt = $key->getAttribute('accessedAt', '');
|
|
||||||
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCCESS)) > $accessedAt) {
|
|
||||||
$key->setAttribute('accessedAt', DateTime::now());
|
|
||||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
|
||||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
|
||||||
}
|
|
||||||
|
|
||||||
$sdkValidator = new WhiteList($servers, true);
|
|
||||||
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
|
|
||||||
if ($sdkValidator->isValid($sdk)) {
|
|
||||||
$sdks = $key->getAttribute('sdks', []);
|
|
||||||
if (!in_array($sdk, $sdks)) {
|
|
||||||
array_push($sdks, $sdk);
|
|
||||||
$key->setAttribute('sdks', $sdks);
|
|
||||||
|
|
||||||
/** Update access time as well */
|
|
||||||
$key->setAttribute('accessedAt', Datetime::now());
|
|
||||||
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
|
||||||
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Authorization::setRole($role);
|
|
||||||
|
|
||||||
foreach (Auth::getRoles($user) as $authRole) {
|
|
||||||
Authorization::setRole($authRole);
|
|
||||||
}
|
|
||||||
|
|
||||||
$service = $route->getLabel('sdk.namespace', '');
|
|
||||||
if (!empty($service)) {
|
|
||||||
if (
|
|
||||||
array_key_exists($service, $project->getAttribute('services', []))
|
|
||||||
&& !$project->getAttribute('services', [])[$service]
|
|
||||||
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
|
||||||
) {
|
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_SERVICE_DISABLED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!\in_array($scope, $scopes)) {
|
|
||||||
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
|
||||||
throw new AppwriteException(AppwriteException::PROJECT_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new AppwriteException(AppwriteException::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')');
|
|
||||||
}
|
|
||||||
|
|
||||||
if (in_array('api', $route->getGroups())) {
|
|
||||||
if (false === $user->getAttribute('status')) { // Account is blocked
|
|
||||||
throw new AppwriteException(AppwriteException::USER_BLOCKED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($user->getAttribute('reset')) {
|
|
||||||
throw new AppwriteException(AppwriteException::USER_PASSWORD_RESET_REQUIRED);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($mode !== APP_MODE_ADMIN) {
|
|
||||||
$mfaEnabled = $user->getAttribute('mfa', false);
|
|
||||||
$hasVerifiedAuthenticator = $user->getAttribute('totpVerification', false);
|
|
||||||
$hasVerifiedEmail = $user->getAttribute('emailVerification', false);
|
|
||||||
$hasVerifiedPhone = $user->getAttribute('phoneVerification', false);
|
|
||||||
$hasMoreFactors = $hasVerifiedEmail || $hasVerifiedPhone || $hasVerifiedAuthenticator;
|
|
||||||
$minimumFactors = ($mfaEnabled && $hasMoreFactors) ? 2 : 1;
|
|
||||||
|
|
||||||
if (!in_array('mfa', $route->getGroups())) {
|
|
||||||
if ($session && \count($session->getAttribute('factors')) < $minimumFactors) {
|
|
||||||
throw new AppwriteException(AppwriteException::USER_MORE_FACTORS_REQUIRED);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
App::options()
|
App::options()
|
||||||
|
|
|
@ -6,7 +6,6 @@ use Appwrite\Event\Database as EventDatabase;
|
||||||
use Appwrite\Event\Delete;
|
use Appwrite\Event\Delete;
|
||||||
use Appwrite\Event\Event;
|
use Appwrite\Event\Event;
|
||||||
use Appwrite\Event\Func;
|
use Appwrite\Event\Func;
|
||||||
use Appwrite\Event\Mail;
|
|
||||||
use Appwrite\Event\Messaging;
|
use Appwrite\Event\Messaging;
|
||||||
use Appwrite\Extend\Exception;
|
use Appwrite\Extend\Exception;
|
||||||
use Appwrite\Event\Usage;
|
use Appwrite\Event\Usage;
|
||||||
|
@ -22,7 +21,9 @@ use Utopia\Database\Database;
|
||||||
use Utopia\Database\DateTime;
|
use Utopia\Database\DateTime;
|
||||||
use Utopia\Database\Document;
|
use Utopia\Database\Document;
|
||||||
use Utopia\Database\Validator\Authorization;
|
use Utopia\Database\Validator\Authorization;
|
||||||
use MaxMind\Db\Reader;
|
use Utopia\Config\Config;
|
||||||
|
use Utopia\Database\Helpers\Role;
|
||||||
|
use Utopia\Validator\WhiteList;
|
||||||
|
|
||||||
$parseLabel = function (string $label, array $responsePayload, array $requestParams, Document $user) {
|
$parseLabel = function (string $label, array $responsePayload, array $requestParams, Document $user) {
|
||||||
preg_match_all('/{(.*?)}/', $label, $matches);
|
preg_match_all('/{(.*?)}/', $label, $matches);
|
||||||
|
@ -135,7 +136,7 @@ $databaseListener = function (string $event, Document $document, Document $proje
|
||||||
$queueForUsage
|
$queueForUsage
|
||||||
->addMetric(METRIC_DEPLOYMENTS, $value) // per project
|
->addMetric(METRIC_DEPLOYMENTS, $value) // per project
|
||||||
->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project
|
->addMetric(METRIC_DEPLOYMENTS_STORAGE, $document->getAttribute('size') * $value) // per project
|
||||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value)// per function
|
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS), $value) // per function
|
||||||
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);
|
->addMetric(str_replace(['{resourceType}', '{resourceInternalId}'], [$document->getAttribute('resourceType'), $document->getAttribute('resourceInternalId')], METRIC_FUNCTION_ID_DEPLOYMENTS_STORAGE), $document->getAttribute('size') * $value);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -143,6 +144,151 @@ $databaseListener = function (string $event, Document $document, Document $proje
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
App::init()
|
||||||
|
->groups(['api'])
|
||||||
|
->inject('utopia')
|
||||||
|
->inject('request')
|
||||||
|
->inject('dbForConsole')
|
||||||
|
->inject('project')
|
||||||
|
->inject('user')
|
||||||
|
->inject('session')
|
||||||
|
->inject('servers')
|
||||||
|
->inject('mode')
|
||||||
|
->action(function (App $utopia, Request $request, Database $dbForConsole, Document $project, Document $user, ?Document $session, array $servers, string $mode) {
|
||||||
|
$route = $utopia->getRoute();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ACL Check
|
||||||
|
*/
|
||||||
|
$role = ($user->isEmpty())
|
||||||
|
? Role::guests()->toString()
|
||||||
|
: Role::users()->toString();
|
||||||
|
|
||||||
|
// Add user roles
|
||||||
|
$memberships = $user->find('teamId', $project->getAttribute('teamId'), 'memberships');
|
||||||
|
|
||||||
|
if ($memberships) {
|
||||||
|
foreach ($memberships->getAttribute('roles', []) as $memberRole) {
|
||||||
|
switch ($memberRole) {
|
||||||
|
case 'owner':
|
||||||
|
$role = Auth::USER_ROLE_OWNER;
|
||||||
|
break;
|
||||||
|
case 'admin':
|
||||||
|
$role = Auth::USER_ROLE_ADMIN;
|
||||||
|
break;
|
||||||
|
case 'developer':
|
||||||
|
$role = Auth::USER_ROLE_DEVELOPER;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$roles = Config::getParam('roles', []);
|
||||||
|
$scope = $route->getLabel('scope', 'none'); // Allowed scope for chosen route
|
||||||
|
$scopes = $roles[$role]['scopes']; // Allowed scopes for user role
|
||||||
|
|
||||||
|
$authKey = $request->getHeader('x-appwrite-key', '');
|
||||||
|
|
||||||
|
if (!empty($authKey)) { // API Key authentication
|
||||||
|
// Check if given key match project API keys
|
||||||
|
$key = $project->find('secret', $authKey, 'keys');
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Try app auth when we have project key and no user
|
||||||
|
* Mock user to app and grant API key scopes in addition to default app scopes
|
||||||
|
*/
|
||||||
|
if ($key && $user->isEmpty()) {
|
||||||
|
$user = new Document([
|
||||||
|
'$id' => '',
|
||||||
|
'status' => true,
|
||||||
|
'email' => 'app.' . $project->getId() . '@service.' . $request->getHostname(),
|
||||||
|
'password' => '',
|
||||||
|
'name' => $project->getAttribute('name', 'Untitled'),
|
||||||
|
]);
|
||||||
|
|
||||||
|
$role = Auth::USER_ROLE_APPS;
|
||||||
|
$scopes = \array_merge($roles[$role]['scopes'], $key->getAttribute('scopes', []));
|
||||||
|
|
||||||
|
$expire = $key->getAttribute('expire');
|
||||||
|
if (!empty($expire) && $expire < DateTime::formatTz(DateTime::now())) {
|
||||||
|
throw new Exception(Exception::PROJECT_KEY_EXPIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
Authorization::setRole(Auth::USER_ROLE_APPS);
|
||||||
|
Authorization::setDefaultStatus(false); // Cancel security segmentation for API keys.
|
||||||
|
|
||||||
|
$accessedAt = $key->getAttribute('accessedAt', '');
|
||||||
|
if (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_KEY_ACCCESS)) > $accessedAt) {
|
||||||
|
$key->setAttribute('accessedAt', DateTime::now());
|
||||||
|
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||||
|
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
$sdkValidator = new WhiteList($servers, true);
|
||||||
|
$sdk = $request->getHeader('x-sdk-name', 'UNKNOWN');
|
||||||
|
if ($sdkValidator->isValid($sdk)) {
|
||||||
|
$sdks = $key->getAttribute('sdks', []);
|
||||||
|
if (!in_array($sdk, $sdks)) {
|
||||||
|
array_push($sdks, $sdk);
|
||||||
|
$key->setAttribute('sdks', $sdks);
|
||||||
|
|
||||||
|
/** Update access time as well */
|
||||||
|
$key->setAttribute('accessedAt', Datetime::now());
|
||||||
|
$dbForConsole->updateDocument('keys', $key->getId(), $key);
|
||||||
|
$dbForConsole->purgeCachedDocument('projects', $project->getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Authorization::setRole($role);
|
||||||
|
|
||||||
|
foreach (Auth::getRoles($user) as $authRole) {
|
||||||
|
Authorization::setRole($authRole);
|
||||||
|
}
|
||||||
|
|
||||||
|
$service = $route->getLabel('sdk.namespace', '');
|
||||||
|
if (!empty($service)) {
|
||||||
|
if (
|
||||||
|
array_key_exists($service, $project->getAttribute('services', []))
|
||||||
|
&& !$project->getAttribute('services', [])[$service]
|
||||||
|
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
|
||||||
|
) {
|
||||||
|
throw new Exception(Exception::GENERAL_SERVICE_DISABLED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!\in_array($scope, $scopes)) {
|
||||||
|
if ($project->isEmpty()) { // Check if permission is denied because project is missing
|
||||||
|
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Exception(Exception::GENERAL_UNAUTHORIZED_SCOPE, $user->getAttribute('email', 'User') . ' (role: ' . \strtolower($roles[$role]['label']) . ') missing scope (' . $scope . ')');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $user->getAttribute('status')) { // Account is blocked
|
||||||
|
throw new Exception(Exception::USER_BLOCKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($user->getAttribute('reset')) {
|
||||||
|
throw new Exception(Exception::USER_PASSWORD_RESET_REQUIRED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($mode !== APP_MODE_ADMIN) {
|
||||||
|
$mfaEnabled = $user->getAttribute('mfa', false);
|
||||||
|
$hasVerifiedAuthenticator = $user->getAttribute('totpVerification', false);
|
||||||
|
$hasVerifiedEmail = $user->getAttribute('emailVerification', false);
|
||||||
|
$hasVerifiedPhone = $user->getAttribute('phoneVerification', false);
|
||||||
|
$hasMoreFactors = $hasVerifiedEmail || $hasVerifiedPhone || $hasVerifiedAuthenticator;
|
||||||
|
$minimumFactors = ($mfaEnabled && $hasMoreFactors) ? 2 : 1;
|
||||||
|
|
||||||
|
if (!in_array('mfa', $route->getGroups())) {
|
||||||
|
if ($session && \count($session->getAttribute('factors')) < $minimumFactors) {
|
||||||
|
throw new Exception(Exception::USER_MORE_FACTORS_REQUIRED);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
App::init()
|
App::init()
|
||||||
->groups(['api'])
|
->groups(['api'])
|
||||||
->inject('utopia')
|
->inject('utopia')
|
||||||
|
@ -212,8 +358,7 @@ App::init()
|
||||||
$response
|
$response
|
||||||
->addHeader('X-RateLimit-Limit', $limit)
|
->addHeader('X-RateLimit-Limit', $limit)
|
||||||
->addHeader('X-RateLimit-Remaining', $remaining)
|
->addHeader('X-RateLimit-Remaining', $remaining)
|
||||||
->addHeader('X-RateLimit-Reset', $time)
|
->addHeader('X-RateLimit-Reset', $time);
|
||||||
;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$enabled = App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled';
|
$enabled = App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled';
|
||||||
|
@ -253,8 +398,7 @@ App::init()
|
||||||
|
|
||||||
$dbForProject
|
$dbForProject
|
||||||
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $databaseListener($event, $document, $project, $queueForUsage, $dbForProject))
|
->on(Database::EVENT_DOCUMENT_CREATE, 'calculate-usage', fn ($event, $document) => $databaseListener($event, $document, $project, $queueForUsage, $dbForProject))
|
||||||
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $databaseListener($event, $document, $project, $queueForUsage, $dbForProject))
|
->on(Database::EVENT_DOCUMENT_DELETE, 'calculate-usage', fn ($event, $document) => $databaseListener($event, $document, $project, $queueForUsage, $dbForProject));
|
||||||
;
|
|
||||||
|
|
||||||
$useCache = $route->getLabel('cache', false);
|
$useCache = $route->getLabel('cache', false);
|
||||||
|
|
||||||
|
@ -296,7 +440,7 @@ App::init()
|
||||||
if ($fileSecurity && !$valid) {
|
if ($fileSecurity && !$valid) {
|
||||||
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
$file = $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId);
|
||||||
} else {
|
} else {
|
||||||
$file = Authorization::skip(fn() => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
$file = Authorization::skip(fn () => $dbForProject->getDocument('bucket_' . $bucket->getInternalId(), $fileId));
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($file->isEmpty()) {
|
if ($file->isEmpty()) {
|
||||||
|
@ -308,8 +452,7 @@ App::init()
|
||||||
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT')
|
->addHeader('Expires', \date('D, d M Y H:i:s', \time() + $timestamp) . ' GMT')
|
||||||
->addHeader('X-Appwrite-Cache', 'hit')
|
->addHeader('X-Appwrite-Cache', 'hit')
|
||||||
->setContentType($data['contentType'])
|
->setContentType($data['contentType'])
|
||||||
->send(base64_decode($data['payload']))
|
->send(base64_decode($data['payload']));
|
||||||
;
|
|
||||||
} else {
|
} else {
|
||||||
$response->addHeader('X-Appwrite-Cache', 'miss');
|
$response->addHeader('X-Appwrite-Cache', 'miss');
|
||||||
}
|
}
|
||||||
|
@ -497,7 +640,7 @@ App::shutdown()
|
||||||
'resource' => $resource,
|
'resource' => $resource,
|
||||||
'contentType' => $response->getContentType(),
|
'contentType' => $response->getContentType(),
|
||||||
'payload' => base64_encode($data['payload']),
|
'payload' => base64_encode($data['payload']),
|
||||||
]) ;
|
]);
|
||||||
|
|
||||||
$signature = md5($data);
|
$signature = md5($data);
|
||||||
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
$cacheLog = Authorization::skip(fn () => $dbForProject->getDocument('cache', $key));
|
||||||
|
@ -505,10 +648,10 @@ App::shutdown()
|
||||||
$now = DateTime::now();
|
$now = DateTime::now();
|
||||||
if ($cacheLog->isEmpty()) {
|
if ($cacheLog->isEmpty()) {
|
||||||
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
|
Authorization::skip(fn () => $dbForProject->createDocument('cache', new Document([
|
||||||
'$id' => $key,
|
'$id' => $key,
|
||||||
'resource' => $resource,
|
'resource' => $resource,
|
||||||
'accessedAt' => $now,
|
'accessedAt' => $now,
|
||||||
'signature' => $signature,
|
'signature' => $signature,
|
||||||
])));
|
])));
|
||||||
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
} elseif (DateTime::formatTz(DateTime::addSeconds(new \DateTime(), -APP_CACHE_UPDATE)) > $accessedAt) {
|
||||||
$cacheLog->setAttribute('accessedAt', $now);
|
$cacheLog->setAttribute('accessedAt', $now);
|
||||||
|
|
Loading…
Reference in a new issue