BannedUserAgentHeaderFilter::__invoke()   A
last analyzed

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 10
CRAP Score 4

Importance

Changes 0
Metric Value
eloc 9
dl 0
loc 22
ccs 10
cts 10
cp 1
rs 9.9666
c 0
b 0
f 0
cc 4
nc 4
nop 1
crap 4
1
<?php
2
3
declare(strict_types=1);
4
5
namespace DanBettles\Defence\Filter;
6
7
use DanBettles\Defence\Envelope;
8
use InvalidArgumentException;
9
10
use function is_array;
11
use function is_string;
12
use function preg_match;
13
14
use const false;
15
use const null;
16
use const true;
17
18
/**
19
 * Rejects requests containing the specified user-agent string(s).
20
 *
21
 * Apparently, some malicious users don't know/think to change the user-agent string in their scripts, so this filter
22
 * can be used to quickly reject probing/harmful requests--requests sent via unusual user agents.  Commercial
23
 * screen-scraping apps identify themselves, and experienced programmers know to use a sensible user-agent string when
24
 * working with tools like cURL.
25
 *
26
 * @phpstan-import-type IncomingFilterOptions from \DanBettles\Defence\Filter\AbstractFilter
27
 *
28
 * @phpstan-type Selector string|string[]
29
 */
30
class BannedUserAgentHeaderFilter extends AbstractFilter
31
{
32
    /**
33
     * @phpstan-var Selector
34
     */
35
    private $selector;
36
37
    /**
38
     * @phpstan-param Selector $selector  One/more regular expressions.
39
     * @phpstan-param IncomingFilterOptions $options
40
     */
41 16
    public function __construct($selector, array $options = [])
42
    {
43 16
        parent::__construct($options);
44
45 16
        $this->setSelector($selector);
46
    }
47
48 12
    public function __invoke(Envelope $envelope): bool
49
    {
50 12
        $request = $envelope->getRequest();
51
        /** @var string|null Contrary to what Scrutinizer thinks */
52 12
        $uaString = /** @scrutinizer ignore-type */ $request->headers->get('User-Agent');
53
54 12
        if (null === $uaString) {
0 ignored issues
show
introduced by
The condition null === $uaString is always false.
Loading history...
55
            // Since there's no user-agent header, we have nothing to check against our blacklist.  *In this context*,
56
            // then, we have to treat the request as not suspicious -- even though it *is* suspicious that there's no
57
            // user-agent header.
58 2
            return false;
59
        }
60
61 10
        foreach ((array) $this->getSelector() as $selector) {
62 10
            if (preg_match($selector, $uaString)) {
63 6
                $this->envelopeAddLogEntry($envelope, 'The request was made via a banned user agent.');
64
65 6
                return true;
66
            }
67
        }
68
69 4
        return false;
70
    }
71
72
    /**
73
     * @phpstan-param Selector $selector  One/more regular expressions.
74
     * @throws InvalidArgumentException If the selector is invalid
75
     */
76 16
    private function setSelector($selector): self
77
    {
78
        if (
79 16
            empty($selector)
80
            /** @phpstan-ignore-next-line */
81 16
            || (!is_array($selector) && !is_string($selector))
82
        ) {
83 4
            throw new InvalidArgumentException('The selector is invalid');
84
        }
85
86 12
        $this->selector = $selector;
87
88 12
        return $this;
89
    }
90
91
    /**
92
     * @phpstan-return Selector
93
     */
94 10
    public function getSelector()
95
    {
96 10
        return $this->selector;
97
    }
98
}
99