File indexing completed on 2024-10-13 13:29:13

0001 <?php
0002 
0003 /**
0004  *  ocs-webserver
0005  *
0006  *  Copyright 2016 by pling GmbH.
0007  *
0008  *    This file is part of ocs-webserver.
0009  *
0010  *    This program is free software: you can redistribute it and/or modify
0011  *    it under the terms of the GNU Affero General Public License as
0012  *    published by the Free Software Foundation, either version 3 of the
0013  *    License, or (at your option) any later version.
0014  *
0015  *    This program is distributed in the hope that it will be useful,
0016  *    but WITHOUT ANY WARRANTY; without even the implied warranty of
0017  *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0018  *    GNU Affero General Public License for more details.
0019  *
0020  *    You should have received a copy of the GNU Affero General Public License
0021  *    along with this program.  If not, see <http://www.gnu.org/licenses/>.
0022  **/
0023 class Application_Model_RememberMe
0024 {
0025 
0026     protected $salt = 'slkdmclskdaruiowrjasndf224323423rwersdf§$%ZTFG§EWRSGFSD!§RWESFD';
0027 
0028     /** @var null|Zend_Controller_Request_Http */
0029     protected $request;
0030     /** @var string */
0031     protected $dataTableName;
0032     /** @var  Application_Model_DbTable_Comments */
0033     protected $dataTable;
0034     /** @var  string */
0035     protected $cookieName;
0036     /** @var  int */
0037     protected $cookieTimeout;
0038 
0039     /**
0040      * PHP 5 allows developers to declare constructor methods for classes.
0041      * Classes which have a constructor method call this method on each newly-created object,
0042      * so it is suitable for any initialization that the object may need before it is used.
0043      *
0044      * Note: Parent constructors are not called implicitly if the child class defines a constructor.
0045      * In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.
0046      *
0047      * param [ mixed $args [, $... ]]
0048      *
0049      * @param string $_dataTableName
0050      *
0051      * @throws Zend_Exception
0052      * @link http://php.net/manual/en/language.oop5.decon.php
0053      */
0054     public function __construct($_dataTableName = 'Application_Model_DbTable_Session')
0055     {
0056         $this->request = Zend_Controller_Front::getInstance()->getRequest();
0057 
0058         $this->dataTableName = $_dataTableName;
0059         $this->dataTable = new $this->dataTableName;
0060 
0061         $config = Zend_Registry::get('config');
0062         $this->cookieName = $config->settings->session->remember_me->name;
0063         $this->cookieTimeout = $config->settings->session->remember_me->cookie_lifetime;
0064     }
0065 
0066     /**
0067      * @param $identifier
0068      *
0069      * @return array|null
0070      * @throws Zend_Db_Statement_Exception
0071      */
0072     public function updateSession($identifier)
0073     {
0074         $currentSessionCookie = $this->getCookieData();
0075 
0076         if (empty($currentSessionCookie)) {
0077             return $this->createSession($identifier);
0078         }
0079 
0080         $newSessionData = $this->createSessionData($identifier);
0081         $this->setCookie($newSessionData);
0082 
0083         $countUpdated = $this->updateSessionData($currentSessionCookie, $newSessionData, $identifier);
0084 
0085         if (empty($countUpdated)) {
0086             $this->saveSessionData($newSessionData); // old session entry not found; we create a new one
0087         }
0088 
0089         return $newSessionData;
0090     }
0091 
0092     /**
0093      * @return null|array
0094      */
0095     public function getCookieData()
0096     {
0097         $cookieRememberMe = $this->request->getCookie($this->cookieName, null);
0098         if (false === isset($cookieRememberMe)) {
0099             return null;
0100         }
0101         $cookieData = unserialize($cookieRememberMe);
0102         if (empty($cookieData)) {
0103             return null;
0104         }
0105         $sessionData = array();
0106         $sessionData['member_id'] = (int)$cookieData['mi'];
0107         $sessionData['remember_me_id'] = $cookieData['u'];
0108         $sessionData['token'] = isset($cookieData['t']) ? $cookieData['t'] : null;
0109 
0110         return $sessionData;
0111     }
0112 
0113     /**
0114      * @param int $identifier
0115      *
0116      * @return array return new session data
0117      * @throws Exception
0118      */
0119     public function createSession($identifier)
0120     {
0121         $newSessionData = $this->createSessionData($identifier);
0122         $this->setCookie($newSessionData);
0123         $this->saveSessionData($newSessionData);
0124 
0125         return $newSessionData;
0126     }
0127 
0128     /**
0129      * @param int $identifier
0130      *
0131      * @return array
0132      */
0133     protected function createSessionData($identifier)
0134     {
0135         $sessionData = array();
0136         $sessionData['member_id'] = (int)$identifier;
0137         $sessionData['remember_me_id'] = Local_Tools_UUID::generateUUID();
0138         $sessionData['expiry'] = time() + (int)$this->cookieTimeout;
0139         $sessionData['token'] =
0140             base64_encode(hash('sha256', $sessionData['member_id'] . $sessionData['remember_me_id'] . $this->salt));
0141 
0142         return $sessionData;
0143     }
0144 
0145     /**
0146      * @param array $newSessionData
0147      *
0148      * @return bool
0149      */
0150     protected function setCookie($newSessionData)
0151     {
0152         if (empty($newSessionData)) {
0153             return false;
0154         }
0155 
0156         $domain = Local_Tools_ParseDomain::get_domain($this->request->getHttpHost());
0157 
0158         $sessionData = array();
0159         $sessionData['mi'] = $newSessionData['member_id'];
0160         $sessionData['u'] = $newSessionData['remember_me_id'];
0161         $sessionData['t'] = $newSessionData['token'];
0162 
0163         // delete old cookie with wrong domain
0164         //setcookie($this->cookieName, null, time() - $this->cookieTimeout, '/', $this->request->getHttpHost(), null, true);
0165 
0166         return setcookie($this->cookieName, serialize($sessionData), $newSessionData['expiry'], '/', $domain, null, true);
0167     }
0168 
0169     /**
0170      * @param $newSessionData
0171      *
0172      * @return mixed
0173      * @throws Exception
0174      */
0175     protected function saveSessionData($newSessionData)
0176     {
0177         $newSessionData['expiry'] = date('Y-m-d H:i:s', $newSessionData['expiry']); // change to mysql datetime format
0178         $this->dataTable->save($newSessionData);
0179 
0180         return $newSessionData;
0181     }
0182 
0183     /**
0184      * @param array $currentSessionData
0185      * @param array $newSessionData
0186      * @param int   $identifier
0187      *
0188      * @return int count of updated rows
0189      * @throws Zend_Db_Statement_Exception
0190      */
0191     private function updateSessionData($currentSessionData, $newSessionData, $identifier)
0192     {
0193         if (false == isset($currentSessionData) OR (count($currentSessionData) == 0)) {
0194             return null;
0195         }
0196 
0197         $sql =
0198             "UPDATE `session` SET `remember_me_id` = :remember_new, `expiry` = FROM_UNIXTIME(:expiry_new), `changed` = NOW() WHERE `member_id` = :member_id AND `remember_me_id` = :remember_old";
0199 
0200         $result = $this->dataTable->getAdapter()->query($sql, array(
0201             'remember_new' => $newSessionData['remember_me_id'],
0202             'expiry_new'   => $newSessionData['expiry'],
0203             'member_id'    => $identifier,
0204             'remember_old' => $currentSessionData['remember_me_id']
0205         ))
0206         ;
0207 
0208         return $result->rowCount();
0209     }
0210 
0211     public function hasValidCookie()
0212     {
0213         $sessionCookieData = $this->getCookieData();
0214 
0215         return $this->validateCookieData($sessionCookieData);
0216     }
0217 
0218     protected function validateCookieData($currentCookie)
0219     {
0220         if (empty($currentCookie)) {
0221             return false;
0222         }
0223         if (empty($currentCookie['token'])) {
0224             return false;
0225         }
0226         if (empty($currentCookie['member_id']) OR (false == is_int($currentCookie['member_id']))) {
0227             return false;
0228         }
0229         if (empty($currentCookie['remember_me_id'])) {
0230             return false;
0231         }
0232         $cookieToken = base64_decode($currentCookie['token']);
0233         $validateToken = hash('sha256', $currentCookie['member_id'] . $currentCookie['remember_me_id'] . $this->salt);
0234         if ($cookieToken != $validateToken) {
0235             return false;
0236         }
0237 
0238         return true;
0239     }
0240 
0241     public function deleteSession()
0242     {
0243         $currentSessionCookie = $this->getCookieData();
0244         if (empty($currentSessionCookie)) {
0245             return;
0246         }
0247         $this->removeSessionData($currentSessionCookie);
0248         $this->deleteCookie();
0249     }
0250 
0251     /**
0252      * @param array $currentSessionCookie
0253      *
0254      * @return bool
0255      * @throws Zend_Db_Statement_Exception
0256      */
0257     protected function removeSessionData($currentSessionCookie)
0258     {
0259         $sql = "DELETE FROM `session` WHERE `member_id` = :member_id AND `remember_me_id` = :uuid";
0260 
0261         $result = $this->dataTable->getAdapter()->query($sql, array(
0262             'member_id' => $currentSessionCookie['member_id'],
0263             'uuid'      => $currentSessionCookie['remember_me_id']
0264         ))
0265         ;
0266         if ($result->rowCount() > 0) {
0267             return true;
0268         } else {
0269             return false;
0270         }
0271     }
0272 
0273     public function deleteCookie()
0274     {
0275         $domain = Local_Tools_ParseDomain::get_domain($this->request->getHttpHost());
0276         $cookieExpire = time() - $this->cookieTimeout;
0277 
0278         setcookie($this->cookieName, false, $cookieExpire, '/', $this->request->getHttpHost(), null, true);
0279         setcookie($this->cookieName, false, $cookieExpire, '/', $domain, null, true);
0280     }
0281 
0282 }