Issues (1844)

Security Analysis    not enabled

This project does not seem to handle request data directly as such no vulnerable execution paths were found.

  File Inclusion
File Inclusion enables an attacker to inject custom files into PHP's file loading mechanism, either explicitly passed to include, or for example via PHP's auto-loading mechanism.
  Regex Injection
Regex Injection enables an attacker to execute arbitrary code in your PHP process.
  SQL Injection
SQL Injection enables an attacker to execute arbitrary SQL code on your database server gaining access to user data, or manipulating user data.
  Response Splitting
Response Splitting can be used to send arbitrary responses.
  File Manipulation
File Manipulation enables an attacker to write custom data to files. This potentially leads to injection of arbitrary code on the server.
  Object Injection
Object Injection enables an attacker to inject an object into PHP code, and can lead to arbitrary code execution, file exposure, or file manipulation attacks.
  File Exposure
File Exposure allows an attacker to gain access to local files that he should not be able to access. These files can for example include database credentials, or other configuration files.
  XML Injection
XML Injection enables an attacker to read files on your local filesystem including configuration files, or can be abused to freeze your web-server process.
  Code Injection
Code Injection enables an attacker to execute arbitrary code on the server.
  Variable Injection
Variable Injection enables an attacker to overwrite program variables with custom data, and can lead to further vulnerabilities.
  XPath Injection
XPath Injection enables an attacker to modify the parts of XML document that are read. If that XML document is for example used for authentication, this can lead to further vulnerabilities similar to SQL Injection.
  Other Vulnerability
This category comprises other attack vectors such as manipulating the PHP runtime, loading custom extensions, freezing the runtime, or similar.
  Command Injection
Command Injection enables an attacker to inject a shell command that is execute with the privileges of the web-server. This can be used to expose sensitive data, or gain access of your server.
  LDAP Injection
LDAP Injection enables an attacker to inject LDAP statements potentially granting permission to run unauthorized queries, or modify content inside the LDAP tree.
  Cross-Site Scripting
Cross-Site Scripting enables an attacker to inject code into the response of a web-request that is viewed by other users. It can for example be used to bypass access controls, or even to take over other users' accounts.
  Header Injection
Unfortunately, the security analysis is currently not available for your project. If you are a non-commercial open-source project, please contact support to gain access.

class/StaffHandler.php (31 issues)

1
<?php declare(strict_types=1);
2
3
namespace XoopsModules\Xhelp;
4
5
/*
6
 * You may not change or alter any portion of this comment or credits
7
 * of supporting developers from this source code or any supporting source code
8
 * which is considered copyrighted (c) material of the original comment or credit authors.
9
 *
10
 * This program is distributed in the hope that it will be useful,
11
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13
 */
14
15
/**
16
 * @copyright    {@link https://xoops.org/ XOOPS Project}
17
 * @license      {@link https://www.gnu.org/licenses/gpl-2.0.html GNU GPL 2 or later}
18
 * @author       Eric Juden <[email protected]>
19
 * @author       XOOPS Development Team
20
 */
21
22
if (!\defined('XHELP_CLASS_PATH')) {
23
    exit();
24
}
25
26
// require_once XHELP_CLASS_PATH . '/BaseObjectHandler.php';
27
// require_once XHELP_CLASS_PATH . '/NotificationService.php';
28
29
/**
30
 * Staff class
31
 *
32
 * @author  Eric Juden <[email protected]>
33
 */
34
35
// require_once XHELP_CLASS_PATH . '/session.php';
36
37
/**
38
 * StaffHandler class
39
 *
40
 * Staff Handler for Staff class
41
 *
42
 * @author  Eric Juden <[email protected]> &
43
 */
