Merge pull request #7725 from appwrite/feat-disable-api
Allow users to disable APIs
This commit is contained in:
commit
77d91ad762
9 changed files with 133 additions and 0 deletions
16
app/config/apis.php
Normal file
16
app/config/apis.php
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
|
||||
return [
|
||||
'rest' => [
|
||||
'key' => 'rest',
|
||||
'name' => 'REST',
|
||||
],
|
||||
'graphql' => [
|
||||
'key' => 'graphql',
|
||||
'name' => 'GraphQL',
|
||||
],
|
||||
'realtime' => [
|
||||
'key' => 'realtime',
|
||||
'name' => 'Realtime',
|
||||
],
|
||||
];
|
|
@ -3389,6 +3389,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,
|
||||
|
|
|
@ -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.',
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -473,6 +473,71 @@ 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/api/all')
|
||||
->desc('Update all API status')
|
||||
->groups(['api', 'projects'])
|
||||
->label('scope', 'projects.write')
|
||||
->label('sdk.auth', [APP_AUTH_TYPE_ADMIN])
|
||||
->label('sdk.namespace', 'projects')
|
||||
->label('sdk.method', 'updateAPIStatusAll')
|
||||
->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('status', null, new Boolean(), 'API status.')
|
||||
->inject('response')
|
||||
->inject('dbForConsole')
|
||||
->action(function (string $projectId, bool $status, Response $response, Database $dbForConsole) {
|
||||
|
||||
$project = $dbForConsole->getDocument('projects', $projectId);
|
||||
|
||||
if ($project->isEmpty()) {
|
||||
throw new Exception(Exception::PROJECT_NOT_FOUND);
|
||||
}
|
||||
|
||||
$allApis = array_keys(Config::getParam('apis'));
|
||||
|
||||
$apis = [];
|
||||
foreach ($allApis as $api) {
|
||||
$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'])
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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');
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue