Merge pull request #1246 from lohanidamodar/feat-audit-abuse

feat-audit-abuse
This commit is contained in:
Eldad A. Fux 2021-06-12 17:55:04 +03:00 committed by GitHub
commit 00136969d2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 211 additions and 200 deletions

View file

@ -18,10 +18,8 @@ use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Utopia\Validator\ArrayList;
use Utopia\Audit\Audit;
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate;
use Ahc\Jwt\JWT;
use Utopia\Database\Query;
use Utopia\Database\Validator\Authorization;
use Utopia\Database\Validator\UID;
@ -833,22 +831,19 @@ App::get('/v1/account/logs')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->inject('response')
->inject('register')
->inject('project')
->inject('user')
->inject('locale')
->inject('geodb')
->action(function ($response, $register, $project, $user, $locale, $geodb) {
->inject('dbForInternal')
->action(function ($response, $user, $locale, $geodb, $dbForInternal) {
/** @var Appwrite\Utopia\Response $response */
/** @var Appwrite\Database\Document $project */
/** @var Utopia\Database\Document $user */
/** @var Utopia\Locale\Locale $locale */
/** @var MaxMind\Db\Reader $geodb */
/** @var Utopia\Database\Database $dbForInternal */
$adapter = new AuditAdapter($register->get('db'));
$adapter->setNamespace('app_'.$project->getId());
$audit = new Audit($adapter);
$audit = new Audit($dbForInternal);
$countries = $locale->getText('countries');
$logs = $audit->getLogsByUserAndActions($user->getId(), [
@ -1629,4 +1624,4 @@ App::put('/v1/account/verification')
;
$response->dynamic2($verification, Response::MODEL_TOKEN);
});
});

View file

@ -1,25 +1,27 @@
<?php
use Utopia\App;
use Utopia\Exception;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Appwrite\Network\Validator\URL;
use Utopia\Validator\Range;
use Utopia\Validator\Integer;
use Utopia\Config\Config;
use Utopia\Domains\Domain;
use Appwrite\Auth\Auth;
use Appwrite\Task\Validator\Cron;
use Appwrite\Network\Validator\CNAME;
use Appwrite\Network\Validator\Domain as DomainValidator;
use Appwrite\Network\Validator\URL;
use Appwrite\Task\Validator\Cron;
use Appwrite\Utopia\Response;
use Cron\CronExpression;
use Utopia\App;
use Utopia\Config\Config;
use Utopia\Database\Document;
use Utopia\Database\Query;
use Utopia\Database\Validator\UID;
use Utopia\Domains\Domain;
use Utopia\Exception;
use Utopia\Validator\ArrayList;
use Utopia\Validator\Boolean;
use Utopia\Validator\Integer;
use Utopia\Validator\Range;
use Utopia\Validator\Text;
use Utopia\Validator\WhiteList;
use Utopia\Audit\Audit;
use Utopia\Abuse\Adapters\TimeLimit;
App::post('/v1/projects')
->desc('Create Project')
@ -62,8 +64,8 @@ App::post('/v1/projects')
$project = $dbForConsole->createDocument('projects', new Document([
'$collection' => 'projects',
'$read' => ['team:'.$teamId],
'$write' => ['team:'.$teamId.'/owner', 'team:'.$teamId.'/developer'],
'$read' => ['team:' . $teamId],
'$write' => ['team:' . $teamId . '/owner', 'team:' . $teamId . '/developer'],
'name' => $name,
'description' => $description,
'logo' => $logo,
@ -89,11 +91,17 @@ App::post('/v1/projects')
$collections = Config::getParam('collections2', []); /** @var array $collections */
$dbForInternal->setNamespace('project_'.$project->getId().'_internal');
$dbForInternal->setNamespace('project_' . $project->getId() . '_internal');
$dbForInternal->create();
$dbForExternal->setNamespace('project_'.$project->getId().'_external');
$dbForExternal->setNamespace('project_' . $project->getId() . '_external');
$dbForExternal->create();
$audit = new Audit($dbForInternal);
$audit->setup();
$adapter = new TimeLimit("", 0, 1, $dbForInternal);
$adapter->setup();
foreach ($collections as $key => $collection) {
$dbForInternal->createCollection($key);
@ -210,7 +218,7 @@ App::get('/v1/projects/:projectId/usage')
throw new Exception('Project not found', 404);
}
if(App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
if (App::getEnv('_APP_USAGE_STATS', 'enabled') == 'enabled') {
$period = [
'24h' => [
@ -234,44 +242,44 @@ App::get('/v1/projects/:projectId/usage')
'group' => '1d',
],
];
$client = $register->get('influxdb');
$requests = [];
$network = [];
$functions = [];
if ($client) {
$start = $period[$range]['start']->format(DateTime::RFC3339);
$end = $period[$range]['end']->format(DateTime::RFC3339);
$database = $client->selectDB('telegraf');
// Requests
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_requests_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_requests_all" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\' AND "project"=\'' . $project->getId() . '\' GROUP BY time(' . $period[$range]['group'] . ') FILL(null)');
$points = $result->getPoints();
foreach ($points as $point) {
$requests[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => \strtotime($point['time']),
];
}
// Network
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_network_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_network_all" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\' AND "project"=\'' . $project->getId() . '\' GROUP BY time(' . $period[$range]['group'] . ') FILL(null)');
$points = $result->getPoints();
foreach ($points as $point) {
$network[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
'date' => \strtotime($point['time']),
];
}
// Functions
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \''.$start.'\' AND time < \''.$end.'\' AND "metric_type"=\'counter\' AND "project"=\''.$project->getId().'\' GROUP BY time('.$period[$range]['group'].') FILL(null)');
$result = $database->query('SELECT sum(value) AS "value" FROM "appwrite_usage_executions_all" WHERE time > \'' . $start . '\' AND time < \'' . $end . '\' AND "metric_type"=\'counter\' AND "project"=\'' . $project->getId() . '\' GROUP BY time(' . $period[$range]['group'] . ') FILL(null)');
$points = $result->getPoints();
foreach ($points as $point) {
$functions[] = [
'value' => (!empty($point['value'])) ? $point['value'] : 0,
@ -285,14 +293,13 @@ App::get('/v1/projects/:projectId/usage')
$functions = [];
}
// Users
$projectDB->getCollection([
'limit' => 0,
'offset' => 0,
'filters' => [
'$collection=users'
'$collection=users',
],
]);
@ -317,7 +324,7 @@ App::get('/v1/projects/:projectId/usage')
'limit' => 0,
'offset' => 0,
'filters' => [
'$collection='.$collection['$id'],
'$collection=' . $collection['$id'],
],
]);
@ -373,7 +380,7 @@ App::get('/v1/projects/:projectId/usage')
'$collection=files',
],
]
) +
) +
$projectDB->getCount(
[
'attribute' => 'size',
@ -420,16 +427,16 @@ App::patch('/v1/projects/:projectId')
}
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('name', $name)
->setAttribute('description', $description)
->setAttribute('logo', $logo)
->setAttribute('url', $url)
->setAttribute('legalName', $legalName)
->setAttribute('legalCountry', $legalCountry)
->setAttribute('legalState', $legalState)
->setAttribute('legalCity', $legalCity)
->setAttribute('legalAddress', $legalAddress)
->setAttribute('legalTaxId', $legalTaxId)
->setAttribute('name', $name)
->setAttribute('description', $description)
->setAttribute('logo', $logo)
->setAttribute('url', $url)
->setAttribute('legalName', $legalName)
->setAttribute('legalCountry', $legalCountry)
->setAttribute('legalState', $legalState)
->setAttribute('legalCity', $legalCity)
->setAttribute('legalAddress', $legalAddress)
->setAttribute('legalTaxId', $legalTaxId)
);
$response->dynamic2($project, Response::MODEL_PROJECT);
@ -462,8 +469,8 @@ App::patch('/v1/projects/:projectId/oauth2')
}
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('usersOauth2'.\ucfirst($provider).'Appid', $appId)
->setAttribute('usersOauth2'.\ucfirst($provider).'Secret', $secret)
->setAttribute('usersOauth2' . \ucfirst($provider) . 'Appid', $appId)
->setAttribute('usersOauth2' . \ucfirst($provider) . 'Secret', $secret)
);
$response->dynamic2($project, Response::MODEL_PROJECT);
@ -494,7 +501,7 @@ App::patch('/v1/projects/:projectId/auth/limit')
}
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('usersAuthLimit', $limit)
->setAttribute('usersAuthLimit', $limit)
);
$response->dynamic2($project, Response::MODEL_PROJECT);
@ -511,7 +518,7 @@ App::patch('/v1/projects/:projectId/auth/:method')
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: '.implode(',', \array_keys(Config::getParam('auth'))), false)
->param('method', '', new WhiteList(\array_keys(Config::getParam('auth')), true), 'Auth Method. Possible values: ' . implode(',', \array_keys(Config::getParam('auth'))), false)
->param('status', false, new Boolean(true), 'Set the status of this auth method.')
->inject('response')
->inject('dbForConsole')
@ -529,7 +536,7 @@ App::patch('/v1/projects/:projectId/auth/:method')
}
$dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute($authKey, $status)
->setAttribute($authKey, $status)
);
$response->dynamic2($project, Response::MODEL_PROJECT);
@ -570,7 +577,7 @@ App::delete('/v1/projects/:projectId')
->setParam('type', DELETE_TYPE_DOCUMENT)
->setParam('document', $project)
;
if (!$dbForConsole->deleteDocument('teams', $project->getAttribute('teamId', null))) {
throw new Exception('Failed to remove project team from DB', 500);
}
@ -626,7 +633,7 @@ App::post('/v1/projects/:projectId/webhooks')
]);
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('webhooks', $webhook, Document::SET_TYPE_APPEND)
->setAttribute('webhooks', $webhook, Document::SET_TYPE_APPEND)
);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@ -736,16 +743,16 @@ App::put('/v1/projects/:projectId/webhooks/:webhookId')
}
$project->findAndReplace('$id', $webhook->getId(), $webhook
->setAttribute('name', $name)
->setAttribute('events', $events)
->setAttribute('url', $url)
->setAttribute('security', $security)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
, 'webhooks');
->setAttribute('name', $name)
->setAttribute('events', $events)
->setAttribute('url', $url)
->setAttribute('security', $security)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
, 'webhooks');
$dbForConsole->updateDocument('projects', $project->getId(), $project);
$response->dynamic2($webhook, Response::MODEL_WEBHOOK);
});
@ -816,7 +823,7 @@ App::post('/v1/projects/:projectId/keys')
]);
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('keys', $key, Document::SET_TYPE_APPEND)
->setAttribute('keys', $key, Document::SET_TYPE_APPEND)
);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@ -839,7 +846,7 @@ App::get('/v1/projects/:projectId/keys')
->action(function ($projectId, $response, $dbForConsole) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Database\Database $dbForConsole */
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
@ -917,12 +924,12 @@ App::put('/v1/projects/:projectId/keys/:keyId')
}
$project->findAndReplace('$id', $key->getId(), $key
->setAttribute('name', $name)
->setAttribute('scopes', $scopes)
, 'keys');
->setAttribute('name', $name)
->setAttribute('scopes', $scopes)
, 'keys');
$dbForConsole->updateDocument('projects', $project->getId(), $project);
$response->dynamic2($key, Response::MODEL_KEY);
});
@ -1015,7 +1022,7 @@ App::post('/v1/projects/:projectId/tasks')
]);
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('tasks', $task, Document::SET_TYPE_APPEND)
->setAttribute('tasks', $task, Document::SET_TYPE_APPEND)
);
if ($next) {
@ -1135,18 +1142,18 @@ App::put('/v1/projects/:projectId/tasks/:taskId')
$security = ($security === '1' || $security === 'true' || $security === 1 || $security === true);
$project->findAndReplace('$id', $task->getId(), $task
->setAttribute('name', $name)
->setAttribute('status', $status)
->setAttribute('schedule', $schedule)
->setAttribute('updated', \time())
->setAttribute('next', $next)
->setAttribute('security', $security)
->setAttribute('httpMethod', $httpMethod)
->setAttribute('httpUrl', $httpUrl)
->setAttribute('httpHeaders', $httpHeaders)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
, 'tasks');
->setAttribute('name', $name)
->setAttribute('status', $status)
->setAttribute('schedule', $schedule)
->setAttribute('updated', \time())
->setAttribute('next', $next)
->setAttribute('security', $security)
->setAttribute('httpMethod', $httpMethod)
->setAttribute('httpUrl', $httpUrl)
->setAttribute('httpHeaders', $httpHeaders)
->setAttribute('httpUser', $httpUser)
->setAttribute('httpPass', $httpPass)
, 'tasks');
$dbForConsole->updateDocument('projects', $project->getId(), $project);
@ -1231,13 +1238,13 @@ App::post('/v1/projects/:projectId/platforms')
]);
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('platforms', $platform, Document::SET_TYPE_APPEND)
->setAttribute('platforms', $platform, Document::SET_TYPE_APPEND)
);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
$response->dynamic2($platform, Response::MODEL_PLATFORM);
});
App::get('/v1/projects/:projectId/platforms')
->desc('List Platforms')
->groups(['api', 'projects'])
@ -1345,12 +1352,12 @@ App::put('/v1/projects/:projectId/platforms/:platformId')
;
$project->findAndReplace('$id', $platform->getId(), $platform
->setAttribute('name', $name)
->setAttribute('dateUpdated', \time())
->setAttribute('key', $key)
->setAttribute('store', $store)
->setAttribute('hostname', $hostname)
, 'platforms');
->setAttribute('name', $name)
->setAttribute('dateUpdated', \time())
->setAttribute('key', $key)
->setAttribute('store', $store)
->setAttribute('hostname', $hostname)
, 'platforms');
$dbForConsole->updateDocument('projects', $project->getId(), $project);
@ -1424,7 +1431,7 @@ App::post('/v1/projects/:projectId/domains')
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
if (!$target->isKnown() || $target->isTest()) {
throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.', 500);
throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500);
}
$domain = new Domain($domain);
@ -1440,7 +1447,7 @@ App::post('/v1/projects/:projectId/domains')
]);
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project
->setAttribute('domains', $domain, Document::SET_TYPE_APPEND)
->setAttribute('domains', $domain, Document::SET_TYPE_APPEND)
);
$response->setStatusCode(Response::STATUS_CODE_CREATED);
@ -1471,7 +1478,7 @@ App::get('/v1/projects/:projectId/domains')
}
$domains = $project->getAttribute('domains', []);
$response->dynamic2(new Document([
'domains' => $domains,
'sum' => count($domains),
@ -1544,7 +1551,7 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
$target = new Domain(App::getEnv('_APP_DOMAIN_TARGET', ''));
if (!$target->isKnown() || $target->isTest()) {
throw new Exception('Unreachable CNAME target ('.$target->get().'), please use a domain with a public suffix.', 500);
throw new Exception('Unreachable CNAME target (' . $target->get() . '), please use a domain with a public suffix.', 500);
}
if ($domain->getAttribute('verification') === true) {
@ -1558,8 +1565,8 @@ App::patch('/v1/projects/:projectId/domains/:domainId/verification')
}
$project->findAndReplace('$id', $domain->getId(), $domain
->setAttribute('verification', true)
, 'domains');
->setAttribute('verification', true)
, 'domains');
$dbForConsole->updateDocument('projects', $project->getId(), $project);
@ -1610,4 +1617,4 @@ App::delete('/v1/projects/:projectId/domains/:domainId')
;
$response->noContent();
});
});

