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 | /* |
||
4 | * This file is part of the Pushok package. |
||
5 | * |
||
6 | * (c) Arthur Edamov <[email protected]> |
||
7 | * |
||
8 | * For the full copyright and license information, please view the LICENSE |
||
9 | * file that was distributed with this source code. |
||
10 | */ |
||
11 | |||
12 | namespace Pushok; |
||
13 | |||
14 | use Countable; |
||
15 | use Pushok\Payload\Alert; |
||
16 | use Pushok\Payload\Sound; |
||
17 | |||
18 | // Polyfill for PHP 7.2 |
||
19 | if (!function_exists('is_countable')) { |
||
20 | function is_countable($var) |
||
21 | { |
||
22 | return (is_array($var) || $var instanceof Countable); |
||
23 | } |
||
24 | } |
||
25 | |||
26 | /** |
||
27 | * Class Payload |
||
28 | * |
||
29 | * @package Pushok |
||
30 | * |
||
31 | * @see http://bit.ly/payload-key-reference |
||
32 | */ |
||
33 | class Payload implements \JsonSerializable |
||
34 | { |
||
35 | const PAYLOAD_ROOT_KEY = 'aps'; |
||
36 | const PAYLOAD_ALERT_KEY = 'alert'; |
||
37 | const PAYLOAD_BADGE_KEY = 'badge'; |
||
38 | const PAYLOAD_SOUND_KEY = 'sound'; |
||
39 | const PAYLOAD_CONTENT_AVAILABLE_KEY = 'content-available'; |
||
40 | const PAYLOAD_MUTABLE_CONTENT_KEY = 'mutable-content'; |
||
41 | const PAYLOAD_CATEGORY_KEY = 'category'; |
||
42 | const PAYLOAD_THREAD_ID_KEY = 'thread-id'; |
||
43 | const PAYLOAD_URL_ARGS_KEY = 'url-args'; |
||
44 | |||
45 | const PAYLOAD_HTTP2_REGULAR_NOTIFICATION_MAXIMUM_SIZE = 4096; |
||
46 | const PAYLOAD_HTTP2_VOIP_NOTIFICATION_MAXIMUM_SIZE = 5120; |
||
47 | const PAYLOAD_BINARY_REGULAR_NOTIFICATION_MAXIMUM_SIZE = 2048; |
||
48 | |||
49 | |||
50 | /** |
||
51 | * The notification settings for your app on the user’s device determine whether an alert or banner is displayed. |
||
52 | * |
||
53 | * @var Alert|string |
||
54 | */ |
||
55 | private $alert; |
||
56 | |||
57 | /** |
||
58 | * The number to display as the badge of the app icon. |
||
59 | * If this property is absent, the badge is not changed. |
||
60 | * |
||
61 | * @var int |
||
62 | */ |
||
63 | private $badge; |
||
64 | |||
65 | /** |
||
66 | * The name of a sound file in the app bundle or in the Library/Sounds folder of the app’s data container. |
||
67 | * |
||
68 | * @var Sound|string |
||
69 | */ |
||
70 | private $sound; |
||
71 | |||
72 | /** |
||
73 | * Include this key with a value of true to configure a silent notification. |
||
74 | * |
||
75 | * @var bool |
||
76 | */ |
||
77 | private $contentAvailable; |
||
78 | |||
79 | /** |
||
80 | * Include this key with a value of true to configure a mutable content notification. |
||
81 | * |
||
82 | * @var bool |
||
83 | */ |
||
84 | private $mutableContent; |
||
85 | |||
86 | /** |
||
87 | * Provide this key with a string value that represents the notification’s type. |
||
88 | * |
||
89 | * @var string |
||
90 | */ |
||
91 | private $category; |
||
92 | |||
93 | /** |
||
94 | * Provide this key with a string value that represents the app-specific identifier for grouping notifications. |
||
95 | * |
||
96 | * @var string |
||
97 | */ |
||
98 | private $threadId; |
||
99 | |||
100 | /** |
||
101 | * Provide this key with an array value that represents the url-args for Safari notifications. |
||
102 | * |
||
103 | * @var string |
||
104 | */ |
||
105 | private $urlArgs; |
||
106 | |||
107 | /** |
||
108 | * Payload custom values. |
||
109 | * |
||
110 | * @var array |
||
111 | */ |
||
112 | private $customValues; |
||
113 | |||
114 | /** |
||
115 | * Push notification type |
||
116 | * |
||
117 | * https://developer.apple.com/documentation/usernotifications/setting_up_a_remote_notification_server/sending_notification_requests_to_apns#2947607 |
||
118 | * |
||
119 | * @var string |
||
120 | */ |
||
121 | private $pushType; |
||
122 | |||
123 | protected function __construct() |
||
124 | { |
||
125 | } |
||
126 | |||
127 | /** |
||
128 | * @return Payload |
||
129 | */ |
||
130 | public static function create(): Payload |
||
131 | { |
||
132 | return new self(); |
||
133 | } |
||
134 | |||
135 | /** |
||
136 | * Get Alert. |
||
137 | * |
||
138 | * @return Alert|string|array|null |
||
139 | */ |
||
140 | public function getAlert() |
||
141 | { |
||
142 | return $this->alert; |
||
143 | } |
||
144 | |||
145 | /** |
||
146 | * Set Alert. |
||
147 | * |
||
148 | * @param Alert|string $alert|array $alert |
||
149 | * |
||
150 | * @return Payload |
||
151 | */ |
||
152 | public function setAlert($alert): Payload |
||
153 | { |
||
154 | if ($alert instanceof Alert || is_string($alert) || is_array($alert)) { |
||
155 | $this->alert = $alert; |
||
0 ignored issues
–
show
|
|||
156 | } |
||
157 | |||
158 | return $this; |
||
159 | } |
||
160 | |||
161 | /** |
||
162 | * Get badge. |
||
163 | * |
||
164 | * @return int|null |
||
165 | */ |
||
166 | public function getBadge() |
||
167 | { |
||
168 | return $this->badge; |
||
169 | } |
||
170 | |||
171 | /** |
||
172 | * Set badge. |
||
173 | * |
||
174 | * @param int $value |
||
175 | * |
||
176 | * @return Payload |
||
177 | */ |
||
178 | public function setBadge(int $value): Payload |
||
179 | { |
||
180 | $this->badge = $value; |
||
181 | |||
182 | return $this; |
||
183 | } |
||
184 | |||
185 | /** |
||
186 | * Get sound. |
||
187 | * |
||
188 | * @return string|null |
||
189 | */ |
||
190 | public function getSound() |
||
191 | { |
||
192 | return $this->sound; |
||
193 | } |
||
194 | |||
195 | /** |
||
196 | * Set sound. |
||
197 | * |
||
198 | * @param Sound|string $sound |
||
199 | * |
||
200 | * @return Payload |
||
201 | */ |
||
202 | public function setSound($sound): Payload |
||
203 | { |
||
204 | if ($sound instanceof Sound || is_string($sound)) { |
||
205 | $this->sound = $sound; |
||
206 | } |
||
207 | |||
208 | return $this; |
||
209 | } |
||
210 | |||
211 | /** |
||
212 | * Set content availability. |
||
213 | * |
||
214 | * @param bool $value |
||
215 | * |
||
216 | * @return Payload |
||
217 | */ |
||
218 | public function setContentAvailability(bool $value): Payload |
||
219 | { |
||
220 | $this->contentAvailable = $value; |
||
221 | |||
222 | return $this; |
||
223 | } |
||
224 | |||
225 | /** |
||
226 | * Get content availability. |
||
227 | * |
||
228 | * @return bool|null |
||
229 | */ |
||
230 | public function isContentAvailable() |
||
231 | { |
||
232 | return $this->contentAvailable; |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Set the mutable-content key for Notification Service Extensions on iOS10. |
||
237 | * |
||
238 | * @see http://bit.ly/mutable-content |
||
239 | * |
||
240 | * @param bool $value |
||
241 | * |
||
242 | * @return Payload |
||
243 | */ |
||
244 | public function setMutableContent(bool $value): Payload |
||
245 | { |
||
246 | $this->mutableContent = $value; |
||
247 | |||
248 | return $this; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Is content mutable. |
||
253 | * |
||
254 | * @return bool|null |
||
255 | */ |
||
256 | public function hasMutableContent() |
||
257 | { |
||
258 | return $this->mutableContent; |
||
259 | } |
||
260 | |||
261 | /** |
||
262 | * Get category. |
||
263 | * |
||
264 | * @return string|null |
||
265 | */ |
||
266 | public function getCategory() |
||
267 | { |
||
268 | return $this->category; |
||
269 | } |
||
270 | |||
271 | /** |
||
272 | * Set category. |
||
273 | * |
||
274 | * @param string $value |
||
275 | * |
||
276 | * @return Payload |
||
277 | */ |
||
278 | public function setCategory(string $value): Payload |
||
279 | { |
||
280 | $this->category = $value; |
||
281 | |||
282 | return $this; |
||
283 | } |
||
284 | |||
285 | /** |
||
286 | * Get thread-id. |
||
287 | * |
||
288 | * @return string|null |
||
289 | */ |
||
290 | public function getThreadId() |
||
291 | { |
||
292 | return $this->threadId; |
||
293 | } |
||
294 | |||
295 | /** |
||
296 | * Set thread-id. |
||
297 | * |
||
298 | * @param string $value |
||
299 | * |
||
300 | * @return Payload |
||
301 | */ |
||
302 | public function setThreadId(string $value): Payload |
||
303 | { |
||
304 | $this->threadId = $value; |
||
305 | |||
306 | return $this; |
||
307 | } |
||
308 | |||
309 | /** |
||
310 | * Get url-args. |
||
311 | * |
||
312 | * @return array|null |
||
313 | */ |
||
314 | public function getUrlArgs() |
||
315 | { |
||
316 | return $this->urlArgs; |
||
317 | } |
||
318 | |||
319 | /** |
||
320 | * Set url-args. |
||
321 | * |
||
322 | * @param array $value |
||
323 | * |
||
324 | * @return Payload |
||
325 | */ |
||
326 | public function setUrlArgs(array $value): Payload |
||
327 | { |
||
328 | $this->urlArgs = $value; |
||
329 | |||
330 | return $this; |
||
331 | } |
||
332 | |||
333 | /** |
||
334 | * Set custom value for Payload. |
||
335 | * |
||
336 | * @param string $key |
||
337 | * @param mixed $value |
||
338 | * |
||
339 | * @return Payload |
||
340 | * @throws InvalidPayloadException |
||
341 | */ |
||
342 | public function setCustomValue(string $key, $value): Payload |
||
343 | { |
||
344 | if ($key === self::PAYLOAD_ROOT_KEY) { |
||
345 | throw InvalidPayloadException::reservedKey(); |
||
346 | } |
||
347 | |||
348 | $this->customValues[$key] = $value; |
||
349 | |||
350 | return $this; |
||
351 | } |
||
352 | |||
353 | /** |
||
354 | * Merges custom value for Payload. |
||
355 | * |
||
356 | * @param string $key |
||
357 | * @param mixed $value |
||
358 | * |
||
359 | * @return Payload |
||
360 | * @throws InvalidPayloadException |
||
361 | */ |
||
362 | public function addCustomValue(string $key, $value): Payload |
||
363 | { |
||
364 | $this->customValues = array_merge_recursive($this->customValues ? $this->customValues : [], [$key => $value]); |
||
365 | |||
366 | return $this; |
||
367 | } |
||
368 | |||
369 | /** |
||
370 | * Get custom value. |
||
371 | * |
||
372 | * @param $key |
||
373 | * |
||
374 | * @return mixed |
||
375 | * @throws InvalidPayloadException |
||
376 | */ |
||
377 | public function getCustomValue($key) |
||
378 | { |
||
379 | if (!array_key_exists($key, $this->customValues)) { |
||
380 | throw InvalidPayloadException::notExistingCustomValue($key); |
||
381 | } |
||
382 | |||
383 | return $this->customValues[$key]; |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * Set push type for Payload. |
||
388 | * |
||
389 | * @param string $pushType |
||
390 | * @return Payload |
||
391 | */ |
||
392 | public function setPushType($pushType) { |
||
393 | $this->pushType = $pushType; |
||
394 | |||
395 | return $this; |
||
396 | } |
||
397 | |||
398 | /** |
||
399 | * Get push type for Payload. |
||
400 | * |
||
401 | * @return string |
||
402 | */ |
||
403 | public function getPushType() { |
||
404 | return $this->pushType; |
||
405 | } |
||
406 | |||
407 | /** |
||
408 | * Convert Payload to JSON. |
||
409 | * |
||
410 | * @return string |
||
411 | */ |
||
412 | public function toJson(): string |
||
413 | { |
||
414 | $str = json_encode($this, JSON_UNESCAPED_UNICODE); |
||
415 | |||
416 | $this->checkPayloadSize($str); |
||
417 | |||
418 | return $str; |
||
419 | } |
||
420 | |||
421 | /** |
||
422 | * Specify data which should be serialized to JSON. |
||
423 | * |
||
424 | * @return array |
||
425 | * @link http://php.net/manual/en/jsonserializable.jsonserialize.php |
||
426 | */ |
||
427 | public function jsonSerialize() |
||
428 | { |
||
429 | $payload = self::getDefaultPayloadStructure(); |
||
430 | |||
431 | if ($this->alert instanceof Alert) { |
||
432 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_ALERT_KEY} = $this->alert; |
||
433 | } elseif(is_string($this->alert)){ |
||
434 | $json = json_decode($this->alert, true); |
||
435 | if($json){ |
||
436 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_ALERT_KEY} = $json; |
||
437 | } else { |
||
438 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_ALERT_KEY} = $this->alert; |
||
439 | } |
||
440 | } elseif (is_array($this->alert)){ |
||
441 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_ALERT_KEY} = $this->alert; |
||
442 | } |
||
443 | |||
444 | if (is_int($this->badge)) { |
||
445 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_BADGE_KEY} = $this->badge; |
||
446 | } |
||
447 | |||
448 | if ($this->sound instanceof Sound || is_string($this->sound)) { |
||
449 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_SOUND_KEY} = $this->sound; |
||
450 | } |
||
451 | |||
452 | if (is_bool($this->contentAvailable)) { |
||
453 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_CONTENT_AVAILABLE_KEY} = (int)$this->contentAvailable; |
||
454 | } |
||
455 | |||
456 | if (is_bool($this->mutableContent)) { |
||
457 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_MUTABLE_CONTENT_KEY} = (int)$this->mutableContent; |
||
458 | } |
||
459 | |||
460 | if (is_string($this->category)) { |
||
461 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_CATEGORY_KEY} = $this->category; |
||
462 | } |
||
463 | |||
464 | if (is_string($this->threadId)) { |
||
465 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_THREAD_ID_KEY} = $this->threadId; |
||
466 | } |
||
467 | |||
468 | if (is_array($this->urlArgs)) { |
||
469 | $payload[self::PAYLOAD_ROOT_KEY]->{self::PAYLOAD_URL_ARGS_KEY} = $this->urlArgs; |
||
470 | } |
||
471 | |||
472 | if (is_countable($this->customValues) && count($this->customValues)) { |
||
473 | $payload = array_merge($payload, $this->customValues); |
||
474 | } |
||
475 | |||
476 | return $payload; |
||
477 | } |
||
478 | |||
479 | /** |
||
480 | * Get default payload structure. |
||
481 | * |
||
482 | * @return array |
||
483 | */ |
||
484 | private static function getDefaultPayloadStructure() |
||
485 | { |
||
486 | return [self::PAYLOAD_ROOT_KEY => new \stdClass]; |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * @param $jsonPayload |
||
491 | * @return void |
||
492 | * @throws InvalidPayloadException |
||
493 | */ |
||
494 | private function checkPayloadSize($jsonPayload) |
||
495 | { |
||
496 | $strLength = strlen($jsonPayload); |
||
497 | if ('voip' === $this->getPushType()) { |
||
498 | if ($strLength > self::PAYLOAD_HTTP2_VOIP_NOTIFICATION_MAXIMUM_SIZE) { |
||
499 | throw new InvalidPayloadException('Voip Payload size limit exceeded'); |
||
500 | } |
||
501 | } elseif ($strLength > self::PAYLOAD_HTTP2_REGULAR_NOTIFICATION_MAXIMUM_SIZE) { |
||
502 | throw new InvalidPayloadException('Payload size limit exceeded'); |
||
503 | } |
||
504 | } |
||
505 | } |
||
506 |
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.