diff --git a/tests/unit/Utopia/RequestTest.php b/tests/unit/Utopia/RequestTest.php index 4c2bed60c3..4f996cd872 100644 --- a/tests/unit/Utopia/RequestTest.php +++ b/tests/unit/Utopia/RequestTest.php @@ -191,7 +191,6 @@ class RequestTest extends TestCase $ip = $this->request->getIP(); $this->assertIsString($ip); - // Default fallback when nothing is set $this->assertSame('0.0.0.0', $ip); } @@ -206,6 +205,16 @@ class RequestTest extends TestCase $this->assertSame('192.168.1.100', $ip); } + public function testGetIPWithXForwardedFor(): void + { + // Set X-Forwarded-For header with single IP + $this->request->addHeader('x-forwarded-for', '203.0.113.195'); + + $ip = $this->request->getIP(); + + $this->assertSame('203.0.113.195', $ip); + } + public function testGetIPWithMultipleProxies(): void { // Set X-Forwarded-For with multiple IPs (leftmost is client) @@ -230,12 +239,14 @@ class RequestTest extends TestCase public function testGetIPWithInvalidIP(): void { // Set invalid IP in X-Forwarded-For + // When the leftmost IP is invalid, the entire header is skipped + // and we fallback to remote_addr (intentional security behavior) $this->request->addHeader('x-forwarded-for', 'not-an-ip, 203.0.113.195'); $this->request->setServer('remote_addr', '192.168.1.100'); $ip = $this->request->getIP(); - // Should fallback to remote_addr since first IP is invalid + // Should fallback to remote_addr since leftmost IP is invalid $this->assertSame('192.168.1.100', $ip); } @@ -244,12 +255,12 @@ class RequestTest extends TestCase // Assuming you can set environment variable in test $_ENV['_APP_TRUSTED_HEADERS'] = 'cf-connecting-ip'; - $this->request->addHeader('cf-connecting-ip', '203.0.113.195, 70.41.3.18'); + $this->request->addHeader('cf-connecting-ip', '203.0.113.195'); $this->request->addHeader('x-forwarded-for', '198.51.100.178'); $ip = $this->request->getIP(); - // Should use cf-connecting-ip since it's the leftmost trusted header and passed + // Should use cf-connecting-ip since it's the trusted header $this->assertSame('203.0.113.195', $ip); unset($_ENV['_APP_TRUSTED_HEADERS']); @@ -284,4 +295,37 @@ class RequestTest extends TestCase unset($_ENV['_APP_TRUSTED_HEADERS']); } + + public function testGetIPWithIPv6(): void + { + $this->request->addHeader('x-forwarded-for', '2001:0db8:85a3:0000:0000:8a2e:0370:7334'); + + $ip = $this->request->getIP(); + + $this->assertSame('2001:0db8:85a3:0000:0000:8a2e:0370:7334', $ip); + } + + public function testGetIPWithEmptyHeader(): void + { + $this->request->addHeader('x-forwarded-for', ''); + $this->request->setServer('remote_addr', '192.168.1.100'); + + $ip = $this->request->getIP(); + + // Should fallback to remote_addr when header is empty + $this->assertSame('192.168.1.100', $ip); + } + + public function testGetIPWithEmptyTrustedHeadersConfig(): void + { + $_ENV['_APP_TRUSTED_HEADERS'] = ' , , '; + $this->request->setServer('remote_addr', '192.168.1.100'); + + $ip = $this->request->getIP(); + + // Should fallback to remote_addr when config is effectively empty + $this->assertSame('192.168.1.100', $ip); + + unset($_ENV['_APP_TRUSTED_HEADERS']); + } }