This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | |||
3 | namespace Apiato\Core\Traits\TestsTraits\PhpUnit; |
||
4 | |||
5 | use Illuminate\Support\Arr; |
||
6 | use App\Ship\Exceptions\MissingTestEndpointException; |
||
7 | use App\Ship\Exceptions\UndefinedMethodException; |
||
8 | use App\Ship\Exceptions\WrongEndpointFormatException; |
||
9 | use Illuminate\Support\Facades\Config; |
||
10 | use Illuminate\Support\Str; |
||
11 | use Log; |
||
12 | use Vinkla\Hashids\Facades\Hashids; |
||
13 | |||
14 | /** |
||
15 | * Class TestsRequestHelperTrait |
||
16 | * |
||
17 | * Tests helper for making HTTP requests. |
||
18 | * |
||
19 | * @author Mahmoud Zalt <[email protected]> |
||
20 | */ |
||
21 | trait TestsRequestHelperTrait |
||
22 | { |
||
23 | |||
24 | /** |
||
25 | * property to be set on the user test class |
||
26 | * |
||
27 | * @var string |
||
28 | */ |
||
29 | protected $endpoint = ''; |
||
30 | |||
31 | /** |
||
32 | * property to be set on the user test class |
||
33 | * |
||
34 | * @var bool |
||
35 | */ |
||
36 | protected $auth = true; |
||
37 | |||
38 | /** |
||
39 | * Http response |
||
40 | * |
||
41 | * @var \Illuminate\Foundation\Testing\TestResponse |
||
42 | */ |
||
43 | protected $response; |
||
44 | |||
45 | /** |
||
46 | * @var string |
||
47 | */ |
||
48 | protected $responseContent; |
||
49 | |||
50 | /** |
||
51 | * @var array |
||
52 | */ |
||
53 | protected $responseContentArray; |
||
54 | |||
55 | /** |
||
56 | * @var \stdClass |
||
57 | */ |
||
58 | protected $responseContentObject; |
||
59 | |||
60 | /** |
||
61 | * Allows users to override the default class property `endpoint` directly before calling the `makeCall` function. |
||
62 | * |
||
63 | * @var string |
||
64 | */ |
||
65 | protected $overrideEndpoint; |
||
66 | |||
67 | /** |
||
68 | * Allows users to override the default class property `auth` directly before calling the `makeCall` function. |
||
69 | * |
||
70 | * @var string |
||
71 | */ |
||
72 | protected $overrideAuth; |
||
73 | |||
74 | /** |
||
75 | * @param array $data |
||
76 | * @param array $headers |
||
77 | * |
||
78 | * @throws \App\Ship\Exceptions\UndefinedMethodException |
||
79 | * |
||
80 | * @return \Illuminate\Foundation\Testing\TestResponse |
||
81 | */ |
||
82 | public function makeCall(array $data = [], array $headers = []) |
||
83 | { |
||
84 | // Get or create a testing user. It will get your existing user if you already called this function from your |
||
85 | // test. Or create one if you never called this function from your tests "Only if the endpoint is protected". |
||
86 | $this->getTestingUser(); |
||
0 ignored issues
–
show
|
|||
87 | |||
88 | // read the $endpoint property from the test and set the verb and the uri as properties on this trait |
||
89 | $endpoint = $this->parseEndpoint(); |
||
90 | $verb = $endpoint['verb']; |
||
91 | $url = $endpoint['url']; |
||
92 | |||
93 | // validating user http verb input + converting `get` data to query parameter |
||
94 | switch ($verb) { |
||
95 | case 'get': |
||
96 | $url = $this->dataArrayToQueryParam($data, $url); |
||
97 | break; |
||
98 | case 'post': |
||
99 | case 'put': |
||
100 | case 'patch': |
||
101 | case 'delete': |
||
102 | break; |
||
103 | default: |
||
104 | throw new UndefinedMethodException('Unsupported HTTP Verb (' . $verb . ')!'); |
||
105 | } |
||
106 | |||
107 | $httpResponse = $this->json($verb, $url, $data, $headers); |
||
0 ignored issues
–
show
It seems like
json() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
108 | |||
109 | $this->logResponseData($httpResponse); |
||
110 | |||
111 | return $this->setResponseObjectAndContent($httpResponse); |
||
112 | } |
||
113 | |||
114 | /** |
||
115 | * @param $httpResponse |
||
116 | * |
||
117 | * @return \Illuminate\Foundation\Testing\TestResponse |
||
118 | */ |
||
119 | public function setResponseObjectAndContent($httpResponse) |
||
120 | { |
||
121 | $this->setResponseContent($httpResponse); |
||
122 | |||
123 | return $this->response = $httpResponse; |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * @param $httpResponse |
||
128 | * |
||
129 | * @return mixed |
||
130 | */ |
||
131 | public function setResponseContent($httpResponse) |
||
132 | { |
||
133 | return $this->responseContent = $httpResponse->getContent(); |
||
134 | } |
||
135 | |||
136 | /** |
||
137 | * @return string |
||
138 | */ |
||
139 | public function getResponseContent() |
||
140 | { |
||
141 | return $this->responseContent; |
||
142 | } |
||
143 | |||
144 | /** |
||
145 | * @return mixed |
||
146 | */ |
||
147 | public function getResponseContentArray() |
||
148 | { |
||
149 | return $this->responseContentArray ? : $this->responseContentArray = json_decode($this->getResponseContent(), |
||
150 | true); |
||
151 | } |
||
152 | |||
153 | /** |
||
154 | * @return mixed |
||
155 | */ |
||
156 | public function getResponseContentObject() |
||
157 | { |
||
158 | return $this->responseContentObject ? : $this->responseContentObject = json_decode($this->getResponseContent(), |
||
159 | false); |
||
160 | } |
||
161 | |||
162 | /** |
||
163 | * Inject the ID in the Endpoint URI before making the call by |
||
164 | * overriding the `$this->endpoint` property |
||
165 | * |
||
166 | * Example: you give it ('users/{id}/stores', 100) it returns 'users/100/stores' |
||
167 | * |
||
168 | * @param $id |
||
169 | * @param bool $skipEncoding |
||
170 | * @param string $replace |
||
171 | * |
||
172 | * @return $this |
||
173 | */ |
||
174 | public function injectId($id, $skipEncoding = false, $replace = '{id}') |
||
175 | { |
||
176 | // In case Hash ID is enabled it will encode the ID first |
||
177 | $id = $this->hashEndpointId($id, $skipEncoding); |
||
178 | $this->endpoint = str_replace($replace, $id, $this->endpoint); |
||
179 | |||
180 | return $this; |
||
181 | } |
||
182 | |||
183 | /** |
||
184 | * Override the default class endpoint property before making the call |
||
185 | * |
||
186 | * to be used as follow: $this->endpoint('[email protected]')->makeCall($data); |
||
187 | * |
||
188 | * @param $endpoint |
||
189 | * |
||
190 | * @return $this |
||
191 | */ |
||
192 | public function endpoint($endpoint) |
||
193 | { |
||
194 | $this->overrideEndpoint = $endpoint; |
||
195 | |||
196 | return $this; |
||
197 | } |
||
198 | |||
199 | /** |
||
200 | * @return string |
||
201 | */ |
||
202 | public function getEndpoint() |
||
203 | { |
||
204 | return !is_null($this->overrideEndpoint) ? $this->overrideEndpoint : $this->endpoint; |
||
205 | } |
||
206 | |||
207 | /** |
||
208 | * Override the default class auth property before making the call |
||
209 | * |
||
210 | * to be used as follow: $this->auth('false')->makeCall($data); |
||
211 | * |
||
212 | * @param bool $auth |
||
213 | * |
||
214 | * @return $this |
||
215 | */ |
||
216 | public function auth(bool $auth) |
||
217 | { |
||
218 | $this->overrideAuth = $auth; |
||
0 ignored issues
–
show
The property
$overrideAuth was declared of type string , but $auth is of type boolean . Maybe add a type cast?
This check looks for assignments to scalar types that may be of the wrong type. To ensure the code behaves as expected, it may be a good idea to add an explicit type cast. $answer = 42;
$correct = false;
$correct = (bool) $answer;
![]() |
|||
219 | |||
220 | return $this; |
||
221 | } |
||
222 | |||
223 | /** |
||
224 | * @return bool |
||
225 | */ |
||
226 | public function getAuth() |
||
227 | { |
||
228 | return !is_null($this->overrideAuth) ? $this->overrideAuth : $this->auth; |
||
229 | } |
||
230 | |||
231 | /** |
||
232 | * @param $uri |
||
233 | * |
||
234 | * @return string |
||
235 | */ |
||
236 | private function buildUrlForUri($uri) |
||
237 | { |
||
238 | // add `/` at the beginning in case it doesn't exist |
||
239 | if (!Str::startsWith($uri, '/')) { |
||
240 | $uri = '/' . $uri; |
||
241 | } |
||
242 | |||
243 | return Config::get('apiato.api.url') . $uri; |
||
244 | } |
||
245 | |||
246 | /** |
||
247 | * Attach Authorization Bearer Token to the request headers |
||
248 | * if it does not exist already and the authentication is required |
||
249 | * for the endpoint `$this->auth = true`. |
||
250 | * |
||
251 | * @param $headers |
||
252 | * |
||
253 | * @return mixed |
||
254 | */ |
||
255 | private function injectAccessToken(array $headers = []) |
||
0 ignored issues
–
show
|
|||
256 | { |
||
257 | // if endpoint is protected (requires token to access it's functionality) |
||
258 | if ($this->getAuth() && !$this->headersContainAuthorization($headers)) { |
||
259 | // append the token to the header |
||
260 | $headers['Authorization'] = 'Bearer ' . $this->getTestingUser()->token; |
||
0 ignored issues
–
show
It seems like
getTestingUser() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
261 | } |
||
262 | |||
263 | return $headers; |
||
264 | } |
||
265 | |||
266 | /** |
||
267 | * just check if headers array has an `Authorization` as key. |
||
268 | * |
||
269 | * @param $headers |
||
270 | * |
||
271 | * @return bool |
||
272 | */ |
||
273 | private function headersContainAuthorization($headers) |
||
274 | { |
||
275 | return Arr::has($headers, 'Authorization'); |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * @param $data |
||
280 | * @param $url |
||
281 | * |
||
282 | * @return string |
||
283 | */ |
||
284 | private function dataArrayToQueryParam($data, $url) |
||
285 | { |
||
286 | return $data ? $url . '?' . http_build_query($data) : $url; |
||
287 | } |
||
288 | |||
289 | /** |
||
290 | * @param $text |
||
291 | * |
||
292 | * @return string |
||
293 | */ |
||
294 | private function getJsonVerb($text) |
||
0 ignored issues
–
show
|
|||
295 | { |
||
296 | return Str::replaceFirst('json:', '', $text); |
||
297 | } |
||
298 | |||
299 | |||
300 | /** |
||
301 | * @param $id |
||
302 | * @param bool $skipEncoding |
||
303 | * |
||
304 | * @return mixed |
||
305 | */ |
||
306 | private function hashEndpointId($id, $skipEncoding = false) |
||
307 | { |
||
308 | return (Config::get('apiato.hash-id') && !$skipEncoding) ? Hashids::encode($id) : $id; |
||
309 | } |
||
310 | |||
311 | /** |
||
312 | * read `$this->endpoint` property from the test class (`[email protected]`) and convert it to usable data |
||
313 | * |
||
314 | * @return array |
||
315 | */ |
||
316 | private function parseEndpoint() |
||
317 | { |
||
318 | $this->validateEndpointExist(); |
||
319 | |||
320 | $separator = '@'; |
||
321 | |||
322 | $this->validateEndpointFormat($separator); |
||
323 | |||
324 | // convert the string to array |
||
325 | $asArray = explode($separator, $this->getEndpoint(), 2); |
||
326 | |||
327 | // get the verb and uri values from the array |
||
328 | extract(array_combine(['verb', 'uri'], $asArray)); |
||
0 ignored issues
–
show
|
|||
329 | /** @var TYPE_NAME $verb */ |
||
330 | /** @var TYPE_NAME $uri */ |
||
331 | |||
332 | return [ |
||
333 | 'verb' => $verb, |
||
334 | 'uri' => $uri, |
||
335 | 'url' => $this->buildUrlForUri($uri), |
||
336 | ]; |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * @void |
||
341 | */ |
||
342 | private function validateEndpointExist() |
||
343 | { |
||
344 | if (!$this->getEndpoint()) { |
||
345 | throw new MissingTestEndpointException(); |
||
346 | } |
||
347 | } |
||
348 | |||
349 | /** |
||
350 | * @param $separator |
||
351 | * |
||
352 | * @throws WrongEndpointFormatException |
||
353 | */ |
||
354 | private function validateEndpointFormat($separator) |
||
355 | { |
||
356 | // check if string contains the separator |
||
357 | if (!strpos($this->getEndpoint(), $separator)) { |
||
358 | throw new WrongEndpointFormatException(); |
||
359 | } |
||
360 | } |
||
361 | |||
362 | /** |
||
363 | * Transform headers array to array of $_SERVER vars with HTTP_* format. |
||
364 | * |
||
365 | * @param array $headers |
||
366 | * |
||
367 | * @return array |
||
368 | */ |
||
369 | protected function transformHeadersToServerVars(array $headers) |
||
370 | { |
||
371 | return collect($headers)->mapWithKeys(function ($value, $name) { |
||
372 | $name = strtr(strtoupper($name), '-', '_'); |
||
373 | |||
374 | return [$this->formatServerHeaderKey($name) => $value]; |
||
0 ignored issues
–
show
It seems like
formatServerHeaderKey() must be provided by classes using this trait. How about adding it as abstract method to this trait?
This check looks for methods that are used by a trait but not required by it. To illustrate, let’s look at the following code example trait Idable {
public function equalIds(Idable $other) {
return $this->getId() === $other->getId();
}
}
The trait Adding the ![]() |
|||
375 | })->all(); |
||
376 | } |
||
377 | |||
378 | /** |
||
379 | * @param \Illuminate\Testing\TestResponse $httpResponse |
||
380 | */ |
||
381 | private function logResponseData($httpResponse) |
||
382 | { |
||
383 | $responseLoggerEnabled = Config::get('debugger.tests.response_logger'); |
||
384 | |||
385 | if($responseLoggerEnabled){ |
||
386 | Log::notice(get_object_vars($httpResponse->getData())); |
||
387 | } |
||
388 | } |
||
389 | |||
390 | } |
||
391 |
This check looks for methods that are used by a trait but not required by it.
To illustrate, let’s look at the following code example
The trait
Idable
provides a methodequalsId
that in turn relies on the methodgetId()
. If this method does not exist on a class mixing in this trait, the method will fail.Adding the
getId()
as an abstract method to the trait will make sure it is available.