View file

@ -13,7 +13,6 @@ use Utopia\Validator\Text;
use Utopia\Validator\Range;
use Utopia\Validator\Boolean;
use Utopia\Audit\Audit;
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
use Utopia\Database\Document;
use Utopia\Database\Exception\Duplicate;
use Utopia\Database\Validator\UID;
@ -214,12 +213,10 @@ App::get('/v1/users/:userId/logs')
->label('sdk.response.model', Response::MODEL_LOG_LIST)
->param('userId', '', new UID(), 'User unique ID.')
->inject('response')
->inject('register')
->inject('project')
->inject('dbForInternal')
->inject('locale')
->inject('geodb')
->action(function ($userId, $response, $register, $project, $dbForInternal, $locale, $geodb) {
->action(function ($userId, $response, $dbForInternal, $locale, $geodb) {
/** @var Appwrite\Utopia\Response $response */
/** @var Utopia\Registry\Registry $register */
/** @var Appwrite\Database\Document $project */
@ -233,10 +230,7 @@ App::get('/v1/users/:userId/logs')
throw new Exception('User not found', 404);
}
$adapter = new AuditAdapter($register->get('db'));
$adapter->setNamespace('app_'.$project->getId());
$audit = new Audit($adapter);
$audit = new Audit($dbForInternal);
$countries = $locale->getText('countries');

View file

@ -9,7 +9,7 @@ use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\Storage\Device\Local;
use Utopia\Storage\Storage;
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes) {
App::init(function ($utopia, $request, $response, $project, $user, $register, $events, $audits, $usage, $deletes, $dbForInternal) {
/** @var Utopia\App $utopia */
/** @var Utopia\Swoole\Request $request */
/** @var Appwrite\Utopia\Response $response */
@ -21,6 +21,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
/** @var Appwrite\Event\Event $usage */
/** @var Appwrite\Event\Event $deletes */
/** @var Appwrite\Event\Event $functions */
/** @var Utopia\Database\Database $dbForInternal */
Storage::setDevice('files', new Local(APP_STORAGE_UPLOADS.'/app-'.$project->getId()));
Storage::setDevice('functions', new Local(APP_STORAGE_FUNCTIONS.'/app-'.$project->getId()));
@ -31,47 +32,44 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
throw new Exception('Missing or unknown project ID', 400);
}
// /*
// * Abuse Check
// */
// $timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), function () use ($register) {
// return $register->get('db');
// });
// $timeLimit->setNamespace('app_'.$project->getId());
// $timeLimit
// ->setParam('{userId}', $user->getId())
// ->setParam('{userAgent}', $request->getUserAgent(''))
// ->setParam('{ip}', $request->getIP())
// ->setParam('{url}', $request->getHostname().$route->getURL())
// ;
/*
* Abuse Check
*/
$timeLimit = new TimeLimit($route->getLabel('abuse-key', 'url:{url},ip:{ip}'), $route->getLabel('abuse-limit', 0), $route->getLabel('abuse-time', 3600), $dbForInternal);
$timeLimit
->setParam('{userId}', $user->getId())
->setParam('{userAgent}', $request->getUserAgent(''))
->setParam('{ip}', $request->getIP())
->setParam('{url}', $request->getHostname().$route->getURL())
;
// //TODO make sure we get array here
//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);
// }
// }
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);
$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))
// ;
// }
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);
$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);
// }
if (($abuse->check() // Route is rate-limited
&& App::getEnv('_APP_OPTIONS_ABUSE', 'enabled') !== 'disabled') // Abuse is not disabled
&& (!$isAppUser && !$isPrivilegedUser)) // User is not an admin or API key
{
throw new Exception('Too many requests', 429);
}
/*
* Background Jobs
@ -111,7 +109,7 @@ App::init(function ($utopia, $request, $response, $project, $user, $register, $e
->setParam('projectId', $project->getId())
;
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes'], 'api');
}, ['utopia', 'request', 'response', 'project', 'user', 'register', 'events', 'audits', 'usage', 'deletes', 'dbForInternal'], 'api');
App::init(function ($utopia, $request, $response, $project, $user) {

View file

@ -14,6 +14,8 @@ use Utopia\App;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Database\Validator\Authorization as Authorization2;
use Utopia\Audit\Audit;
use Utopia\Abuse\Adapters\TimeLimit;
// xdebug_start_trace('/tmp/trace');
@ -67,6 +69,12 @@ $http->on('start', function (Server $http) use ($payloadSize, $register) {
$register->get('cache')->flushAll();
$dbForConsole->create();
$audit = new Audit($dbForConsole);
$audit->setup();
$adapter = new TimeLimit("", 0, 1, $dbForConsole);
$adapter->setup();
foreach ($collections as $key => $collection) {
$dbForConsole->createCollection($key);

View file

@ -2,8 +2,11 @@
use Appwrite\Resque\Worker;
use Utopia\Audit\Audit;
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
use Utopia\Cache\Adapter\Redis;
use Utopia\Cache\Cache;
use Utopia\CLI\Console;
use Utopia\Database\Adapter\MariaDB;
use Utopia\Database\Database;
require_once __DIR__.'/../init.php';
@ -31,10 +34,11 @@ class AuditsV1 extends Worker
$data = $this->args['data'];
$db = $register->get('db', true);
$adapter = new AuditAdapter($db);
$adapter->setNamespace('app_'.$projectId);
$cache = new Cache(new Redis($register->get('cache')));
$dbForInternal = new Database(new MariaDB($db), $cache);
$dbForInternal->setNamespace('project_'.$projectId.'_internal');
$audit = new Audit($adapter);
$audit = new Audit($dbForInternal);
$audit->log($userId, $event, $resource, $userAgent, $ip, '', $data);
}

View file

@ -1,6 +1,8 @@
<?php
use Appwrite\Database\Database;
use Utopia\Database\Database as Database2;
use Utopia\Cache\Adapter\Redis as RedisCache;
use Appwrite\Database\Adapter\MySQL as MySQLAdapter;
use Appwrite\Database\Adapter\Redis as RedisAdapter;
use Appwrite\Database\Document;
@ -12,7 +14,8 @@ use Utopia\Abuse\Adapters\TimeLimit;
use Utopia\CLI\Console;
use Utopia\Config\Config;
use Utopia\Audit\Audit;
use Utopia\Audit\Adapters\MySQL as AuditAdapter;
use Utopia\Cache\Cache;
use Utopia\Database\Adapter\MariaDB;
require_once __DIR__.'/../init.php';
@ -165,12 +168,9 @@ class DeletesV1 extends Worker
throw new Exception('Failed to delete audit logs. No timestamp provided');
}
$timeLimit = new TimeLimit("", 0, 1, function () use ($register) {
return $register->get('db');
});
$this->deleteForProjectIds(function($projectId) use ($timeLimit, $timestamp){
$timeLimit->setNamespace('app_'.$projectId);
$this->deleteForProjectIds(function($projectId) use ($timestamp){
$timeLimit = new TimeLimit("", 0, 1, $this->getInternalDB($projectId));
$abuse = new Abuse($timeLimit);
$status = $abuse->cleanup($timestamp);
@ -187,9 +187,7 @@ class DeletesV1 extends Worker
throw new Exception('Failed to delete audit logs. No timestamp provided');
}
$this->deleteForProjectIds(function($projectId) use ($register, $timestamp){
$adapter = new AuditAdapter($register->get('db'));
$adapter->setNamespace('app_'.$projectId);
$audit = new Audit($adapter);
$audit = new Audit($this->getInternalDB($projectId));
$status = $audit->cleanup($timestamp);
if (!$status) {
throw new Exception('Failed to delete Audit logs for project'.$projectId);
@ -373,4 +371,18 @@ class DeletesV1 extends Worker
return $projectDB;
}
}
/**
* @return Database2
*/
protected function getInternalDB($projectId): Database2
{
global $register;
$cache = new Cache(new RedisCache($register->get('cache')));
$dbForInternal = new Database2(new MariaDB($register->get('db')), $cache);
$dbForInternal->setNamespace('project_'.$projectId.'_internal'); // Main DB
return $dbForInternal;
}
}

