Files
FreshRSS/tests/app/Utils/httpUtilTest.php
T
Jamal Kamaladdinoglu 2bb901d9c4 Accept a trusted proxy address given without a subnet (#9301)
TRUSTED_PROXY=192.168.1.1 is ignored and only 192.168.1.1/32 is honoured. checkCIDR() splits the range on the slash and rejects the value when the mask part is missing, so an address written without a subnet never matches.

An address without a subnet is now read as a single host: /32 for IPv4 and /128 for IPv6. That is the format docs/en/admins/09_AccessControl.md points at.

Host names such as gateway.localdomain are still not resolved.

tests/app/Utils/httpUtilTest.php gains 16 cases for checkCIDR, two of which fail without this change.

Refs #9210
2026-09-13 22:34:39 +02:00

75 lines
2.8 KiB
PHP

<?php
declare(strict_types=1);
use PHPUnit\Framework\Attributes\DataProvider;
/**
* Tests for FreshRSS_http_Util
*/
class httpUtilTest extends \PHPUnit\Framework\TestCase {
#[DataProvider('provideUrlsIgnoringHttps')]
public function test_compareUrlIgnoringHttps(string $url1, string $url2, bool $expected): void {
self::assertEquals($expected, FreshRSS_http_Util::compareUrlIgnoringHttps($url1, $url2) === 0);
}
#[DataProvider('provideCidrRanges')]
public function test_checkCIDR(string $ip, string $range, bool $expected): void {
$checkCIDR = new ReflectionMethod(FreshRSS_http_Util::class, 'checkCIDR');
self::assertEquals($expected, $checkCIDR->invoke(null, $ip, $range));
}
/** @return list<array{string,string,bool}> */
public static function provideCidrRanges(): array {
return [
// A range without a subnet is a single address
['192.168.1.1', '192.168.1.1', true],
['192.168.1.2', '192.168.1.1', false],
['2001:db8::1', '2001:db8::1', true],
['2001:db8::2', '2001:db8::1', false],
// An explicit subnet keeps working
['192.168.1.1', '192.168.1.1/32', true],
['192.168.1.42', '192.168.1.0/24', true],
['192.168.2.42', '192.168.1.0/24', false],
['192.168.1.1', '0.0.0.0/0', true],
['2001:db8::1', '2001:db8::/32', true],
// Invalid input is still rejected
['192.168.1.1', '', false],
['192.168.1.1', '192.168.1.1/', false],
['192.168.1.1', '192.168.1.1/33', false],
['192.168.1.1', '192.168.1.1/abc', false],
['192.168.1.1', 'gateway.localdomain', false],
['192.168.1.1', '2001:db8::1', false],
['not-an-ip', '192.168.1.1', false],
];
}
/** @return list<array{string,string,bool}> */
public static function provideUrlsIgnoringHttps(): array {
return [
// Only the scheme differs → equal
['http://www.blogger.com/feeds/1/posts', 'https://www.blogger.com/feeds/1/posts', true],
['https://example.net/feed.xml?a=1&b=2', 'http://example.net/feed.xml?a=1&b=2', true],
['HTTP://Example.net/Feed', 'https://Example.net/Feed', true],
['HTTPS://Example.net/Feed', 'http://Example.net/Feed', true],
// Fully identical → equal
['https://example.net/feed', 'https://example.net/feed', true],
['', '', true],
// Path differs → not equal (scheme-only tolerance must not hide real mismatches)
['http://example.net/a', 'https://example.net/b', false],
// Trailing slash is a path difference → not equal
['http://example.net/', 'https://example.net', false],
// Host differs → not equal
['http://a.example.net/feed', 'https://b.example.net/feed', false],
// Query differs → not equal
['https://example.net/feed?a=1', 'http://example.net/feed?a=2', false],
// Non-http(s) schemes are compared as-is
['ftp://example.net/feed', 'https://example.net/feed', false],
];
}
}