diff --git a/.env b/.env index 189095e9e5..c1ccc71182 100644 --- a/.env +++ b/.env @@ -10,6 +10,7 @@ _APP_SYSTEM_SECURITY_EMAIL_ADDRESS=security@appwrite.io _APP_SYSTEM_RESPONSE_FORMAT= _APP_OPTIONS_ABUSE=disabled _APP_OPTIONS_FORCE_HTTPS=disabled +_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS=disabled _APP_OPENSSL_KEY_V1=your-secret-key _APP_DOMAIN=localhost _APP_DOMAIN_FUNCTIONS=functions.localhost diff --git a/app/config/variables.php b/app/config/variables.php index 5d8c0eaa2e..7685f3f735 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -36,7 +36,16 @@ return [ ], [ 'name' => '_APP_OPTIONS_FORCE_HTTPS', - 'description' => 'Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443.', + 'description' => 'Allows you to force HTTPS connection to your API. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443, and you have set up wildcard certificates with DNS challenge.', + 'introduction' => '', + 'default' => 'disabled', + 'required' => false, + 'question' => '', + 'filter' => '' + ], + [ + 'name' => '_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS', + 'description' => 'Allows you to force HTTPS connection to function domains. This feature redirects any HTTP call to HTTPS and adds the \'Strict-Transport-Security\' header to all HTTP responses. By default, set to \'enabled\'. To disable, set to \'disabled\'. This feature will work only when your ports are set to default 80 and 443.', 'introduction' => '', 'default' => 'disabled', 'required' => false, diff --git a/app/controllers/general.php b/app/controllers/general.php index d47b863574..6da34cf1c2 100644 --- a/app/controllers/general.php +++ b/app/controllers/general.php @@ -83,6 +83,16 @@ function router(App $utopia, Database $dbForConsole, SwooleRequest $swooleReques $type = $route->getAttribute('resourceType'); if ($type === 'function') { + if (App::getEnv('_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS + if ($request->getProtocol() !== 'https') { + if ($request->getMethod() !== Request::METHOD_GET) { + throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.'); + } + + return $response->redirect('https://' . $request->getHostname() . $request->getURI()); + } + } + $functionId = $route->getAttribute('resourceId'); $projectId = $route->getAttribute('projectId'); @@ -380,7 +390,7 @@ App::init() if (App::getEnv('_APP_OPTIONS_FORCE_HTTPS', 'disabled') === 'enabled') { // Force HTTPS if ($request->getProtocol() !== 'https' && ($swooleRequest->header['host'] ?? '') !== 'localhost' && ($swooleRequest->header['host'] ?? '') !== APP_HOSTNAME_INTERNAL) { // localhost allowed for proxy, APP_HOSTNAME_INTERNAL allowed for migrations if ($request->getMethod() !== Request::METHOD_GET) { - throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP.'); + throw new AppwriteException(AppwriteException::GENERAL_PROTOCOL_UNSUPPORTED, 'Method unsupported over HTTP. Please use HTTPS instead.'); } return $response->redirect('https://' . $request->getHostname() . $request->getURI()); diff --git a/app/views/install/compose.phtml b/app/views/install/compose.phtml index f8ea37067c..cbda77d5e2 100644 --- a/app/views/install/compose.phtml +++ b/app/views/install/compose.phtml @@ -85,6 +85,7 @@ services: - _APP_SYSTEM_RESPONSE_FORMAT - _APP_OPTIONS_ABUSE - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET @@ -383,6 +384,7 @@ services: - _APP_FUNCTIONS_MEMORY - _APP_FUNCTIONS_SIZE_LIMIT - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - _APP_DOMAIN - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY diff --git a/docker-compose.yml b/docker-compose.yml index 25c3973080..9811015f3a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -106,6 +106,7 @@ services: - _APP_SYSTEM_RESPONSE_FORMAT - _APP_OPTIONS_ABUSE - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_TARGET @@ -418,6 +419,7 @@ services: - _APP_FUNCTIONS_MEMORY - _APP_FUNCTIONS_SIZE_LIMIT - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - _APP_DOMAIN - _APP_STORAGE_DEVICE - _APP_STORAGE_S3_ACCESS_KEY diff --git a/src/Appwrite/Platform/Tasks/Doctor.php b/src/Appwrite/Platform/Tasks/Doctor.php index 423dd78fe7..739a23aaf4 100644 --- a/src/Appwrite/Platform/Tasks/Doctor.php +++ b/src/Appwrite/Platform/Tasks/Doctor.php @@ -93,6 +93,12 @@ class Doctor extends Action Console::log('🟢 HTTPS force option is enabled'); } + if ('enabled' !== App::getEnv('_APP_OPTIONS_FUNCTIONS_FORCE_HTTPS', 'disabled')) { + Console::log('🔴 HTTPS force option is disabled for function domains'); + } else { + Console::log('🟢 HTTPS force option is enabled for function domains'); + } + $providerName = App::getEnv('_APP_LOGGING_PROVIDER', ''); $providerConfig = App::getEnv('_APP_LOGGING_CONFIG', ''); diff --git a/tests/resources/docker/docker-compose.yml b/tests/resources/docker/docker-compose.yml index 3baae7316d..19e63c5313 100644 --- a/tests/resources/docker/docker-compose.yml +++ b/tests/resources/docker/docker-compose.yml @@ -67,6 +67,7 @@ services: - _APP_ENV - _APP_OPTIONS_ABUSE - _APP_OPTIONS_FORCE_HTTPS + - _APP_OPTIONS_FUNCTIONS_FORCE_HTTPS - _APP_OPENSSL_KEY_V1 - _APP_DOMAIN - _APP_DOMAIN_FUNCTIONS