Server IP : 184.154.167.98 / Your IP : 18.119.105.32 Web Server : Apache System : Linux pink.dnsnetservice.com 4.18.0-553.22.1.lve.1.el8.x86_64 #1 SMP Tue Oct 8 15:52:54 UTC 2024 x86_64 User : puertode ( 1767) PHP Version : 7.2.34 Disable Function : NONE MySQL : OFF | cURL : ON | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : ON Directory : /home/puertode/www/mesa/include/ |
Upload File : |
<?php /********************************************************************* class.client.php Handles everything about EndUser Peter Rotich <peter@osticket.com> Copyright (c) 2006-2013 osTicket http://www.osticket.com Released under the GNU General Public License WITHOUT ANY WARRANTY. See LICENSE.TXT for details. vim: expandtab sw=4 ts=4 sts=4: **********************************************************************/ require_once INCLUDE_DIR.'class.user.php'; abstract class TicketUser implements EmailContact, ITicketUser, TemplateVariable { static private $token_regex = '/^(?P<type>\w{1})(?P<algo>\d+)x(?P<hash>.*)$/i'; protected $user; protected $_guest = false; function __construct($user) { $this->user = $user; } function __call($name, $args) { global $cfg; $rv = null; if($this->user && is_callable(array($this->user, $name))) $rv = $args ? call_user_func_array(array($this->user, $name), $args) : call_user_func(array($this->user, $name)); return $rv ?: false; } // Required for Internationalization::getCurrentLanguage() in templates function getLanguage() { return $this->user->getLanguage(); } static function getVarScope() { return array( 'email' => __('Email Address'), 'name' => array('class' => 'PersonsName', 'desc' => __('Full Name')), 'ticket_link' => __('Link to view the ticket'), ); } function getVar($tag) { switch (strtolower($tag)) { case 'ticket_link': $ticket = $this->getTicket(); return $this->getTicketLink(($ticket && !$ticket->getNumCollaborators())); break; } } function getTicketLink($authtoken=true) { global $cfg; $ticket = $this->getTicket(); if ($authtoken && $ticket && $cfg->isAuthTokenEnabled()) { $qstr = array(); $qstr['auth'] = $ticket->getAuthToken($this); return sprintf('%s/view.php?%s', $cfg->getBaseUrl(), Http::build_query($qstr, false) ); } return sprintf('%s/view.php?id=%s', $cfg->getBaseUrl(), $ticket ? $ticket->getId() : 0 ); } function getId() { return ($this->user) ? $this->user->getId() : null; } function getEmail() { return ($this->user) ? $this->user->getEmail() : null; } function getName() { return ($this->user) ? $this->user->getName() : null; } static function lookupByToken($token) { //Expecting well formatted token see getAuthToken routine for details. $matches = array(); if (!preg_match(static::$token_regex, $token, $matches)) return null; //Unpack the user and ticket ids $matches +=unpack('Vuid/Vtid', Base32::decode(strtolower(substr($matches['hash'], 0, 13)))); $user = null; if (!($ticket = Ticket::lookup($matches['tid']))) // Require a ticket for now return null; switch ($matches['type']) { case 'c': //Collaborator c if (($user = Collaborator::lookup($matches['uid'])) && $user->getTicketId() != $matches['tid']) $user = null; break; case 'o': //Ticket owner if (($user = $ticket->getOwner()) && $user->getId() != $matches['uid']) { $user = null; } break; } if (!$user || !$user instanceof ITicketUser || strcasecmp($ticket->getAuthToken($user, $matches['algo']), $token)) return false; return $user; } static function lookupByEmail($email) { if (!($user=User::lookup(array('emails__address' => $email)))) return null; return new EndUser($user); } function isOwner() { return $this instanceof TicketOwner; } function flagGuest() { $this->_guest = true; } function isGuest() { return $this->_guest; } function getUserId() { return $this->user->getId(); } function getEmailAddress() { $emailaddr = (string) $this->getEmail(); if (($name=$this->getName())) $emailaddr = sprintf('"%s" <%s>', (string) $name, $emailaddr); return $emailaddr; } function __toString() { return $this->getEmailAddress(); } abstract function getTicketId(); abstract function getTicket(); } class TicketOwner extends TicketUser { protected $ticket; function __construct($user, $ticket) { parent::__construct($user); $this->ticket = $ticket; } function __toString() { return (string) $this->getName(); } function getTicket() { return $this->ticket; } function getTicketId() { return $this->ticket->getId(); } } /* * Decorator class for authenticated user * */ class EndUser extends BaseAuthenticatedUser { protected $user; protected $_account = false; protected $_stats; protected $topic_stats; function __construct($user) { $this->user = $user; } /* * Delegate calls to the user */ function __call($name, $args) { if(!$this->user || !is_callable(array($this->user, $name))) return $this->getVar(substr($name, 3)); return $args ? call_user_func_array(array($this->user, $name), $args) : call_user_func(array($this->user, $name)); } function getVar($tag) { $u = $this; // Traverse the $user properties of all nested user objects to get // to the User instance with the custom data while (isset($u->user)) { $u = $u->user; if (method_exists($u, 'getVar')) { if ($rv = $u->getVar($tag)) return $rv; } } } function getId() { //We ONLY care about user ID at the ticket level if ($this->user instanceof Collaborator) return $this->user->getUserId(); elseif ($this->user) return $this->user->getId(); return false; } function getUserName() { //XXX: Revisit when real usernames are introduced or when email // requirement is removed. return $this->user->getEmail(); } function getUserType() { return $this->isOwner() ? 'owner' : 'collaborator'; } function getAuthBackend() { list($authkey,) = explode(':', $this->getAuthKey()); return UserAuthenticationBackend::getBackend($authkey); } function get2FABackend() { //TODO: support 2FA on client portal return null; } function getTicketStats() { if (!isset($this->_stats)) $this->_stats = $this->getStats(); return $this->_stats; } function getNumTickets($forMyOrg=false, $state=false) { $stats = $this->getTicketStats(); $count = 0; $section = $forMyOrg ? 'myorg' : 'mine'; foreach ($stats[$section] as $row) { if ($state && $row['status__state'] != $state) continue; $count += $row['count']; } return $count; } function getNumOpenTickets($forMyOrg=false) { return $this->getNumTickets($forMyOrg, 'open') ?: 0; } function getNumClosedTickets($forMyOrg=false) { return $this->getNumTickets($forMyOrg, 'closed') ?: 0; } function getNumTopicTickets($topic_id, $forMyOrg=false) { $stats = $this->getTicketStats(); $section = $forMyOrg ? 'myorg' : 'mine'; if (!isset($this->topic_stats)) { $this->topic_stats = array(); foreach ($stats[$section] as $row) { $this->topic_stats[$row['topic_id']] += $row['count']; } } return $this->topic_stats[$topic_id]; } function getNumTopicTicketsInState($topic_id, $state=false, $forMyOrg=false) { $stats = $this->getTicketStats(); $count = 0; $section = $forMyOrg ? 'myorg' : 'mine'; foreach ($stats[$section] as $row) { if ($topic_id != $row['topic_id']) continue; if ($state && $state != $row['status__state']) continue; $count += $row['count']; } return $count; } function getNumOrganizationTickets() { return $this->getNumTickets(true); } function getNumOpenOrganizationTickets() { return $this->getNumTickets(true, 'open'); } function getNumClosedOrganizationTickets() { return $this->getNumTickets(true, 'closed'); } function getAccount() { if ($this->_account === false) $this->_account = ClientAccount::lookup(array('user_id'=>$this->getId())); return $this->_account; } function getUser() { if ($this->user === false) $this->user = User::lookup($this->getId()); return $this->user; } function getLanguage($flags=false) { if ($acct = $this->getAccount()) return $acct->getLanguage($flags); } private function getStats() { global $cfg; $basic = Ticket::objects() ->annotate(array('count' => SqlAggregate::COUNT('ticket_id'))) ->values('status__state', 'topic_id') ->distinct('status_id', 'topic_id'); // Share tickets among the organization for owners only $mine = clone $basic; $collab = clone $basic; $mine->filter(array( 'user_id' => $this->getId(), )); // Also add collaborator tickets to the list. This may seem ugly; // but the general rule for SQL is that a single query can only use // one index. Therefore, to scan two indexes (by user_id and // thread.collaborators.user_id), we need two queries. A union will // help out with that. if ($cfg->collaboratorTicketsVisibility()) $mine->union($collab->filter(array( 'thread__collaborators__user_id' => $this->getId(), Q::not(array('user_id' => $this->getId())) ))); if ($orgid = $this->getOrgId()) { // Also generate a separate query for all the tickets owned by // either my organization or ones that I'm collaborating on // which are not part of the organization. $myorg = clone $basic; $myorg->values('user__org_id'); $collab = clone $myorg; $myorg->filter(array('user__org_id' => $orgid)); $myorg->union($collab->filter(array( 'thread__collaborators__user_id' => $this->getId(), Q::not(array('user__org_id' => $orgid)) ))); } return array('mine' => $mine, 'myorg' => $myorg); } function onLogin($bk) { if ($account = $this->getAccount()) $account->onLogin($bk); } } class ClientAccount extends UserAccount { function check_passwd($password, $autoupdate=true) { /*bcrypt based password match*/ if(Passwd::cmp($password, $this->get('passwd'))) return true; //Fall back to MD5 if(!$password || strcmp($this->get('passwd'), MD5($password))) return false; //Password is a MD5 hash: rehash it (if enabled) otherwise force passwd change. if ($autoupdate) $this->set('passwd', Passwd::hash($password)); if (!$autoupdate || !$this->save()) $this->forcePasswdReset(); return true; } function hasCurrentPassword($password) { return $this->check_passwd($password, false); } function cancelResetTokens() { // TODO: Drop password-reset tokens from the config table for // this user id $sql = 'DELETE FROM '.CONFIG_TABLE.' WHERE `namespace`="pwreset" AND `value`='.db_input('c'.$this->getUserId()); if (!db_query($sql, false)) return false; unset($_SESSION['_client']['reset-token']); } function onLogin($bk) { $this->setExtraAttr('browser_lang', Internationalization::getCurrentLanguage()); $this->save(); } function update($vars, &$errors) { global $cfg; // FIXME: Updates by agents should go through UserAccount::update() global $thisstaff, $thisclient; if ($thisstaff) return parent::update($vars, $errors); $rtoken = $_SESSION['_client']['reset-token']; if ($rtoken) { $_config = new Config('pwreset'); if ($_config->get($rtoken) != 'c'.$this->getUserId()) $errors['err'] = __('Invalid reset token. Logout and try again'); elseif (!($ts = $_config->lastModified($rtoken)) && ($cfg->getPwResetWindow() < (time() - strtotime($ts)))) $errors['err'] = __('Invalid reset token. Logout and try again'); } elseif ($vars['passwd1'] || $vars['passwd2'] || $vars['cpasswd']) { if (!$vars['passwd1']) $errors['passwd1']=__('New password is required'); elseif ($vars['passwd1'] && strcmp($vars['passwd1'], $vars['passwd2'])) $errors['passwd2']=__('Passwords do not match'); elseif ($this->get('passwd')) { if (!$vars['cpasswd']) $errors['cpasswd']=__('Current password is required'); elseif (!$this->hasCurrentPassword($vars['cpasswd'])) $errors['cpasswd']=__('Invalid current password!'); } // Check password policies if (!$errors) { try { UserAccount::checkPassword($vars['passwd1'], @$vars['cpasswd']); } catch (BadPassword $ex) { $errors['passwd1'] = $ex->getMessage(); } } } // Timezone selection is not required. System default is a valid // fallback if ($errors) return false; $this->set('timezone', $vars['timezone']); // Change language $this->set('lang', $vars['lang'] ?: null); Internationalization::setCurrentLanguage(null); TextDomain::configureForUser($this); if ($vars['backend']) { $this->set('backend', $vars['backend']); if ($vars['username']) $this->set('username', Format::sanitize($vars['username'])); } if ($vars['passwd1']) { $this->set('passwd', Passwd::hash($vars['passwd1'])); $info = array('password' => $vars['passwd1']); Signal::send('auth.pwchange', $this->getUser(), $info); $this->cancelResetTokens(); $this->clearStatus(UserAccountStatus::REQUIRE_PASSWD_RESET); // Clean sessions Signal::send('auth.clean', $this->getUser(), $thisclient); } return $this->save(); } } interface ITicketUser { /* PHP 5.3 < 5.3.8 will crash with some abstract inheritance issue * ------------------------------------------------------------ function isOwner(); function flagGuest(); function isGuest(); function getUserId(); function getTicketId(); function getTicket(); */ } ?>