Allow users to disable APIs
This commit is contained in:
parent
9e4250ad9f
commit
d3b0b00917
10 changed files with 106 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',
|
||||||
|
],
|
||||||
|
];
|
|
@ -3367,6 +3367,17 @@ $consoleCollections = array_merge([
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'filters' => ['json'],
|
'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'),
|
'$id' => ID::custom('smtp'),
|
||||||
'type' => Database::VAR_STRING,
|
'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.',
|
'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,
|
'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 => [
|
Exception::GENERAL_SERVICE_DISABLED => [
|
||||||
'name' => Exception::GENERAL_SERVICE_DISABLED,
|
'name' => Exception::GENERAL_SERVICE_DISABLED,
|
||||||
'description' => 'The requested service is disabled. You can enable the service from the Appwrite console.',
|
'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\Database\Document;
|
||||||
use Utopia\Validator\JSON;
|
use Utopia\Validator\JSON;
|
||||||
use Utopia\Validator\Text;
|
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')
|
App::get('/v1/graphql')
|
||||||
->desc('GraphQL endpoint')
|
->desc('GraphQL endpoint')
|
||||||
|
|
|
@ -473,6 +473,37 @@ App::patch('/v1/projects/:projectId/service/all')
|
||||||
$response->dynamic($project, Response::MODEL_PROJECT);
|
$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')
|
App::patch('/v1/projects/:projectId/oauth2')
|
||||||
->desc('Update project OAuth2')
|
->desc('Update project OAuth2')
|
||||||
->groups(['api', 'projects'])
|
->groups(['api', 'projects'])
|
||||||
|
|
|
@ -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
|
// Skip Appwrite Router for ACME challenge. Nessessary for certificate generation
|
||||||
$path = ($swooleRequest->server['request_uri'] ?? '/');
|
$path = ($swooleRequest->server['request_uri'] ?? '/');
|
||||||
if (\str_starts_with($path, '/.well-known/acme-challenge')) {
|
if (\str_starts_with($path, '/.well-known/acme-challenge')) {
|
||||||
|
|
|
@ -21,6 +21,7 @@ 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 Appwrite\Extend\Exception as AppwriteException;
|
||||||
|
|
||||||
$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);
|
||||||
|
@ -164,6 +165,14 @@ App::init()
|
||||||
throw new Exception(Exception::PROJECT_UNKNOWN);
|
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
|
* 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('events', __DIR__ . '/config/events.php');
|
||||||
Config::load('auth', __DIR__ . '/config/auth.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('errors', __DIR__ . '/config/errors.php');
|
||||||
Config::load('providers', __DIR__ . '/config/providers.php');
|
Config::load('providers', __DIR__ . '/config/providers.php');
|
||||||
Config::load('platforms', __DIR__ . '/config/platforms.php');
|
Config::load('platforms', __DIR__ . '/config/platforms.php');
|
||||||
|
|
|
@ -28,6 +28,7 @@ use Utopia\Config\Config;
|
||||||
use Utopia\Database\Database;
|
use Utopia\Database\Database;
|
||||||
use Utopia\WebSocket\Server;
|
use Utopia\WebSocket\Server;
|
||||||
use Utopia\WebSocket\Adapter;
|
use Utopia\WebSocket\Adapter;
|
||||||
|
use Appwrite\Extend\Exception as AppwriteException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var \Utopia\Registry\Registry $register
|
* @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');
|
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);
|
$dbForProject = getProjectDB($project);
|
||||||
$console = $app->getResource('console'); /** @var Document $console */
|
$console = $app->getResource('console'); /** @var Document $console */
|
||||||
$user = $app->getResource('user'); /** @var Document $user */
|
$user = $app->getResource('user'); /** @var Document $user */
|
||||||
|
|
|
@ -40,6 +40,7 @@ class Exception extends \Exception
|
||||||
public const GENERAL_MOCK = 'general_mock';
|
public const GENERAL_MOCK = 'general_mock';
|
||||||
public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden';
|
public const GENERAL_ACCESS_FORBIDDEN = 'general_access_forbidden';
|
||||||
public const GENERAL_UNKNOWN_ORIGIN = 'general_unknown_origin';
|
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_SERVICE_DISABLED = 'general_service_disabled';
|
||||||
public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope';
|
public const GENERAL_UNAUTHORIZED_SCOPE = 'general_unauthorized_scope';
|
||||||
public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded';
|
public const GENERAL_RATE_LIMIT_EXCEEDED = 'general_rate_limit_exceeded';
|
||||||
|
|
Loading…
Reference in a new issue