<?php
/*****************************************************************************
 * Session.php
 * Contains the key class Session.
 *
 * Kabuki CMS (C) 2013-2015, Aaron van Geffen
 *****************************************************************************/

class Session
{
	public static function start()
	{
		session_start();

		// Resuming an existing session? Check what we know!
		if (isset($_SESSION['user_id'], $_SESSION['ip_address'], $_SESSION['user_agent']))
		{
			// If we're not browsing over HTTPS, protect against session hijacking.
			if (!isset($_SERVER['HTTPS']) && isset($_SERVER['REMOTE_ADDR']) && $_SESSION['ip_address'] !== $_SERVER['REMOTE_ADDR'])
			{
				$_SESSION = [];
				throw new UserFacingException('Your session failed to validate: your IP address has changed. Please re-login and try again.');
			}
			// Either way, require re-login if the browser identifier has changed.
			elseif (isset($_SERVER['HTTP_USER_AGENT']) && $_SESSION['user_agent'] !== $_SERVER['HTTP_USER_AGENT'])
			{
				$_SESSION = [];
				throw new UserFacingException('Your session failed to validate: your browser identifier has changed. Please re-login and try again.');
			}
		}
		elseif (!isset($_SESSION['ip_address'], $_SESSION['user_agent']))
			$_SESSION = [
				'ip_address' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : '',
				'user_agent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : '',
			];

		return true;
	}

	public static function resetSessionToken()
	{
		$_SESSION['session_token'] = sha1(session_id() . mt_rand());
		$_SESSION['session_token_key'] = substr(preg_replace('~^\d+~', '', sha1(mt_rand() . session_id() . mt_rand())), 0, rand(7, 12));
		return true;
	}

	public static function validateSession($method = 'post')
	{
		// First, check whether the submitted token and key match the ones in storage.
		if (($method === 'post' && (!isset($_POST[$_SESSION['session_token_key']]) || $_POST[$_SESSION['session_token_key']] !== $_SESSION['session_token'])) ||
			($method === 'get' && (!isset($_GET[$_SESSION['session_token_key']]) || $_GET[$_SESSION['session_token_key']] !== $_SESSION['session_token'])))
			throw new UserFacingException('Session failed to verify (' . $method . '). Please reload the page and try again.');

		// Check the referring site, too -- should be the same site!
		$referring_host = isset($_SERVER['HTTP_REFERER']) ? parse_url($_SERVER['HTTP_REFERER'], PHP_URL_HOST) : '';
		if (!empty($referring_host))
		{
			if (strpos($_SERVER['HTTP_HOST'], ':') !== false)
				$current_host = substr($_SERVER['HTTP_HOST'], 0, strpos($_SERVER['HTTP_HOST'], ':'));
			else
				$current_host = $_SERVER['HTTP_HOST'];

			$base_url_host = parse_url(BASEURL, PHP_URL_HOST);

			// The referring_host must match either the base_url_host or the current_host.
			if (strtolower($referring_host) !== strtolower($base_url_host) && strtolower($referring_host) !== strtolower($current_host))
				throw new UserFacingException('Invalid referring URL. Please reload the page and try again.');
		}

		// All looks good from here! But you can only use this token once, so...
		return self::resetSessionToken();
	}

	public static function getSessionToken()
	{
		if (empty($_SESSION['session_token']))
			trigger_error('Call to getSessionToken without a session token being set!', E_USER_ERROR);

		return $_SESSION['session_token'];
	}

	public static function getSessionTokenKey()
	{
		if (empty($_SESSION['session_token_key']))
			trigger_error('Call to getSessionTokenKey without a session token key being set!', E_USER_ERROR);

		return $_SESSION['session_token_key'];
	}
}