| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- <?php
- declare(strict_types=1);
- namespace App\Tests\Unit\Http;
- use App\Infrastructure\Http\Middleware\InternalNetworkMiddleware;
- use PHPUnit\Framework\Attributes\DataProvider;
- use PHPUnit\Framework\TestCase;
- use Psr\Http\Message\ResponseInterface;
- use Psr\Http\Message\ServerRequestInterface;
- use Psr\Http\Server\RequestHandlerInterface;
- use Slim\Psr7\Factory\ResponseFactory;
- use Slim\Psr7\Factory\ServerRequestFactory;
- /**
- * Network gate must let RFC1918 + loopback through, 404 everything else,
- * and never leak via 403 (which would tell attackers the endpoint exists).
- * The handler is stubbed to a marker response so we can confirm whether
- * the middleware short-circuited or passed through.
- */
- final class InternalNetworkMiddlewareTest extends TestCase
- {
- /**
- * @return iterable<string, array{string, bool}>
- */
- public static function addressProvider(): iterable
- {
- yield 'loopback v4' => ['127.0.0.1', true];
- yield 'loopback v6' => ['::1', true];
- yield 'rfc1918 10/8' => ['10.5.6.7', true];
- yield 'rfc1918 172.16/12' => ['172.16.42.1', true];
- yield 'rfc1918 172.31/12 (boundary)' => ['172.31.255.255', true];
- yield 'just outside 172.16/12' => ['172.32.0.1', false];
- yield 'rfc1918 192.168/16' => ['192.168.1.1', true];
- yield 'public 1.1.1.1' => ['1.1.1.1', false];
- yield 'public v4' => ['203.0.113.4', false];
- yield 'public v6' => ['2001:db8::1', false];
- yield 'malformed' => ['not-an-ip', false];
- yield 'empty' => ['', false];
- }
- #[DataProvider('addressProvider')]
- public function testNetworkGate(string $remoteAddr, bool $shouldPass): void
- {
- $middleware = new InternalNetworkMiddleware(new ResponseFactory());
- $req = (new ServerRequestFactory())->createServerRequest(
- 'POST',
- '/internal/jobs/tick',
- ['REMOTE_ADDR' => $remoteAddr],
- );
- $passthrough = new class () implements RequestHandlerInterface {
- public bool $reached = false;
- public function handle(ServerRequestInterface $request): ResponseInterface
- {
- $this->reached = true;
- $factory = new ResponseFactory();
- return $factory->createResponse(204);
- }
- };
- $response = $middleware->process($req, $passthrough);
- if ($shouldPass) {
- self::assertSame(204, $response->getStatusCode());
- self::assertTrue($passthrough->reached);
- } else {
- self::assertSame(404, $response->getStatusCode());
- self::assertFalse($passthrough->reached, 'handler must not see disallowed sources');
- }
- }
- }
|