IpFilter   A
last analyzed

Complexity

Total Complexity 6

Size/Duplication

Total Lines 48
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
eloc 14
dl 0
loc 48
ccs 17
cts 17
cp 1
rs 10
c 0
b 0
f 0
wmc 6

3 Methods

Rating   Name   Duplication   Size   Complexity  
A createForbiddenResponse() 0 6 1
A __construct() 0 6 1
A process() 0 19 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace Yiisoft\Yii\Middleware;
6
7
use Psr\Http\Message\ResponseFactoryInterface;
8
use Psr\Http\Message\ResponseInterface;
9
use Psr\Http\Message\ServerRequestInterface;
10
use Psr\Http\Server\MiddlewareInterface;
11
use Psr\Http\Server\RequestHandlerInterface;
12
use Yiisoft\Http\Status;
13
use Yiisoft\Validator\Rule\Ip;
14
use Yiisoft\Validator\ValidatorInterface;
15
16
/**
17
 * `IpFilter` allows access from specified IP ranges only and responds with 403 for all other IPs.
18
 */
19
final class IpFilter implements MiddlewareInterface
20
{
21
    /**
22
     * @param ValidatorInterface $validator Client IP validator. The properties of the validator
23
     * can be modified up to the moment of processing.
24
     * @param ResponseFactoryInterface $responseFactory The response factory instance.
25
     * @param string|null $clientIpAttribute Name of the request attribute holding client IP. If there is no such
26
     * attribute, or it has no value, then the middleware will respond with 403 forbidden.
27
     * If the name of the request attribute is `null`, then `REMOTE_ADDR` server parameter is used to determine client IP.
28
     * @param array $ipRanges Allowed IPv4 or IPv6 ranges.
29
     *
30
     * @psalm-param array<array-key, string> $ipRanges
31
     */
32 9
    public function __construct(
33
        private ValidatorInterface $validator,
34
        private ResponseFactoryInterface $responseFactory,
35
        private ?string $clientIpAttribute = null,
36
        private array $ipRanges = [],
37
    ) {
38 9
    }
39
40 9
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
41
    {
42 9
        if ($this->clientIpAttribute !== null) {
43 1
            $clientIp = $request->getAttribute($this->clientIpAttribute);
44
        }
45
46
        /** @psalm-var array{REMOTE_ADDR?: mixed} $serverParams */
47 9
        $serverParams = $request->getServerParams();
48 9
        $clientIp ??= $serverParams['REMOTE_ADDR'] ?? null;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $clientIp does not seem to be defined for all execution paths leading up to this point.
Loading history...
49 9
        if ($clientIp === null) {
50 1
            return $this->createForbiddenResponse();
51
        }
52
53 8
        $result = $this->validator->validate($clientIp, [new Ip(ranges: $this->ipRanges)]);
54 8
        if (!$result->isValid()) {
55 5
            return $this->createForbiddenResponse();
56
        }
57
58 3
        return $handler->handle($request);
59
    }
60
61 6
    private function createForbiddenResponse(): ResponseInterface
62
    {
63 6
        $response = $this->responseFactory->createResponse(Status::FORBIDDEN);
64 6
        $response->getBody()->write(Status::TEXTS[Status::FORBIDDEN]);
65
66 6
        return $response;
67
    }
68
}
69