diff --git a/.env b/.env index 189095e9e5..0bed611fca 100644 --- a/.env +++ b/.env @@ -9,6 +9,7 @@ _APP_SYSTEM_EMAIL_ADDRESS=team@appwrite.io _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=security@appwrite.io _APP_SYSTEM_RESPONSE_FORMAT= _APP_OPTIONS_ABUSE=disabled +_APP_OPTIONS_ROUTER_PROTECTION=enabled _APP_OPTIONS_FORCE_HTTPS=disabled _APP_OPENSSL_KEY_V1=your-secret-key _APP_DOMAIN=localhost diff --git a/app/controllers/general.php b/app/controllers/general.php index d47b863574..3cf78ed4d9 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -47,6 +47,8 @@ Config::setParam('cookieSamesite', Response::COOKIE_SAMESITE_NONE); function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleRequest, Request $request, Response $response) { + $utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml'); + $host = $request->getHostname() ?? ''; $route = Authorization::skip( @@ -57,12 +59,23 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques )[0] ?? null; if ($route === null) { + if($host === App::getEnv('_APP_DOMAIN_FUNCTIONS', '')) { + throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain cannot be used for security reasons. Please use any subdomain instead.'); + } + + if(\str_ends_with($host, App::getEnv('_APP_DOMAIN_FUNCTIONS', ''))) { + throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'This domain is not connected to any Appwrite resource yet. Please configure custom domain or function domain to allow this request.'); + } + + if(App::getEnv('_APP_OPTIONS_ROUTER_PROTECTION', 'disabled') === 'enabled') { + throw new AppwriteException(AppwriteException::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite over this domain. Please add it as custom domain to your project or disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.'); + } + // Act as API - no Proxy logic + $utopia->getRoute()?->label('error', ''); return false; } - $utopia->getRoute()?->label('error', __DIR__ . '/../views/general/error.phtml'); - $projectId = $route->getAttribute('projectId'); $project = Authorization::skip( fn () => $dbForConsole->getDocument('projects', $projectId) @@ -164,6 +177,7 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques throw new AppwriteException(AppwriteException::GENERAL_SERVER_ERROR, 'Unknown resource type ' . $type); } + $utopia->getRoute()?->label('error', ''); return false; } diff --git a/app/controllers/web/console.php b/app/controllers/web/console.php index 4a6f15df3a..ccb088e6ed 100644 --- a/app/controllers/web/console.php +++ b/app/controllers/web/console.php @@ -28,9 +28,17 @@ App::get('/console/*') ->groups(['web']) ->label('permission', 'public') ->label('scope', 'home') + ->inject('utopia') ->inject('request') ->inject('response') - ->action(function (Request $request, Response $response) { + ->action(function (App $utopia, Request $request, Response $response) { + $host = $request->getHostname() ?? ''; + $mainDomain = App::getEnv('_APP_DOMAIN', ''); + if(App::getEnv('_APP_OPTIONS_ROUTER_PROTECTION', 'disabled') === 'enabled' && $host !== $mainDomain) { + $utopia->getRoute()?->label('error', __DIR__ . '/../../views/general/error.phtml'); + throw new Exception(Exception::GENERAL_ACCESS_FORBIDDEN, 'Router protection does not allow accessing Appwrite Console over custom domain. Please disable _APP_OPTIONS_ROUTER_PROTECTION environment variable.'); + } + $fallback = file_get_contents(__DIR__ . '/../../../console/index.html'); // Card SSR diff --git a/docker-compose.yml b/docker-compose.yml index a6c1018d3c..231a7b2170 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -105,6 +105,7 @@ services: - _APP_SYSTEM_SECURITY_EMAIL_ADDRESS - _APP_SYSTEM_RESPONSE_FORMAT - _APP_OPTIONS_ABUSE + - _APP_OPTIONS_ROUTER_PROTECTION - _APP_OPTIONS_FORCE_HTTPS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN @@ -222,6 +223,7 @@ services: - _APP_ENV - _APP_WORKER_PER_CORE - _APP_OPTIONS_ABUSE + - _APP_OPTIONS_ROUTER_PROTECTION - _APP_OPENSSL_KEY_V1 - _APP_REDIS_HOST - _APP_REDIS_PORT