View file

@ -39,9 +39,9 @@
"appwrite/php-runtimes": "0.2.*",
"utopia-php/framework": "0.14.*",
"utopia-php/abuse": "0.4.*",
"utopia-php/abuse": "dev-feat-utopia-db-integration",
"utopia-php/analytics": "0.2.*",
"utopia-php/audit": "0.5.*",
"utopia-php/audit": "dev-feat-utopia-db-integration",
"utopia-php/cache": "0.4.*",
"utopia-php/cli": "0.11.*",
"utopia-php/config": "0.2.*",
@ -62,6 +62,16 @@
"adhocore/jwt": "1.1.2",
"slickdeals/statsd": "3.0.2"
},
"repositories": [
{
"type": "git",
"url": "https://github.com/lohanidamodar/audit"
},
{
"type": "git",
"url": "https://github.com/lohanidamodar/abuse"
}
],
"require-dev": {
"appwrite/sdk-generator": "0.10.11",
"swoole/ide-helper": "4.6.6",

55
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2d21d6dff0d1764f94854a32d5312b0d",
"content-hash": "e3617b2fd699e599dc2c1d7ed74c9f44",
"packages": [
{
"name": "adhocore/jwt",
@ -1603,21 +1603,16 @@
},
{
"name": "utopia-php/abuse",
"version": "0.4.1",
"version": "dev-feat-utopia-db-integration",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/abuse.git",
"reference": "8b7973aae4b02489bd22ffea45b985608f13b6d9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/abuse/zipball/8b7973aae4b02489bd22ffea45b985608f13b6d9",
"reference": "8b7973aae4b02489bd22ffea45b985608f13b6d9",
"shasum": ""
"url": "https://github.com/lohanidamodar/abuse",
"reference": "4f3349b3c1c85353708d13f7eb3c34c0762d4828"
},
"require": {
"ext-pdo": "*",
"php": ">=7.4"
"php": ">=7.4",
"utopia-php/database": "0.2.*"
},
"require-dev": {
"phpunit/phpunit": "^9.4",
@ -1629,7 +1624,6 @@
"Utopia\\Abuse\\": "src/Abuse"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@ -1641,17 +1635,13 @@
],
"description": "A simple abuse library to manage application usage limits",
"keywords": [
"Abuse",
"abuse",
"framework",
"php",
"upf",
"utopia"
],
"support": {
"issues": "https://github.com/utopia-php/abuse/issues",
"source": "https://github.com/utopia-php/abuse/tree/0.4.1"
},
"time": "2021-06-05T14:31:33+00:00"
"time": "2021-06-09T09:11:16+00:00"
},
{
"name": "utopia-php/analytics",
@ -1710,21 +1700,16 @@
},
{
"name": "utopia-php/audit",
"version": "0.5.1",
"version": "dev-feat-utopia-db-integration",
"source": {
"type": "git",
"url": "https://github.com/utopia-php/audit.git",
"reference": "154a850170a58667a15e4b65fbabb6cd0b709dd9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/utopia-php/audit/zipball/154a850170a58667a15e4b65fbabb6cd0b709dd9",
"reference": "154a850170a58667a15e4b65fbabb6cd0b709dd9",
"shasum": ""
"url": "https://github.com/lohanidamodar/audit",
"reference": "b3b85524717bbf52cfe71f01474c4012bfd4323a"
},
"require": {
"ext-pdo": "*",
"php": ">=7.1"
"php": ">=7.4",
"utopia-php/database": "0.2.*"
},
"require-dev": {
"phpunit/phpunit": "^9.3",
@ -1736,7 +1721,6 @@
"Utopia\\Audit\\": "src/Audit"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
@ -1748,17 +1732,13 @@
],
"description": "A simple audit library to manage application users logs",
"keywords": [
"Audit",
"audit",
"framework",
"php",
"upf",
"utopia"
],
"support": {
"issues": "https://github.com/utopia-php/audit/issues",
"source": "https://github.com/utopia-php/audit/tree/0.5.1"
},
"time": "2020-12-21T17:28:53+00:00"
"time": "2021-06-09T09:10:27+00:00"
},
{
"name": "utopia-php/cache",
@ -6190,7 +6170,10 @@
],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"stability-flags": {
"utopia-php/abuse": 20,
"utopia-php/audit": 20
},
"prefer-stable": false,
"prefer-lowest": false,
"platform": {