Passed
Push — master ( ddbf8b...086098 )
by Robbie
11:17
created

Url::checkRequest()   B

Complexity

Conditions 11
Paths 8

Size

Total Lines 37
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 11
eloc 18
nc 8
nop 1
dl 0
loc 37
rs 7.3166
c 0
b 0
f 0

How to fix   Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace SilverStripe\Control\Middleware\ConfirmationMiddleware;
4
5
use SilverStripe\Control\HTTPRequest;
6
use SilverStripe\Security\Confirmation;
7
8
/**
9
 * A rule to match a particular URL
10
 */
11
class Url implements Rule, Bypass
12
{
13
    use PathAware;
14
15
    /**
16
     * The HTTP methods
17
     *
18
     * @var HttpMethodBypass
19
     */
20
    private $httpMethods;
21
22
    /**
23
     * The list of GET parameters URL should have to match
24
     *
25
     * @var array keys are parameter names, values are strings to match or null if any
26
     */
27
    private $params = null;
28
29
    /**
30
     * Initialize the rule with the parameters
31
     *
32
     * @param string $path url path to check for
33
     * @param string[]|string|null $httpMethods to match against
34
     * @param string[]|null $params a list of GET parameters
35
     */
36
    public function __construct($path, $httpMethods = null, $params = null)
37
    {
38
        $this->setPath($path);
39
        $this->setParams($params);
40
        $this->httpMethods = new HttpMethodBypass();
41
42
        if (is_array($httpMethods)) {
43
            $this->addHttpMethods(...$httpMethods);
44
        } elseif (!is_null($httpMethods)) {
45
            $this->addHttpMethods($httpMethods);
46
        }
47
    }
48
49
    /**
50
     * Add HTTP methods to check against
51
     *
52
     * @param string[] ...$methods
53
     *
54
     * @return $this
55
     */
56
    public function addHttpMethods(...$methods)
57
    {
58
        $this->httpMethods->addMethods(...$methods);
59
        return $this;
60
    }
61
62
    /**
63
     * Returns HTTP methods to be checked
64
     *
65
     * @return string[]
66
     */
67
    public function getHttpMethods()
68
    {
69
        return $this->httpMethods->getMethods();
70
    }
71
72
    /**
73
     * Set the GET parameters
74
     * null to skip parameter check
75
     *
76
     * If an array of parameters provided,
77
     * then URL should contain ALL of them and
78
     * ONLY them to match. If the values in the list
79
     * contain strings, those will be checked
80
     * against parameter values accordingly. Null
81
     * as a value in the array matches any parameter values.
82
     *
83
     * @param string|null $httpMethods
84
     *
85
     * @return $this
86
     */
87
    public function setParams($params = null)
88
    {
89
        $this->params = $params;
90
        return $this;
91
    }
92
93
    public function checkRequestForBypass(HTTPRequest $request)
94
    {
95
        return $this->checkRequest($request);
96
    }
97
98
    public function getRequestConfirmationItem(HTTPRequest $request)
99
    {
100
        if (!$this->checkRequest($request)) {
101
            return null;
102
        }
103
104
        $fullPath = $request->getURL(true);
105
        $token = $this->generateToken($request->httpMethod(), $fullPath);
106
107
        return $this->buildConfirmationItem($token, $fullPath);
108
    }
109
110
    /**
111
     * Match the request against the rules
112
     *
113
     * @param HTTPRequest $request
114
     *
115
     * @return bool
116
     */
117
    public function checkRequest(HTTPRequest $request)
118
    {
119
        $httpMethods = $this->getHttpMethods();
120
121
        if (count($httpMethods) && !in_array($request->httpMethod(), $httpMethods, true)) {
122
            return false;
123
        }
124
125
        if (!$this->checkPath($request->getURL())) {
126
            return false;
127
        }
128
129
        if (!is_null($this->params)) {
0 ignored issues
show
introduced by
The condition is_null($this->params) is always false.
Loading history...
130
            $getVars = $request->getVars();
131
132
            // compare the request parameters with the declared ones
133
            foreach ($this->params as $key => $val) {
134
                if (is_null($val)) {
135
                    $cmp = array_key_exists($key, $getVars);
136
                } else {
137
                    $cmp = isset($getVars[$key]) && $getVars[$key] === strval($val);
138
                }
139
140
                if (!$cmp) {
141
                    return false;
142
                }
143
            }
144
145
            // check only declared parameters exist in the request
146
            foreach ($getVars as $key => $val) {
147
                if (!array_key_exists($key, $this->params)) {
148
                    return false;
149
                }
150
            }
151
        }
152
153
        return true;
154
    }
155
156
    /**
157
     * Checks the given path by the rules and
158
     * returns true if it is matching
159
     *
160
     * @param string $path Path to be checked
161
     *
162
     * @return bool
163
     */
164
    protected function checkPath($path)
165
    {
166
        return $this->getPath() === $this->normalisePath($path);
167
    }
168
169
    /**
170
     * Generates the confirmation item
171
     *
172
     * @param string $token
173
     * @param string $url
174
     *
175
     * @return Confirmation\Item
176
     */
177
    protected function buildConfirmationItem($token, $url)
178
    {
179
        return new Confirmation\Item(
180
            $token,
181
            _t(__CLASS__.'.CONFIRMATION_NAME', 'URL is protected'),
182
            _t(__CLASS__.'.CONFIRMATION_DESCRIPTION', 'The URL is: "{url}"', ['url' => $url])
183
        );
184
    }
185
186
    /**
187
     * Generates the unique token depending on the path
188
     *
189
     * @param string $path URL path
190
     *
191
     * @return string
192
     */
193
    protected function generateToken($httpMethod, $path)
194
    {
195
        return sprintf('%s::%s|%s', static::class, $httpMethod, $path);
196
    }
197
}
198