44
class StaffHandler extends BaseObjectHandler
45
{
46
    /**
47
     * Name of child class
48
     *
49
     * @var string
50
     */
51
    public $classname = Staff::class;
52
    /**
53
     * DB table name
54
     *
55
     * @var string
56
     */
57
    public $dbtable = 'xhelp_staff';
58
59
    private const TABLE = 'xhelp_staff';
60
    private const ENTITY = Staff::class;
61
    private const ENTITYNAME = 'Staff';
62
    private const KEYNAME = 'id';
63
    private const IDENTIFIER = 'uid';
64
65
    /**
66
     * Constructor
67
     *
68
     * @param \XoopsMySQLDatabase|null $db reference to a xoopsDB object
69
     */
70
    public function __construct(\XoopsMySQLDatabase $db = null)
71
    {
72
        $this->init($db);
73
        $this->helper = Helper::getInstance();
74
        parent::__construct($db, static::TABLE, static::ENTITY, static::KEYNAME, static::IDENTIFIER);
75
    }
76
77
    /**
78
     * retrieve a staff object from the database
79
     * @param int $uid user id
80
     * @return bool|Staff
81
     */
82
    public function &getByUid(int $uid)
83
    {
84
        $ret = false;
85
        $uid = $uid;
86
        if ($uid > 0) {
87
            $sql = $this->selectQuery(new \Criteria('uid', (string)$uid));
88
            if (!$result = $this->db->query($sql)) {
89
                return $ret;
90
            }
91
            $arr = $this->db->fetchArray($result);
92
            if ($arr) {
93
                $ret = new $this->classname($arr);
94
95
                return $ret;
96
            }
97
        }
98
99
        return $ret;
100
    }
101
102
    /**
103
     * Add user to a new role
104
     *
105
     * @param int $uid    user id
106
     * @param int $roleid role id
107
     * @param int $deptid department id
108
     *
109
     * @return bool true if success, FALSE if failure
110
     */
111
    public function addStaffRole(int $uid, int $roleid, int $deptid): bool
112
    {
113
        $staffRoleHandler = $this->helper->getHandler('StaffRole');
114
        $role             = $staffRoleHandler->create();
115
        $role->setVar('uid', $uid);
116
        $role->setVar('roleid', $roleid);
117
        $role->setVar('deptid', $deptid);
118
        if (!$staffRoleHandler->insert($role)) {
119
            return false;
120
        }
121
122
        return true;
123
    }
124
125
    /**
126
     * Retrive all roles of the current staff member
127
     *
128
     * @param int  $uid
129
     * @param bool $id_as_key
130
     * @return array|bool StaffRoles or FALSE if failure
131
     */
132
    public function getRoles(int $uid, bool $id_as_key = false)
133
    {
134
        $uid = $uid;
135
        /** @var \XoopsModules\Xhelp\StaffRoleHandler $staffRoleHandler */
136
        $staffRoleHandler = $this->helper->getHandler('StaffRole');
137
138
        if (!$roles = $staffRoleHandler->getObjectsByStaff($uid, $id_as_key)) {
139
            return false;
140
        }
141
142
        return $roles;
143
    }
144
145
    /**
146
     * @return bool
147
     */
148
    public function clearRoles(): bool
149
    {
150
        $session = Session::getInstance();
151
152
        $myRoles = $session->get('xhelp_hasRights');
153
        if ($myRoles) {
154
            $session->del('xhelp_hasRights');
155
156
            return true;
157
        }
158
159
        return false;
160
    }
161
162
    /**
163
     * Retrieve all of the roles of current department for staff member
164
     *
165
     * @param int  $uid
166
     * @param int  $deptid
167
     * @param bool $id_as_key
168
     * @return array|bool array of StaffRoles or FALSE if failure
169
     */
170
    public function getRolesByDept(int $uid, int $deptid, bool $id_as_key = false)
171
    {
172
        $ret              = false;
173
        $uid              = $uid;
174
        $deptid           = $deptid;
175
        $staffRoleHandler = $this->helper->getHandler('StaffRole');
176
177
        $criteria = new \CriteriaCompo(new \Criteria('uid', (string)$uid));
178
        $criteria->add(new \Criteria('deptid', (string)$deptid));
179
180
        if (!$roles = $staffRoleHandler->getObjects($criteria, $id_as_key)) {
181
            return $ret;
182
        }
183
184
        return $roles;
185
    }
186
187
    /**
188
     * Remove user from a role
189
     *
190
     * @param int $uid user id
191
     * @return true if success, FALSE if failure
192
     * @internal param int $roleid role id
193
     * @internal param int $deptid department id
194
     */
195
    public function removeStaffRoles(int $uid): bool
196
    {
197
        $staffRoleHandler = $this->helper->getHandler('StaffRole');
198
        $criteria         = new \Criteria('uid', (string)$uid);
199
200
        return $staffRoleHandler->deleteAll($criteria);
201
    }
202
203
    /**
204
     * Check if a user is in a particular role
205
     *
206
     * @param int $uid    user id
207
     * @param int $roleid role id
208
     *
209
     * @return bool true on success, FALSE on failure
210
     */
211
    public function staffInRole(int $uid, int $roleid): bool
212
    {
213
        $staffRoleHandler = $this->helper->getHandler('StaffRole');
214
        if (!$inRole = $staffRoleHandler->staffInRole($uid, $roleid)) {
0 ignored issues
show
The assignment to $inRole is dead and can be removed.
Loading history...
215
            return false;
216
        }
217
218
        return true;
219
    }
220
221
    /**
222
     * Retrieve amount of time spent by staff member
223
     * @param int $uid user id
224
     * @return int
225
     */
226
    public function &getTimeSpent(int $uid = 0): int
227
    {
228
        $responseHandler = $this->helper->getHandler('Response');
229
        if (0 == !$uid) {
230
            $uid       = $uid;
231
            $criteria  = new \Criteria('uid', (string)$uid);
232
            $responses = $responseHandler->getObjects($criteria);
233
        } else {
234
            $responses = $responseHandler->getObjects();
235
        }
236
        $timeSpent = 0;
237
        foreach ($responses as $response) {
238
            $newTime   = $response->getVar('timeSpent');
239
            $timeSpent += $newTime;
240
        }
241
242
        return $timeSpent;
243
    }
244
245
    /**
246
     * @return array
247
     */
248
    public function &getByAllDepts(): array
249
    {
250
        $ret = $this->getObjects(new \Criteria('allDepartments', '1'), true);
251
252
        return $ret;
253
    }
254
255
    /**
256
     * creates new staff member
257
     *
258
     * @param int    $uid
259
     * @param string $email
260
     * @return bool
261
     */
262
    public function addStaff(int $uid, string $email) //, $allDepts = 0
263
    : bool
264
    {
265
        $notify = new NotificationService();
266
        /** @var \XoopsModules\Xhelp\Staff $staff */
267
        $staff = $this->create();
268
        $staff->setVar('uid', $uid);
269
        $staff->setVar('email', $email);
270
        $numNotify = $notify->getNumDeptNotifications();
271
        $staff->setVar('notify', (2 ** $numNotify) - 1);
272
        $staff->setVar('permTimestamp', \time());
273
274
        return $this->insert($staff);
275
    }
276
277
    /**
278
     * checks to see if the user is a staff member
279
     *
280
     * @param int $uid User ID to look for
281
     * @return bool TRUE if user is a staff member, false if not
282
     */
283
    public function isStaff(int $uid): bool
284
    {
285
        $count = $this->getCount(new \Criteria('uid', (string)$uid));
286
287
        return ($count > 0);
288
    }
289
290
    /**
291
     * @param \XoopsObject $object
292
     * @return string
293
     */
294
    public function insertQuery(\XoopsObject $object): string
295
    {
296
        //TODO mb replace with individual variables
297
        // Copy all object vars into local variables
298
        foreach ($object->cleanVars as $k => $v) {
299
            ${$k} = $v;
300
        }
301
302
        $sql = \sprintf(
303
            'INSERT INTO `%s` (id, uid, email, responseTime, numReviews, callsClosed, attachSig, rating, allDepartments, ticketsResponded, notify, permTimestamp) VALUES (%u, %u, %s, %u, %u, %u, %u, %u, %u, %u, %u, %u)',
304
            $this->db->prefix($this->dbtable),
305
            $id,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
306
            $uid,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $uid seems to be never defined.
Loading history...
307
            $this->db->quoteString($email),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $email seems to be never defined.
Loading history...
308
            $responseTime,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $responseTime seems to be never defined.
Loading history...
309
            $numReviews,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $numReviews seems to be never defined.
Loading history...
310
            $callsClosed,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callsClosed seems to be never defined.
Loading history...
311
            $attachSig,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $attachSig seems to be never defined.
Loading history...
312
            $rating,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rating seems to be never defined.
Loading history...
313
            $allDepartments,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $allDepartments seems to be never defined.
Loading history...
314
            $ticketsResponded,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ticketsResponded seems to be never defined.
Loading history...
315
            $notify,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $notify seems to be never defined.
Loading history...
316
            $permTimestamp
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $permTimestamp seems to be never defined.
Loading history...
317
        );
318
319
        return $sql;
320
    }
321
322
    /**
323
     * @param \XoopsObject $object
324
     * @return string
325
     */
326
    public function updateQuery(\XoopsObject $object): string
327
    {
328
        //TODO mb replace with individual variables
329
        // Copy all object vars into local variables
330
        foreach ($object->cleanVars as $k => $v) {
331
            ${$k} = $v;
332
        }
333
334
        $sql = \sprintf(
335
            'UPDATE `%s` SET uid = %u, email = %s, responseTime = %u, numReviews = %u, callsClosed = %u, attachSig = %u, rating = %u, allDepartments = %u, ticketsResponded = %u, notify = %u, permTimestamp = %u WHERE id = %u',
336
            $this->db->prefix($this->dbtable),
337
            $uid,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $uid seems to be never defined.
Loading history...
338
            $this->db->quoteString($email),
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $email seems to be never defined.
Loading history...
339
            $responseTime,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $responseTime seems to be never defined.
Loading history...
340
            $numReviews,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $numReviews seems to be never defined.
Loading history...
341
            $callsClosed,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $callsClosed seems to be never defined.
Loading history...
342
            $attachSig,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $attachSig seems to be never defined.
Loading history...
343
            $rating,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $rating seems to be never defined.
Loading history...
344
            $allDepartments,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $allDepartments seems to be never defined.
Loading history...
345
            $ticketsResponded,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $ticketsResponded seems to be never defined.
Loading history...
346
            $notify,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $notify seems to be never defined.
Loading history...
347
            $permTimestamp,
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $permTimestamp seems to be never defined.
Loading history...
348
            $id
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $id seems to be never defined.
Loading history...
349
        );
350
351
        return $sql;
352
    }
353
354
    /**
355
     * @param \XoopsObject $object
356
     * @return string
357
     */
358
    public function deleteQuery(\XoopsObject $object): string
359
    {
360
        $sql = \sprintf('DELETE FROM `%s` WHERE id = %u', $this->db->prefix($this->dbtable), $object->getVar('id'));
0 ignored issues
show
It seems like $object->getVar('id') can also be of type array and array; however, parameter $values of sprintf() does only seem to accept double|integer|string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

360
        $sql = \sprintf('DELETE FROM `%s` WHERE id = %u', $this->db->prefix($this->dbtable), /** @scrutinizer ignore-type */ $object->getVar('id'));
Loading history...
361
362
        return $sql;
363
    }
364
365
    /**
366
     * delete a staff member from the database
367
     *
368
     * @param \XoopsObject $object    reference to the {@link Staff}
369
     *                                obj to delete
370
     * @param bool         $force
371
     * @return bool FALSE if failed.
372
     */
373
    public function delete(\XoopsObject $object, $force = false): bool
374
    {
375
        if (0 != \strcasecmp($this->classname, \get_class($object))) {
376
            return false;
377
        }
378
379
        // Clear Department Membership
380
        /** @var \XoopsModules\Xhelp\MembershipHandler $membershipHandler */
381
        $membershipHandler = $this->helper->getHandler('Membership');
382
        if (!$membershipHandler->clearStaffMembership($object->getVar('uid'))) {
383
            return false;
384
        }
385
386
        // Remove ticket lists
387
        $ticketListHandler = $this->helper->getHandler('TicketList');
388
        $criteria          = new \Criteria('uid', $object->getVar('uid'));
0 ignored issues
show
It seems like $object->getVar('uid') can also be of type array and array; however, parameter $value of Criteria::__construct() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

388
        $criteria          = new \Criteria('uid', /** @scrutinizer ignore-type */ $object->getVar('uid'));
Loading history...
389
        if (!$ticketListHandler->deleteAll($criteria)) {
390
            return false;
391
        }
392
393
        // Remove saved searches
394
        $savedSearchHandler = $this->helper->getHandler('SavedSearch');
395
        if (!$savedSearchHandler->deleteAll($criteria)) {   // use existing crit object
396
            return false;
397
        }
398
399
        // Clear permission roles
400
        if (!$this->removeStaffRoles($object->getVar('uid'))) {
401
            return false;
402
        }
403
404
        $ret = parent::delete($object, $force);
405
406
        return $ret;
407
    }
408
409
    /**
410
     * Adjust the # of calls closed for the given user by the given offset
411
     *
412
     * @param int $uid    User ID to modify
413
     * @param int $offset Number of tickets to add to current call count (Negative for decrementing)
414
     * @return bool FALSE if query failed
415
     */
416
    public function increaseCallsClosed(int $uid, int $offset = 1): bool
417
    {
418
        if ($offset < 0) {
419
            $sql = \sprintf('UPDATE `%s` SET callsClosed = callsClosed - %u WHERE uid = %u', $this->db->prefix($this->dbtable), \abs($offset), $uid);
420
        } else {
421
            $sql = \sprintf('UPDATE `%s` SET callsClosed = callsClosed + %u WHERE uid = %u', $this->db->prefix($this->dbtable), $offset, $uid);
422
        }
423
        if (!$result = $this->db->query($sql)) {
0 ignored issues
show
The assignment to $result is dead and can be removed.
Loading history...
424
            return false;
425
        }
426
427
        return true;
428
    }
429
430
    /**
431
     * Adjust the responseTime for the specified staff member
432
     *
433
     * @param int $uid          User ID to modify
434
     * @param int $responseTime If $ticketCount is specified, the total # of response seconds, otherwise the number of seconds to add
435
     * @param int $ticketCount  If = 0, increments 'responseTime' and 'ticketsResponded' otherwise, total # of tickets
436
     * @return bool FALSE if query failed
437
     */
438
    public function updateResponseTime(int $uid, int $responseTime, int $ticketCount = 0): bool
439
    {
440
        if (0 == $ticketCount) {
441
            //Incrementing responseTime
442
            $sql = \sprintf('UPDATE `%s` SET responseTime = responseTime + %u, ticketsResponded = ticketsResponded + 1 WHERE uid = %u', $this->db->prefix($this->dbtable), $responseTime, $uid);
443
        } else {
444
            //Setting responseTime, ticketsResponded
445
            $sql = \sprintf('UPDATE `%s` SET responseTime = %u, ticketsResponded = %u WHERE uid = %u', $this->db->prefix($this->dbtable), $responseTime, $ticketCount, $uid);
446
        }
447
        if (!$result = $this->db->query($sql)) {
0 ignored issues
show
The assignment to $result is dead and can be removed.
Loading history...
448
            return false;
449
        }
450
451
        return true;
452
    }
453
454
    /**
455
     * Adjust the rating for the specified staff member
456
     *
457
     * @param int $uid        Staff ID to modify
458
     * @param int $rating     If $numReviews is specified, the total # of rating points, otherwise the number of rating points to add
459
     * @param int $numReviews If = 0, increments 'rating' and 'numReviews', otherwise total # of reviews
460
     * @return bool FALSE if query failed
461
     */
462
    public function updateRating(int $uid, int $rating, int $numReviews = 0): bool
463
    {
464
        if (0 == $numReviews) {
465
            //Add New Review
466
            $sql = \sprintf('UPDATE `%s` SET rating = rating + %u, numReviews = numReviews + 1 WHERE uid = %u', $this->db->prefix($this->dbtable), $rating, $uid);
467
        } else {
468
            //Set rating, numReviews to supplied values
469
            $sql = \sprintf('UPDATE `%s` SET rating = %u, numReviews = %u WHERE uid = %u', $this->db->prefix($this->dbtable), $rating, $numReviews, $uid);
470
        }
471
        if (!$result = $this->db->query($sql)) {
0 ignored issues
show
The assignment to $result is dead and can be removed.
Loading history...
472
            return false;
473
        }
474
475
        return true;
476
    }
477
478
    /**
479
     * Retrieve array of all staff with permission for current task
480
     * @param int  $task
481
     * @param int  $deptid
482
     * @param bool $id_as_key
483
     * @return array
484
     */
485
    public function getStaffByTask(int $task, int $deptid = 0, bool $id_as_key = false): array
486
    {
487
        $task = $task;
488
        if (null !== $deptid) {
0 ignored issues
show
The condition null !== $deptid is always true.
Loading history...
489
            $deptid = $deptid;
490
        }
491
492
        // Get roles with $task value set
493
        $roleHandler = $this->helper->getHandler('Role');
494
        $roles       = $roleHandler->getRolesByTask($task);
495
        $aRoles      = [];
496
        foreach ($roles as $role) {
497
            $aRoles[$role->getVar('id')] = '';
498
        }
499
500
        // Get staff roles by dept
501
        $staffRoleHandler = $this->helper->getHandler('StaffRole');
502
        $criteria         = new \CriteriaCompo(new \Criteria('deptid', (string)$deptid));
503
        $criteria->add(new \Criteria('roleid', '(' . \implode(',', \array_keys($aRoles)) . ')', 'IN'));
504
        unset($aRoles);
505
506
        $staffRoles = $staffRoleHandler->getObjects($criteria);
507
        $aStaffID   = [];
508
        foreach ($staffRoles as $sRole) {
509
            $aStaffID[$sRole->getVar('uid')] = '';
510
        }
511
512
        // Get staff objects
513
        $criteria     = new \Criteria('uid', '(' . \implode(',', \array_keys($aStaffID)) . ')', 'IN');
514
        $staffHandler = $this->helper->getHandler('Staff');
515
516
        return $staffHandler->getObjects($criteria, $id_as_key);
517
    }
518
}
519