. */ /* Default values */ define('_IT_SESSION_COOKIE', 'SESSION'); define('_IT_SESSION_COOKIE_EXPIRY', 0); define('_IT_SESSION_LIFETIME', 3600); class it_session { /* PRIVATE */ var $cookiename; /* Cookie to store session */ var $cookie; /* Session identifier of this session */ var $uid; /* Session user id */ var $domain = ''; /* Session domain (e.g. ".relog.ch") */ var $address = ''; /* Guessed IP address of client */ var $ssl; /* Session using SSL? */ var $lifetime; /* Session life-time in seconds */ var $secret; /* Session secret to generate session ids */ var $now; /* This session start time slot */ var $prev; /* Previous session start time slot */ var $hascookies; /* Do cookies work? Used by has_cookies() */ /* Constructor */ function __construct() { $this->cookiename = _IT_SESSION_COOKIE; $this->lifetime = _IT_SESSION_LIFETIME; /* * NOTE: Does not work with dynamic IPs (dialup with low timeout, * load balanced Proxies and maybe more weird stuff). * $this->address = $_SERVER['REMOTE_ADDR'] . '/' . $_SERVER['HTTP_X_FORWARDED_FOR']; */ $this->ssl = !empty($_SERVER['HTTPS']) && !$GLOBALS['ULTRATRUSTED']; # No SSL cookies for trusted IPs because Chrome does not overwrite SSL cookies with non-SSL ones and thus prevents login to devel after live, reported by David } function set_cookiename($cookiename) { if ($cookiename) $this->cookiename = $cookiename; } function get_uid() { return $this->uid; } function set_uid($uid) { $this->uid = $uid; } function set_domain($domain) { $this->domain = $domain; } function set_lifetime($lifetime) { $this->lifetime = $lifetime; } function set_secret($secret) { $this->secret = $secret; } function init() { if (empty($this->secret)) it::fatal('it_session requires secret to be set'); /* Got a cookie? */ if ($this->hascookies = isset($_COOKIE[$this->cookiename]) && is_string($_COOKIE[$this->cookiename])) $this->cookie = $_COOKIE[$this->cookiename]; else $this->cookie = ''; #debug("hascookies '$this->hascookies', '$this->cookie', " . $_COOKIE[$this->cookiename]); $now = time(); /* * Valid time range is now - 1/2 lifetime to now + 1/2 lifetime * I.e. session has to be either from start or now */ $this->now = $now - ($now % ($this->lifetime / 2)); $this->prev = $this->now - ($this->lifetime / 2); /* Set user id from valid session */ $this->uid = substr($this->cookie, 1, strlen($this->cookie) - 33); if (!$this->is_valid()) $this->uid = ""; #debug("it_session::new session=$this->cookie, user=$this->uid"); } /* INTERNAL: Create session id from session data */ function _mkcookie($uid, $timeslot) { return "A" . $uid . md5("$uid,$this->domain,$this->address,$this->secret,$timeslot"); } /* Check if this session is valid */ function is_valid() { $result = true; if ($this->_mkcookie($this->uid, $this->now) != $this->cookie) { /* Check if using id from previous time slot */ if ($this->_mkcookie($this->uid, $this->prev) == $this->cookie) $this->set_valid(); /* Rejuvenate session */ else $result = false; } return $result; } /* * Validate this session * @param $valid Should this session be validated or invalidated? * @param $login_identifier_required Does session validation require login magic? * @param $login_identifier Session validation magic cookie to be checked * @return true if successful */ function set_valid($valid = true, $login_identifier_required = false, $login_identifier = "") { $result = false; if ($valid && (!$login_identifier_required || ($login_identifier == $this->_mkcookie("", $this->cookie)))) { $this->cookie = $this->_mkcookie($this->uid, $this->now); $result = true; } else { $this->cookie = bin2hex(random_bytes(16)); /* random garbage */ $result = !$valid; /* Setting to invalid succeeded or setting to valid failed */ } it::setcookie($this->cookiename, $this->cookie, [ 'expires' => _IT_SESSION_COOKIE_EXPIRY, 'path' => "/", 'domain' => $this->domain, 'secure' => $this->ssl, 'httponly' => true, 'samesite' => _IT_USER_COOKIE_SAMESITE ]); $_COOKIE[$this->cookiename] = $this->cookie; return $result; } function purge() { $this->cookie = ""; $_COOKIE[$this->cookiename] = ""; $this->uid = ""; } /* * Create a login identifier and set session to login identifier 'secret' value * Returns a value to be put into the login
which has to be passed to * set_valid() to create a valid session */ function create_login_identifier() { if (!$this->cookie) { $this->cookie = bin2hex(random_bytes(16)); /* random garbage */ it::setcookie($this->cookiename, $this->cookie, [ 'expires' => _IT_SESSION_COOKIE_EXPIRY, 'path' => "/", 'domain' => $this->domain, 'secure' => $this->ssl, 'httponly' => true, 'samesite' => _IT_USER_COOKIE_SAMESITE ]); } $login_identifier = $this->_mkcookie("", $this->cookie); return $login_identifier; } /* * Check if cookies are enabled. * NOTE: Only works if you used create_login_identifier() on previous page */ function has_cookies() { return $this->hascookies; } /* * Sign string for current session * @param $text Text to be signed * @return Signature for $text */ function _sign($text, $timeslot) { return "B" . md5("$text,$this->uid,$this->domain,$this->address,$this->secret,$timeslot"); } /* * Sign string for current session * @param $text Text to be signed * @return Signature for $text */ function create_signature($text) { return $this->_sign($text, $this->now); } /* * Check signature for string for current session * @param $text Text which was signed * @param $signature Signature to be checked * @return True if signature ok, false otherwise */ function check_signature($text, $signature) { return (($this->_sign($text, $this->now) == $signature) || ($this->_sign($text, $this->prev) == $signature)); } } /* End class it_session */