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 | namespace PHPDaemon\Clients\XMPP; |
||
3 | |||
4 | use PHPDaemon\Traits\EventHandlers; |
||
5 | |||
6 | class XMPPRoster |
||
7 | { |
||
8 | use EventHandlers; |
||
9 | use \PHPDaemon\Traits\ClassWatchdog; |
||
10 | use \PHPDaemon\Traits\StaticObjectWatchdog; |
||
11 | |||
12 | /** |
||
13 | * @var Connection |
||
14 | */ |
||
15 | public $xmpp; |
||
16 | |||
17 | /** |
||
18 | * @var array |
||
19 | */ |
||
20 | public $roster_array = []; |
||
21 | |||
22 | /** |
||
23 | * @var boolean |
||
24 | */ |
||
25 | public $track_presence = true; |
||
26 | |||
27 | /** |
||
28 | * @var boolean |
||
29 | */ |
||
30 | public $auto_subscribe = true; |
||
31 | |||
32 | /** |
||
33 | * @var string |
||
34 | */ |
||
35 | public $ns = 'jabber:iq:roster'; |
||
36 | |||
37 | /** |
||
38 | * Constructor |
||
39 | * @param Connection $xmpp |
||
40 | */ |
||
41 | public function __construct($xmpp) |
||
42 | { |
||
43 | $this->xmpp = $xmpp; |
||
44 | |||
45 | $this->xmpp->xml->addXPathHandler('{jabber:client}presence', function ($xml) { |
||
46 | $payload = []; |
||
47 | $payload['type'] = (isset($xml->attrs['type'])) ? $xml->attrs['type'] : 'available'; |
||
48 | $payload['show'] = (isset($xml->sub('show')->data)) ? $xml->sub('show')->data : $payload['type']; |
||
49 | $payload['from'] = $xml->attrs['from']; |
||
50 | $payload['status'] = (isset($xml->sub('status')->data)) ? $xml->sub('status')->data : ''; |
||
51 | $payload['priority'] = (isset($xml->sub('priority')->data)) ? intval($xml->sub('priority')->data) : 0; |
||
52 | $payload['xml'] = $xml; |
||
53 | if (($payload['from'] === $this->xmpp->fulljid) && $payload['type'] === 'unavailable') { |
||
54 | $this->xmpp->finish(); |
||
55 | } |
||
56 | if ($this->track_presence) { |
||
57 | $this->setPresence($payload['from'], $payload['priority'], $payload['show'], $payload['status']); |
||
58 | } |
||
59 | //Daemon::log("Presence: {$payload['from']} [{$payload['show']}] {$payload['status']}"); |
||
60 | if (array_key_exists('type', $xml->attrs) and $xml->attrs['type'] === 'subscribe') { |
||
61 | if ($this->auto_subscribe) { |
||
62 | $this->xmpp->sendXML("<presence type='subscribed' to='{$xml->attrs['from']}' from='{$this->xmpp->fulljid}' />"); |
||
63 | $this->xmpp->sendXML("<presence type='subscribe' to='{$xml->attrs['from']}' from='{$this->xmpp->fulljid}' />"); |
||
64 | } |
||
65 | $this->event('subscription_requested', $payload); |
||
66 | } elseif (array_key_exists('type', $xml->attrs) and $xml->attrs['type'] === 'subscribed') { |
||
67 | $this->event('subscription_accepted', $payload); |
||
68 | } else { |
||
69 | $this->event('presence', $payload); |
||
70 | } |
||
71 | }); |
||
72 | $this->fetch(); |
||
73 | } |
||
74 | |||
75 | /** |
||
76 | * Set presence |
||
77 | * @param string $presence |
||
78 | * @param integer $priority |
||
79 | * @param string $show |
||
80 | * @param string $status |
||
81 | */ |
||
82 | public function setPresence($presence, $priority, $show, $status) |
||
83 | { |
||
84 | list($jid, $resource) = explode('/', $presence . '/'); |
||
85 | if ($show !== 'unavailable') { |
||
86 | if (!$this->isContact($jid)) { |
||
87 | $this->_addContact($jid, 'not-in-roster'); |
||
88 | } |
||
89 | $this->roster_array[$jid]['presence'][$resource] = [ |
||
90 | 'priority' => $priority, |
||
91 | 'show' => $show, |
||
92 | 'status' => $status |
||
93 | ]; |
||
94 | } else { //Nuke unavailable resources to save memory |
||
95 | unset($this->roster_array[$jid]['resource'][$resource]); |
||
96 | } |
||
97 | } |
||
98 | |||
99 | /** |
||
100 | * Discover if a contact exists in the roster via jid |
||
101 | * @param string $jid |
||
102 | * @return boolean |
||
103 | */ |
||
104 | public function isContact($jid) |
||
105 | { |
||
106 | return array_key_exists($jid, $this->roster_array); |
||
107 | } |
||
108 | |||
109 | /** |
||
110 | * Add given contact to roster |
||
111 | * @param string $jid |
||
112 | * @param string $subscription |
||
113 | * @param string $name |
||
114 | * @param array $groups |
||
115 | */ |
||
116 | public function _addContact($jid, $subscription, $name = '', $groups = []) |
||
117 | { |
||
118 | $contact = ['jid' => $jid, 'subscription' => $subscription, 'name' => $name, 'groups' => $groups]; |
||
119 | if ($this->isContact($jid)) { |
||
120 | $this->roster_array[$jid]['contact'] = $contact; |
||
121 | } else { |
||
122 | $this->roster_array[$jid] = ['contact' => $contact]; |
||
123 | } |
||
124 | } |
||
125 | |||
126 | /** |
||
127 | * @TODO |
||
128 | * @param callable $cb |
||
0 ignored issues
–
show
|
|||
129 | * @callback $cb ( ) |
||
130 | */ |
||
131 | public function fetch($cb = null) |
||
132 | { |
||
133 | $this->xmpp->queryGet($this->ns, function ($xml) use ($cb) { |
||
134 | $status = "result"; |
||
135 | $xmlroster = $xml->sub('query'); |
||
136 | $contacts = []; |
||
137 | foreach ($xmlroster->subs as $item) { |
||
138 | $groups = []; |
||
139 | if ($item->name === 'item') { |
||
140 | $jid = $item->attrs['jid']; //REQUIRED |
||
141 | $name = isset($item->attrs['name']) ? $item->attrs['name'] : ''; //MAY |
||
142 | $subscription = $item->attrs['subscription']; |
||
143 | foreach ($item->subs as $subitem) { |
||
144 | if ($subitem->name === 'group') { |
||
145 | $groups[] = $subitem->data; |
||
146 | } |
||
147 | } |
||
148 | $contacts[] = [$jid, $subscription, $name, $groups]; //Store for action if no errors happen |
||
149 | } else { |
||
150 | $status = 'error'; |
||
151 | } |
||
152 | } |
||
153 | if ($status === 'result') { //No errors, add contacts |
||
154 | foreach ($contacts as $contact) { |
||
155 | $this->_addContact($contact[0], $contact[1], $contact[2], $contact[3]); |
||
156 | } |
||
157 | } |
||
158 | if ($xml->attrs['type'] === 'set') { |
||
159 | $this->xmpp->sendXML('<iq type="reply" id="' . $xml->attrs['id'] . '" to="' . $xml->attrs['from'] . '" />'); |
||
160 | } |
||
161 | if ($cb) { |
||
162 | $cb($status); |
||
163 | } |
||
164 | }); |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * @TODO |
||
169 | * @param string $jid |
||
170 | * @param string $type |
||
171 | * @param callable $cb |
||
0 ignored issues
–
show
Should the type for parameter
$cb not be callable|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
172 | * @callback $cb ( ) |
||
173 | */ |
||
174 | public function setSubscription($jid, $type, $cb = null) |
||
175 | { |
||
176 | $this->rosterSet('<item jid="' . htmlspecialchars($jid) . '" subscription="' . htmlspecialchars($type) . '" />', |
||
177 | $cb); |
||
178 | } |
||
179 | |||
180 | /** |
||
181 | * @TODO |
||
182 | * @param string $xml |
||
183 | * @param callable $cb |
||
0 ignored issues
–
show
Should the type for parameter
$cb not be callable|null ?
This check looks for It makes a suggestion as to what type it considers more descriptive. Most often this is a case of a parameter that can be null in addition to its declared types. ![]() |
|||
184 | * @callback $cb ( ) |
||
185 | */ |
||
186 | public function rosterSet($xml, $cb = null) |
||
187 | { |
||
188 | $this->xmpp->querySetTo($this->xmpp->fulljid, $this->ns, $xml, $cb); |
||
0 ignored issues
–
show
It seems like
$cb defined by parameter $cb on line 186 can also be of type null ; however, PHPDaemon\Clients\XMPP\Connection::querySetTo() does only seem to accept callable , maybe add an additional type check?
This check looks at variables that have been passed in as parameters and are passed out again to other methods. If the outgoing method call has stricter type requirements than the method itself, an issue is raised. An additional type check may prevent trouble. ![]() |
|||
189 | } |
||
190 | |||
191 | /** |
||
192 | * Retrieve contact via jid |
||
193 | * @param string $jid |
||
194 | * @return array|null |
||
195 | */ |
||
196 | public function getContact($jid) |
||
197 | { |
||
198 | if ($this->isContact($jid)) { |
||
199 | return $this->roster_array[$jid]['contact']; |
||
200 | } |
||
201 | return null; |
||
202 | } |
||
203 | |||
204 | /** |
||
205 | * Return best presence for jid |
||
206 | * @param string $jid |
||
207 | * @return array|false |
||
208 | */ |
||
209 | public function getPresence($jid) |
||
210 | { |
||
211 | $split = split("/", $jid); |
||
212 | $jid = $split[0]; |
||
213 | if (!$this->isContact($jid)) { |
||
214 | return false; |
||
215 | } |
||
216 | $current = [ |
||
217 | 'resource' => '', |
||
218 | 'active' => '', |
||
219 | 'priority' => -129, |
||
220 | 'show' => '', |
||
221 | 'status' => '' |
||
222 | ]; //Priorities can only be -128 = 127 |
||
223 | foreach ($this->roster_array[$jid]['presence'] as $resource => $presence) { |
||
224 | //Highest available priority or just highest priority |
||
225 | if ($presence['priority'] > $current['priority'] && (($presence['show'] === 'chat' || $presence['show'] === 'available') or ($current['show'] !== 'chat' or $current['show'] !== 'available'))) { |
||
226 | $current = $presence; |
||
227 | $current['resource'] = $resource; |
||
228 | } |
||
229 | } |
||
230 | return $current; |
||
231 | } |
||
232 | } |
||
233 |
This check looks for
@param
annotations where the type inferred by our type inference engine differs from the declared type.It makes a suggestion as to what type it considers more descriptive.
Most often this is a case of a parameter that can be null in addition to its declared types.