1
0
Fork 0
mirror of synced 2024-05-19 04:02:34 +12:00
appwrite/app/controllers/shared/api.php

240 lines
8.6 KiB
PHP
Raw Normal View History

2019-05-09 18:54:39 +12:00
<?php
2019-10-01 17:57:41 +13:00
2021-01-12 10:52:05 +13:00
use Appwrite\Auth\Auth;
2021-06-30 23:36:58 +12:00
use Appwrite\Database\Document;
2021-01-12 10:52:05 +13:00
use Appwrite\Database\Validator\Authorization;
2021-06-30 23:36:58 +12:00
use Appwrite\Messaging\Adapter\Realtime;
2020-06-29 05:31:21 +12:00
use Utopia\App;
2019-11-30 07:23:29 +13:00
use Utopia\Exception;
use Utopia\Abuse\Abuse;
use Utopia\Abuse\Adapters\TimeLimit;
2021-01-22 21:28:33 +13:00
use Utopia\Storage\Device\Local;
use Utopia\Storage\Storage;
2019-11-30 07:23:29 +13:00
2021-06-24 03:11:23 +12:00
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $db) {
2020-07-03 05:37:24 +12:00
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
2020-10-30 02:50:49 +13:00
/** @var Appwrite\Utopia\Response $response */
2020-07-03 05:37:24 +12:00
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Document $user */
/** @var Utopia\Registry\Registry $register */
2021-01-06 01:22:20 +13:00
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var Appwrite\Event\Event $functions */
2021-06-24 03:11:23 +12:00
/** @var PDO $db */
2021-01-06 01:22:20 +13:00
Storage::setDevice('files', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId()));
Storage::setDevice('functions', new Local(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId()));
2020-07-03 05:37:24 +12:00
2019-11-30 07:23:29 +13:00
$route = $utopia->match($request);
2020-06-25 08:59:04 +12:00
if (empty($project->getId()) && $route->getLabel('abuse-limit', 0) > 0) { // Abuse limit requires an active project scope
throw new Exception('Missing or unknown project ID', 400);
}
2021-06-24 03:11:23 +12:00
/*
* Abuse Check
*/
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $db);
2021-06-24 03:11:23 +12:00
$timeLimit->setNamespace('app_'.$project->getId());
$timeLimit
->setParam('{userId}', $user->getId())
->setParam('{userAgent}', $request->getUserAgent(''))
->setParam('{ip}', $request->getIP())
2021-08-19 17:05:21 +12:00
->setParam('{url}', $request->getHostname().$route->getPath())
2021-06-24 03:11:23 +12:00
;
//TODO make sure we get array here
foreach ($request->getParams() as $key => $value) { // Set request params as potential abuse keys
if(!empty($value)) {
$timeLimit->setParam('{param-'.$key.'}', (\is_array($value)) ? \json_encode($value) : $value);
}
}
$abuse = new Abuse($timeLimit);
if ($timeLimit->limit()) {
$response
->addHeader('X-RateLimit-Limit', $timeLimit->limit())
->addHeader('X-RateLimit-Remaining', $timeLimit->remaining())
->addHeader('X-RateLimit-Reset', $timeLimit->time() + $route->getLabel('abuse-time', 3600))
;
}
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
$isAppUser = Auth::isAppUser(Authorization::$roles);
if (($abuse->check() // Route is rate-limited
&& App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not diabled
&& (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key
{
throw new Exception('Too many requests', 429);
}
2021-01-06 01:22:20 +13:00
/*
* Background Jobs
*/
$events
->setParam('projectId', $project->getId())
2021-05-17 23:32:37 +12:00
->setParam('webhooks', $project->getAttribute('webhooks', []))
2021-01-06 01:22:20 +13:00
->setParam('userId', $user->getId())
->setParam('event', $route->getLabel('event', ''))
2021-03-30 07:00:10 +13:00
->setParam('eventData', [])
2021-01-06 01:22:20 +13:00
->setParam('functionId', null)
->setParam('executionId', null)
->setParam('trigger', 'event')
;
$audits
->setParam('projectId', $project->getId())
->setParam('userId', $user->getId())
->setParam('event', '')
->setParam('resource', '')
->setParam('userAgent', $request->getUserAgent(''))
->setParam('ip', $request->getIP())
->setParam('data', [])
;
$usage
->setParam('projectId', $project->getId())
->setParam('httpRequest', 1)
->setParam('httpUrl', $request->getHostname().$request->getURI())
->setParam('httpMethod', $request->getMethod())
->setParam('networkRequestSize', 0)
->setParam('networkResponseSize', 0)
->setParam('storage', 0)
;
$deletes
->setParam('projectId', $project->getId())
;
2021-06-24 03:11:23 +12:00
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'db'], 'api');
2021-01-06 01:22:20 +13:00
2021-03-01 07:36:13 +13:00
App::init(function ($utopia, $request, $response, $project, $user) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Database\Document $user */
/** @var Utopia\Registry\Registry $register */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var Appwrite\Event\Event $functions */
$route = $utopia->match($request);
2021-03-02 10:04:53 +13:00
$isPrivilegedUser = Auth::isPrivilegedUser(Authorization::$roles);
2021-03-01 07:36:13 +13:00
$isAppUser = Auth::isAppUser(Authorization::$roles);
2021-03-02 10:04:53 +13:00
if($isAppUser || $isPrivilegedUser) { // Skip limits for app and console devs
2021-03-01 07:36:13 +13:00
return;
}
switch ($route->getLabel('auth.type', '')) {
case 'emailPassword':
2021-03-01 09:46:26 +13:00
if($project->getAttribute('usersAuthEmailPassword', true) === false) {
2021-03-01 07:36:13 +13:00
throw new Exception('Email / Password authentication is disabled for this project', 501);
}
break;
case 'anonymous':
2021-03-01 09:46:26 +13:00
if($project->getAttribute('usersAuthAnonymous', true) === false) {
2021-03-01 07:36:13 +13:00
throw new Exception('Anonymous authentication is disabled for this project', 501);
}
break;
case 'invites':
2021-03-01 09:46:26 +13:00
if($project->getAttribute('usersAuthInvites', true) === false) {
2021-03-01 07:36:13 +13:00
throw new Exception('Invites authentication is disabled for this project', 501);
}
break;
case 'jwt':
2021-03-01 09:46:26 +13:00
if($project->getAttribute('usersAuthJWT', true) === false) {
2021-03-01 07:36:13 +13:00
throw new Exception('JWT authentication is disabled for this project', 501);
}
break;
default:
throw new Exception('Unsupported authentication route');
break;
}
}, ['utopia', 'request', 'response', 'project', 'user'], 'auth');
2021-06-30 23:36:58 +12:00
App::shutdown(function ($utopia, $request, $response, $project, $events, $audits, $usage, $deletes, $mode) {
2021-01-06 01:22:20 +13:00
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Appwrite\Event\Event $events */
/** @var Appwrite\Event\Event $audits */
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var bool $mode */
if (!empty($events->getParam('event'))) {
2021-03-30 07:00:10 +13:00
if(empty($events->getParam('eventData'))) {
$events->setParam('eventData', $response->getPayload());
2021-01-06 01:22:20 +13:00
}
$webhooks = clone $events;
$functions = clone $events;
$webhooks
->setQueue('v1-webhooks')
->setClass('WebhooksV1')
->trigger();
$functions
->setQueue('v1-functions')
->setClass('FunctionsV1')
->trigger();
2021-03-12 05:28:03 +13:00
if ($project->getId() !== 'console') {
2021-06-30 23:36:58 +12:00
$payload = new Document($response->getPayload());
$target = Realtime::fromPayload($events->getParam('event'), $payload);
Realtime::send(
$project->getId(),
$response->getPayload(),
$events->getParam('event'),
$target['channels'],
2021-07-14 03:18:02 +12:00
$target['roles'],
2021-06-30 23:36:58 +12:00
[
'permissionsChanged' => $target['permissionsChanged'],
'userId' => $events->getParam('userId')
]
);
2021-03-12 05:28:03 +13:00
}
2021-01-06 01:22:20 +13:00
}
if (!empty($audits->getParam('event'))) {
$audits->trigger();
}
if (!empty($deletes->getParam('type')) && !empty($deletes->getParam('document'))) {
$deletes->trigger();
}
$route = $utopia->match($request);
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled'
&& $project->getId()
2021-01-06 01:22:20 +13:00
&& $mode !== APP_MODE_ADMIN //TODO: add check to make sure user is admin
&& !empty($route->getLabel('sdk.namespace', null))) { // Don't calculate console usage on admin mode
$usage
->setParam('networkRequestSize', $request->getSize() + $usage->getParam('storage'))
->setParam('networkResponseSize', $response->getSize())
->trigger()
;
}
2021-06-30 23:36:58 +12:00
}, ['utopia', 'request', 'response', 'project', 'events', 'audits', 'usage', 'deletes', 'mode'], 'api');