Skip to content
Snippets Groups Projects
class.client.php 7.84 KiB
Newer Older
Jared Hancock's avatar
Jared Hancock committed
<?php
/*********************************************************************
    class.client.php

    Handles everything about client

    XXX: Please note that osTicket uses email address and ticket ID to authenticate the user*!
          Client is modeled on the info of the ticket used to login .
Jared Hancock's avatar
Jared Hancock committed

    Peter Rotich <peter@osticket.com>
    Copyright (c)  2006-2013 osTicket
Jared Hancock's avatar
Jared Hancock committed
    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:
**********************************************************************/

class Client {

    var $id;
    var $fullname;
    var $username;
    var $email;

    var $ticket_id;
    var $ticketID;

Peter Rotich's avatar
Peter Rotich committed
    function Client($id, $email=null) {
Jared Hancock's avatar
Jared Hancock committed
        $this->id =0;
        $this->load($id,$email);
    }

Peter Rotich's avatar
Peter Rotich committed
    function load($id=0, $email=null) {
        if(!$id && !($id=$this->getId()))
            return false;
        $sql='SELECT ticket_id, ticketID, name, email, phone, phone_ext '
            .' FROM '.TICKET_TABLE
            .' WHERE ticketID='.db_input($id);
        if($email)
Jared Hancock's avatar
Jared Hancock committed
            $sql.=' AND email='.db_input($email);

        if(!($res=db_query($sql)) || !db_num_rows($res))
Jared Hancock's avatar
Jared Hancock committed
            return NULL;

        $this->ht = db_fetch_array($res);
        $this->id         = $this->ht['ticketID']; //placeholder
        $this->ticket_id  = $this->ht['ticket_id'];
        $this->ticketID   = $this->ht['ticketID'];
        $this->fullname   = ucfirst($this->ht['name']);
        $this->username   = $this->ht['email'];
        $this->email      = $this->ht['email'];

        $this->stats = array();
Jared Hancock's avatar
Jared Hancock committed
      
        return($this->id);
    }

    function reload() {
        return $this->load();
    }

    function isClient() {
        return TRUE;
    }
    function getId() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->id;
    }

    function getEmail() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->email;
    }

    function getUserName() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->username;
    }

    function getName() {
Jared Hancock's avatar
Jared Hancock committed
        return $this->fullname;
    }

    function getPhone() {
        return $this->ht['phone'];
    }

    function getPhoneExt() {
        return $this->ht['phone_ext'];
    }
Jared Hancock's avatar
Jared Hancock committed
    
    function getTicketID() {
        return $this->ticketID;
    }

    function getTicketStats() {

        if(!$this->stats['tickets'])
            $this->stats['tickets'] = Ticket::getClientStats($this->getEmail());

        return $this->stats['tickets'];
    }

    function getNumTickets() {
        return ($stats=$this->getTicketStats())?($stats['open']+$stats['closed']):0;
    }

    function getNumOpenTickets() {
        return ($stats=$this->getTicketStats())?$stats['open']:0;
    }

    function getNumClosedTickets() {
        return ($stats=$this->getTicketStats())?$stats['closed']:0;
    }

Jared Hancock's avatar
Jared Hancock committed
    /* ------------- Static ---------------*/
Peter Rotich's avatar
Peter Rotich committed
    function getLastTicketIdByEmail($email) {
        $sql='SELECT ticketID FROM '.TICKET_TABLE
            .' WHERE email='.db_input($email)
            .' ORDER BY created '
            .' LIMIT 1';
        if(($res=db_query($sql)) && db_num_rows($res))
            list($tid) = db_fetch_row($res);

        return $tid;
    }

    function lookup($id, $email=null) {
Jared Hancock's avatar
Jared Hancock committed
        return ($id && is_numeric($id) && ($c=new Client($id,$email)) && $c->getId()==$id)?$c:null;
    }
