1
0
Fork 0
mirror of synced 2024-06-13 16:24:47 +12:00

Allow users to disable APIs

This commit is contained in:
Khushboo Verma 2024-03-04 23:12:54 +01:00
parent 9e4250ad9f
commit d3b0b00917
10 changed files with 106 additions and 0 deletions

16
app/config/apis.php Normal file
View file

@ -0,0 +1,16 @@
<?php
return [
'rest' => [
'key' => 'rest',
'name' => 'REST',
],
'graphql' => [
'key' => 'graphql',
'name' => 'GraphQL',
],
'realtime' => [
'key' => 'realtime',
'name' => 'Realtime',
],
];

View file

@ -3367,6 +3367,17 @@ $consoleCollections = array_merge([
'array' => false,
'filters' => ['json'],
],
[
'$id' => ID::custom('apis'),
'type' => Database::VAR_STRING,
'format' => '',
'size' => 16384,
'signed' => true,
'required' => false,
'default' => [],
'array' => false,
'filters' => ['json'],
],
[
'$id' => ID::custom('smtp'),
'type' => Database::VAR_STRING,

View file

@ -28,6 +28,11 @@ return [
'description' => 'The request originated from an unknown origin. If you trust this domain, please list it as a trusted platform in the Appwrite console.',
'code' => 403,
],
Exception::GENERAL_API_DISABLED => [
'name' => Exception::GENERAL_API_DISABLED,
'description' => 'The requested API is disabled. You can enable the API from the Appwrite console.',
'code' => 403,
],
Exception::GENERAL_SERVICE_DISABLED => [
'name' => Exception::GENERAL_SERVICE_DISABLED,
'description' => 'The requested service is disabled. You can enable the service from the Appwrite console.',

View file

@ -16,6 +16,22 @@ use Utopia\App;
use Utopia\Database\Document;
use Utopia\Validator\JSON;
use Utopia\Validator\Text;
use Appwrite\Auth\Auth;
use Utopia\Database\Validator\Authorization;
use Appwrite\Extend\Exception as AppwriteException;
App::init()
->groups(['graphql'])
->inject('project')
->action(function (Document $project) {
if (
array_key_exists('graphql', $project->getAttribute('apis', []))
&& !$project->getAttribute('apis', [])['graphql']
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
});
App::get('/v1/graphql')
->desc('GraphQL endpoint')

View file

@ -473,6 +473,37 @@ App::patch('/v1/projects/:projectId/service/all')
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/api')
->desc('Update API status')
->groups(['api', 'projects'])
->label('scope', 'projects.write')
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
->label('sdk.namespace', 'projects')
->label('sdk.method', 'updateApiStatus')
->label('sdk.response.code', Response::STATUS_CODE_OK)
->label('sdk.response.type', Response::CONTENT_TYPE_JSON)
->label('sdk.response.model', Response::MODEL_PROJECT)
->param('projectId', '', new UID(), 'Project unique ID.')
->param('api', '', new WhiteList(array_keys(Config::getParam('apis')), true), 'API name.')
->param('status', null, new Boolean(), 'API status.')
->inject('response')
->inject('dbForConsole')
->action(function (string $projectId, string $api, bool $status, Response $response, Database $dbForConsole) {
$project = $dbForConsole->getDocument('projects', $projectId);
if ($project->isEmpty()) {
throw new Exception(Exception::PROJECT_NOT_FOUND);
}
$apis = $project->getAttribute('apis', []);
$apis[$api] = $status;
$project = $dbForConsole->updateDocument('projects', $project->getId(), $project->setAttribute('apis', $apis));
$response->dynamic($project, Response::MODEL_PROJECT);
});
App::patch('/v1/projects/:projectId/oauth2')
->desc('Update project OAuth2')
->groups(['api', 'projects'])

View file

@ -92,6 +92,13 @@ function router(App $utopia, Database $dbForConsole, callable $getProjectDB, Swo
}
}
if (array_key_exists('proxy', $project->getAttribute('apis', []))) {
$status = $project->getAttribute('apis', [])['proxy'];
if (!$status) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
}
// Skip Appwrite Router for ACME challenge. Nessessary for certificate generation
$path = ($swooleRequest->server['request_uri'] ?? '/');
if (\str_starts_with($path, '/.well-known/acme-challenge')) {

View file

@ -21,6 +21,7 @@ use Utopia\Database\Database;
use Utopia\Database\DateTime;
use Utopia\Database\Document;
use Utopia\Database\Validator\Authorization;
use Appwrite\Extend\Exception as AppwriteException;
$parseLabel = function (string $label, array $responsePayload, array $requestParams, Document $user) {
preg_match_all('/{(.*?)}/', $label, $matches);
@ -164,6 +165,14 @@ App::init()
throw new Exception(Exception::PROJECT_UNKNOWN);
}
if (
array_key_exists('rest', $project->getAttribute('apis', []))
&& !$project->getAttribute('apis', [])['rest']
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
/*
* Abuse Check
*/

View file

@ -236,6 +236,7 @@ App::setMode(App::getEnv('_APP_ENV', App::MODE_TYPE_PRODUCTION));
*/
Config::load('events', __DIR__ . '/config/events.php');
Config::load('auth', __DIR__ . '/config/auth.php');
Config::load('apis', __DIR__ . '/config/apis.php'); // List of APIs
Config::load('errors', __DIR__ . '/config/errors.php');
Config::load('providers', __DIR__ . '/config/providers.php');
Config::load('platforms', __DIR__ . '/config/platforms.php');

View file

@ -28,6 +28,7 @@ use Utopia\Config\Config;
use Utopia\Database\Database;
use Utopia\WebSocket\Server;
use Utopia\WebSocket\Adapter;
use Appwrite\Extend\Exception as AppwriteException;
/**
* @var \Utopia\Registry\Registry $register
@ -410,6 +411,14 @@ $server->onOpen(function (int $connection, SwooleRequest $request) use ($server,
throw new Exception(Exception::REALTIME_POLICY_VIOLATION, 'Missing or unknown project ID');
}
if (
array_key_exists('realtime', $project->getAttribute('apis', []))
&& !$project->getAttribute('apis', [])['realtime']
&& !(Auth::isPrivilegedUser(Authorization::getRoles()) || Auth::isAppUser(Authorization::getRoles()))
) {
throw new AppwriteException(AppwriteException::GENERAL_API_DISABLED);
}
$dbForProject = getProjectDB($project);
$console = $app->getResource('console'); /** @var Document $console */
$user = $app->getResource('user'); /** @var Document $user */

View file

@ -40,6 +40,7 @@ class Exception extends \Exception
public const GENERAL_MOCK = 'general_mock';
public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden';
public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin';
public const GENERAL_API_DISABLED = 'general_api_disabled';
public const GENERAL_SERVICE_DISABLED = 'general_service_disabled';
public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope';
public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded';