From 90fb5b6321effea3ff082bd1690049d24c4e2a4c Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 12 Dec 2025 08:42:49 +0100 Subject: [PATCH 1/7] feat: improved reference client ip through _APP_TRUSTED_HEADERS --- .env | 1 + app/config/variables.php | 9 ++++++ src/Appwrite/Utopia/Request.php | 3 ++ tests/e2e/Services/Account/AccountBase.php | 34 ++++++++++++++++++++++ 4 files changed, 47 insertions(+) diff --git a/.env b/.env index 55ec662f24..c9a8b3a0b4 100644 --- a/.env +++ b/.env @@ -125,3 +125,4 @@ _APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10 _APP_PROJECT_REGIONS=default _APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000 _APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main +_APP_TRUSTED_HEADERS= diff --git a/app/config/variables.php b/app/config/variables.php index 408be8d54e..653e959101 100644 --- a/app/config/variables.php +++ b/app/config/variables.php @@ -357,6 +357,15 @@ return [ 'required' => false, 'question' => '', 'filter' => '' + ], + [ + 'name' => '_APP_TRUSTED_HEADERS', + 'description' => 'This option allows you to set the list of trusted headers, the value is a comma‑separated list of HTTP header names, evaluated left-to-right for the first valid IP. Header names are treated case-insensitively.', + 'introduction' => '1.8.0', + 'default' => 'x-forwarded-for', + 'required' => false, + 'question' => '', + 'filter' => '' ] ], ], diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index ce570d2af9..8e6b5d47b3 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -9,9 +9,12 @@ use Swoole\Http\Request as SwooleRequest; use Utopia\Database\Validator\Authorization; use Utopia\Route; use Utopia\Swoole\Request as UtopiaRequest; +use Utopia\System\System; class Request extends UtopiaRequest { + protected array $trustedIpHeaders = explode(",", System::getEnv('_APP_TRUSTED_HEADERS') ?? 'x-forwarded-for'); + /** * @var array */ diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index 13b5015241..c678fb83cd 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -326,4 +326,38 @@ trait AccountBase $this->assertEquals($response['headers']['status-code'], 204); } + + public function testTrustedIpViaHeaders(): void + { + $email = uniqid() . 'user@localhost.test'; + $password = 'password'; + $name = 'User Name'; + + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-forwarded-for' => '203.0.113.195', + ]), [ + 'userId' => ID::unique(), + 'email' => $email, + 'password' => $password, + 'name' => $name, + ]); + + $this->assertEquals($response['headers']['status-code'], 201); + + $response = $this->client->call(Client::METHOD_POST, '/account/sessions/email', array_merge([ + 'origin' => 'http://localhost', + 'content-type' => 'application/json', + 'x-appwrite-project' => $this->getProject()['$id'], + 'x-forwarded-for' => '203.0.113.195', + ]), [ + 'email' => $email, + 'password' => $password, + ]); + + $this->assertEquals($response['headers']['status-code'], 201); + $this->assertEquals('203.0.113.195', $response['body']['clientIp'] ?? $response['body']['ip'] ?? ''); + } } From 6589c6a7863fc2fbf4a75861d9d14532c3a3a071 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 12 Dec 2025 10:54:09 +0100 Subject: [PATCH 2/7] chore: bump utopia-php/framework to version 0.33.35 --- composer.lock | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/composer.lock b/composer.lock index 47a32cf774..e88eb8fe62 100644 --- a/composer.lock +++ b/composer.lock @@ -4264,16 +4264,16 @@ }, { "name": "utopia-php/framework", - "version": "0.33.34", + "version": "0.33.35", "source": { "type": "git", "url": "https://github.com/utopia-php/http.git", - "reference": "76def92594c32504ec80eaacdb60ff8fad73c856" + "reference": "82b139fb04f30045db51b0d322224f222da32313" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/http/zipball/76def92594c32504ec80eaacdb60ff8fad73c856", - "reference": "76def92594c32504ec80eaacdb60ff8fad73c856", + "url": "https://api.github.com/repos/utopia-php/http/zipball/82b139fb04f30045db51b0d322224f222da32313", + "reference": "82b139fb04f30045db51b0d322224f222da32313", "shasum": "" }, "require": { @@ -4306,9 +4306,9 @@ ], "support": { "issues": "https://github.com/utopia-php/http/issues", - "source": "https://github.com/utopia-php/http/tree/0.33.34" + "source": "https://github.com/utopia-php/http/tree/0.33.35" }, - "time": "2025-12-08T07:55:31+00:00" + "time": "2025-12-12T08:33:52+00:00" }, { "name": "utopia-php/image", From ce9a54fd4b39b11ec058f218872a734b6d423088 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Fri, 12 Dec 2025 15:31:42 +0100 Subject: [PATCH 3/7] chore: change implementation for trustedip --- .env | 2 +- src/Appwrite/Utopia/Request.php | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/.env b/.env index c9a8b3a0b4..9c6dc04223 100644 --- a/.env +++ b/.env @@ -125,4 +125,4 @@ _APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10 _APP_PROJECT_REGIONS=default _APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000 _APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main -_APP_TRUSTED_HEADERS= +_APP_TRUSTED_HEADERS=x-forwarded-for diff --git a/src/Appwrite/Utopia/Request.php b/src/Appwrite/Utopia/Request.php index 8e6b5d47b3..cb449e6ffa 100644 --- a/src/Appwrite/Utopia/Request.php +++ b/src/Appwrite/Utopia/Request.php @@ -13,8 +13,6 @@ use Utopia\System\System; class Request extends UtopiaRequest { - protected array $trustedIpHeaders = explode(",", System::getEnv('_APP_TRUSTED_HEADERS') ?? 'x-forwarded-for'); - /** * @var array */ @@ -23,6 +21,9 @@ class Request extends UtopiaRequest public function __construct(SwooleRequest $request) { + $trustedHeaders = System::getEnv('_APP_TRUSTED_HEADERS', 'x-forwarded-for'); + $this->setTrustedIpHeaders(explode(',', $trustedHeaders)); + parent::__construct($request); } From cd90974e1597e0f58991895063f9a3162ce57f97 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Mon, 15 Dec 2025 13:22:29 +0100 Subject: [PATCH 4/7] chore: changes to test to validate default behaviour instead --- .env | 2 +- composer.json | 2 +- composer.lock | 22 ++++++++++++---------- docker-compose.yml | 1 + tests/e2e/Services/Account/AccountBase.php | 11 +++++++---- 5 files changed, 22 insertions(+), 16 deletions(-) diff --git a/.env b/.env index 9c6dc04223..5343c8d086 100644 --- a/.env +++ b/.env @@ -125,4 +125,4 @@ _APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10 _APP_PROJECT_REGIONS=default _APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000 _APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main -_APP_TRUSTED_HEADERS=x-forwarded-for +_APP_TRUSTED_HEADERS= \ No newline at end of file diff --git a/composer.json b/composer.json index d32b739311..d898378ca4 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,7 @@ "utopia-php/queue": "0.11.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.18.*", - "utopia-php/swoole": "0.8.*", + "utopia-php/swoole": "clo-3704-duplicate-changes-to-swoole-due-to-overwrite-dev", "utopia-php/system": "0.9.*", "utopia-php/telemetry": "0.1.*", "utopia-php/vcs": "0.13.*", diff --git a/composer.lock b/composer.lock index e88eb8fe62..656b8a4267 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "7c9cb03eb5267f1e7a3ffc037ae22b6a", + "content-hash": "28bb3cab7ab0efd5e6abf9fa923bd17b", "packages": [ { "name": "adhocore/jwt", @@ -5011,22 +5011,22 @@ }, { "name": "utopia-php/swoole", - "version": "0.8.4", + "version": "dev-clo-3704-duplicate-changes-to-swoole-due-to-overwrite", "source": { "type": "git", "url": "https://github.com/utopia-php/swoole.git", - "reference": "150c30700e738c52348cce9ed0e0f0ff96872081" + "reference": "af6911b0a4eef4b7a825cd246e6070b02b856b8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/swoole/zipball/150c30700e738c52348cce9ed0e0f0ff96872081", - "reference": "150c30700e738c52348cce9ed0e0f0ff96872081", + "url": "https://api.github.com/repos/utopia-php/swoole/zipball/af6911b0a4eef4b7a825cd246e6070b02b856b8f", + "reference": "af6911b0a4eef4b7a825cd246e6070b02b856b8f", "shasum": "" }, "require": { "ext-swoole": "*", "php": ">=8.0", - "utopia-php/framework": "0.33.*" + "utopia-php/framework": "0.33.x" }, "require-dev": { "laravel/pint": "1.2.*", @@ -5056,9 +5056,9 @@ ], "support": { "issues": "https://github.com/utopia-php/swoole/issues", - "source": "https://github.com/utopia-php/swoole/tree/0.8.4" + "source": "https://github.com/utopia-php/swoole/tree/clo-3704-duplicate-changes-to-swoole-due-to-overwrite" }, - "time": "2025-09-07T09:39:46+00:00" + "time": "2025-12-15T10:03:28+00:00" }, { "name": "utopia-php/system", @@ -8943,7 +8943,9 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": [], + "stability-flags": { + "utopia-php/swoole": 20 + }, "prefer-stable": false, "prefer-lowest": false, "platform": { @@ -8967,5 +8969,5 @@ "platform-overrides": { "php": "8.3" }, - "plugin-api-version": "2.6.0" + "plugin-api-version": "2.9.0" } diff --git a/docker-compose.yml b/docker-compose.yml index f246dbb456..ac1c7cd0f1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -219,6 +219,7 @@ services: - _APP_DATABASE_SHARED_NAMESPACE - _APP_FUNCTIONS_CREATION_ABUSE_LIMIT - _APP_CUSTOM_DOMAIN_DENY_LIST + - _APP_TRUSTED_HEADERS extra_hosts: - "host.docker.internal:host-gateway" diff --git a/tests/e2e/Services/Account/AccountBase.php b/tests/e2e/Services/Account/AccountBase.php index c678fb83cd..0c9d481371 100644 --- a/tests/e2e/Services/Account/AccountBase.php +++ b/tests/e2e/Services/Account/AccountBase.php @@ -327,17 +327,20 @@ trait AccountBase $this->assertEquals($response['headers']['status-code'], 204); } - public function testTrustedIpViaHeaders(): void + public function testFallbackForTrustedIp(): void { $email = uniqid() . 'user@localhost.test'; $password = 'password'; $name = 'User Name'; + // call appwrite directly to avoid proxy stripping the headers + $this->client->setEndpoint('http://localhost/v1'); + $response = $this->client->call(Client::METHOD_POST, '/account', array_merge([ 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-forwarded-for' => '203.0.113.195', + 'x-forwarded-for' => '191.0.113.195', ]), [ 'userId' => ID::unique(), 'email' => $email, @@ -351,13 +354,13 @@ trait AccountBase 'origin' => 'http://localhost', 'content-type' => 'application/json', 'x-appwrite-project' => $this->getProject()['$id'], - 'x-forwarded-for' => '203.0.113.195', + 'x-forwarded-for' => '191.0.113.195', ]), [ 'email' => $email, 'password' => $password, ]); $this->assertEquals($response['headers']['status-code'], 201); - $this->assertEquals('203.0.113.195', $response['body']['clientIp'] ?? $response['body']['ip'] ?? ''); + $this->assertEquals('191.0.113.195', $response['body']['clientIp'] ?? $response['body']['ip'] ?? ''); } } From 0d7eb88a45da31c8cb7c9d4950e0f7a0619c5f34 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:08:23 +0100 Subject: [PATCH 5/7] chore: update utopia-php/swoole to version 0.8.5 --- composer.json | 2 +- composer.lock | 20 +++++++++----------- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/composer.json b/composer.json index d898378ca4..95d10ca0c9 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,7 @@ "utopia-php/queue": "0.11.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.18.*", - "utopia-php/swoole": "clo-3704-duplicate-changes-to-swoole-due-to-overwrite-dev", + "utopia-php/swoole": "0.8.5", "utopia-php/system": "0.9.*", "utopia-php/telemetry": "0.1.*", "utopia-php/vcs": "0.13.*", diff --git a/composer.lock b/composer.lock index 656b8a4267..47488ae924 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "28bb3cab7ab0efd5e6abf9fa923bd17b", + "content-hash": "3be93acc5ee72f38f6e3436487169976", "packages": [ { "name": "adhocore/jwt", @@ -5011,22 +5011,22 @@ }, { "name": "utopia-php/swoole", - "version": "dev-clo-3704-duplicate-changes-to-swoole-due-to-overwrite", + "version": "0.8.5", "source": { "type": "git", "url": "https://github.com/utopia-php/swoole.git", - "reference": "af6911b0a4eef4b7a825cd246e6070b02b856b8f" + "reference": "e42b6b8e44c457a7b35d8a857d7af1d67d667c58" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/utopia-php/swoole/zipball/af6911b0a4eef4b7a825cd246e6070b02b856b8f", - "reference": "af6911b0a4eef4b7a825cd246e6070b02b856b8f", + "url": "https://api.github.com/repos/utopia-php/swoole/zipball/e42b6b8e44c457a7b35d8a857d7af1d67d667c58", + "reference": "e42b6b8e44c457a7b35d8a857d7af1d67d667c58", "shasum": "" }, "require": { "ext-swoole": "*", "php": ">=8.0", - "utopia-php/framework": "0.33.x" + "utopia-php/framework": "0.33.35" }, "require-dev": { "laravel/pint": "1.2.*", @@ -5056,9 +5056,9 @@ ], "support": { "issues": "https://github.com/utopia-php/swoole/issues", - "source": "https://github.com/utopia-php/swoole/tree/clo-3704-duplicate-changes-to-swoole-due-to-overwrite" + "source": "https://github.com/utopia-php/swoole/tree/0.8.5" }, - "time": "2025-12-15T10:03:28+00:00" + "time": "2025-12-15T14:03:23+00:00" }, { "name": "utopia-php/system", @@ -8943,9 +8943,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": { - "utopia-php/swoole": 20 - }, + "stability-flags": {}, "prefer-stable": false, "prefer-lowest": false, "platform": { From 8a35762843c172c78933b8b493cb62847296ed8e Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:36:13 +0100 Subject: [PATCH 6/7] chore: update utopia-php/swoole version constraint to 0.8.* --- composer.json | 2 +- composer.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/composer.json b/composer.json index 95d10ca0c9..d32b739311 100644 --- a/composer.json +++ b/composer.json @@ -72,7 +72,7 @@ "utopia-php/queue": "0.11.*", "utopia-php/registry": "0.5.*", "utopia-php/storage": "0.18.*", - "utopia-php/swoole": "0.8.5", + "utopia-php/swoole": "0.8.*", "utopia-php/system": "0.9.*", "utopia-php/telemetry": "0.1.*", "utopia-php/vcs": "0.13.*", diff --git a/composer.lock b/composer.lock index 47488ae924..6277c96145 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "3be93acc5ee72f38f6e3436487169976", + "content-hash": "7c9cb03eb5267f1e7a3ffc037ae22b6a", "packages": [ { "name": "adhocore/jwt", From 03a19cc83c3fafbd5fab5d016392a2555f578ac0 Mon Sep 17 00:00:00 2001 From: Levi van Noort <73097785+levivannoort@users.noreply.github.com> Date: Mon, 15 Dec 2025 15:49:21 +0100 Subject: [PATCH 7/7] chore: set _APP_TRUSTED_HEADERS to x-forwarded-for --- .env | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.env b/.env index 5343c8d086..3a0c4a50cb 100644 --- a/.env +++ b/.env @@ -125,4 +125,4 @@ _APP_WEBHOOK_MAX_FAILED_ATTEMPTS=10 _APP_PROJECT_REGIONS=default _APP_FUNCTIONS_CREATION_ABUSE_LIMIT=5000 _APP_STATS_USAGE_DUAL_WRITING_DBS=database_db_main -_APP_TRUSTED_HEADERS= \ No newline at end of file +_APP_TRUSTED_HEADERS=x-forwarded-for \ No newline at end of file