Peter Rotich's avatar
Peter Rotich committed

    function lookupByEmail($email) {
        return (($id=self::getLastTicketIdByEmail($email)))?self::lookup($id, $email):null;
    }
    /* static */ function login($ticketID, $email, $auth=null, &$errors=array()) {
        global $ost;
        $cfg = $ost->getConfig();
        $auth = trim($auth);
        $email = trim($email);
        $ticketID = trim($ticketID);

        # Only consider auth token for GET requests, and for GET requests,
        # REQUIRE the auth token
        $auto_login = ($_SERVER['REQUEST_METHOD'] == 'GET');

        //Check time for last max failed login attempt strike.
        if($_SESSION['_client']['laststrike']) {
            if((time()-$_SESSION['_client']['laststrike'])<$cfg->getClientLoginTimeout()) {
                $errors['login'] = 'Excessive failed login attempts';
                $errors['err'] = 'You\'ve reached maximum failed login attempts allowed. Try again later or <a href="open.php">open a new ticket</a>';
                $_SESSION['_client']['laststrike'] = time(); //renew the strike.
            } else { //Timeout is over.
                //Reset the counter for next round of attempts after the timeout.
                $_SESSION['_client']['laststrike'] = null;
                $_SESSION['_client']['strikes'] = 0;

        if($auto_login && !$auth)
            $errors['login'] = 'Invalid method';
        elseif(!$ticketID || !Validator::is_email($email))
            $errors['login'] = 'Valid email and ticket number required';

        //Bail out on error.
        if($errors) return false;

        //See if we can fetch local ticket id associated with the ID given
        if(($ticket=Ticket::lookupByExtId($ticketID, $email)) && $ticket->getId()) {
            //At this point we know the ticket ID is valid.
            //TODO: 1) Check how old the ticket is...3 months max?? 2) Must be the latest 5 tickets?? 
            //Check the email given.

            # Require auth token for automatic logins (GET METHOD).
            if (!strcasecmp($ticket->getEmail(), $email) && (!$auto_login || $auth === $ticket->getAuthToken())) {
                    
                //valid match...create session goodies for the client.
                $user = new ClientSession($email,$ticket->getExtId());
                $_SESSION['_client'] = array(); //clear.
                $_SESSION['_client']['userID'] = $ticket->getEmail(); //Email
                $_SESSION['_client']['key'] = $ticket->getExtId(); //Ticket ID --acts as password when used with email. See above.
                $_SESSION['_client']['token'] = $user->getSessionToken();
                $_SESSION['TZ_OFFSET'] = $cfg->getTZoffset();
                $_SESSION['TZ_DST'] = $cfg->observeDaylightSaving();
                $user->refreshSession(); //set the hash.
                //Log login info...
                $msg=sprintf('%s/%s logged in [%s]', $ticket->getEmail(), $ticket->getExtId(), $_SERVER['REMOTE_ADDR']);
                $ost->logDebug('User login', $msg);
        
                //Regenerate session ID.
                $sid=session_id(); //Current session id.
                session_regenerate_id(TRUE); //get new ID.
                if(($session=$ost->getSession()) && is_object($session) && $sid!=session_id())
                    $session->destroy($sid);

                return $user;

            } 
        //If we get to this point we know the login failed.
        $errors['login'] = 'Invalid login';
        $_SESSION['_client']['strikes']+=1;
        if(!$errors && $_SESSION['_client']['strikes']>$cfg->getClientMaxLogins()) {
            $errors['login'] = 'Access Denied';
            $errors['err'] = 'Forgot your login info? Please <a href="open.php">open a new ticket</a>.';
            $_SESSION['_client']['laststrike'] = time();
            $alert='Excessive login attempts by a user.'."\n".
                    'Email: '.$email."\n".'Ticket#: '.$ticketID."\n".
                    'IP: '.$_SERVER['REMOTE_ADDR']."\n".'Time:'.date('M j, Y, g:i a T')."\n\n".
                    'Attempts #'.$_SESSION['_client']['strikes'];
            $ost->logError('Excessive login attempts (user)', $alert, ($cfg->alertONLoginError()));
        } elseif($_SESSION['_client']['strikes']%2==0) { //Log every other failed login attempt as a warning.
            $alert='Email: '.$email."\n".'Ticket #: '.$ticketID."\n".'IP: '.$_SERVER['REMOTE_ADDR'].
                   "\n".'TIME: '.date('M j, Y, g:i a T')."\n\n".'Attempts #'.$_SESSION['_client']['strikes'];
            $ost->logWarning('Failed login attempt (user)', $alert);

        return false;