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

/**
 * Authentication class, containing various static functions used for account verification
 * and session management.
 */
class Authentication
{
	/**
	 * Checks whether a user still exists in the database.
	 */
	public static function checkExists($id_user)
	{
		$res = Registry::get('db')->queryValue('
			SELECT id_user
			FROM users
			WHERE id_user = {int:id}',
			[
				'id' => $id_user,
			]);

		return $res !== null;
	}

	/**
	 * Finds the user id belonging to a certain emailaddress.
	 */
	public static function getUserId($emailaddress)
	{
		$res = Registry::get('db')->queryValue('
			SELECT id_user
			FROM users
			WHERE emailaddress = {string:emailaddress}',
			[
				'emailaddress' => $emailaddress,
			]);

		return empty($res) ? false : $res;
	}

	public static function setResetKey($id_user)
	{
		return Registry::get('db')->query('
			UPDATE users
			SET reset_key = {string:key}
			WHERE id_user = {int:id}',
			[
				'id' => $id_user,
				'key' => self::newActivationKey(),
			]);
	}

	public static function checkResetKey($id_user, $reset_key)
	{
		$key = Registry::get('db')->queryValue('
			SELECT reset_key
			FROM users
			WHERE id_user = {int:id}',
			[
				'id' => $id_user,
			]);

		return $key == $reset_key;
	}

	/**
	 * Verifies whether the user is currently logged in.
	 */
	public static function isLoggedIn()
	{
		// Check whether the active session matches the current user's environment.
		if (isset($_SESSION['ip_address'], $_SESSION['user_agent']) && (
			 (isset($_SERVER['REMOTE_ADDR']) && $_SESSION['ip_address'] != $_SERVER['REMOTE_ADDR']) ||
			 (isset($_SERVER['HTTP_USER_AGENT']) && $_SESSION['user_agent'] != $_SERVER['HTTP_USER_AGENT'])))
		{
			session_destroy();
			return false;
		}

		// A user is logged in if a user id exists in the session and this id is (still) in the database.
		return isset($_SESSION['user_id']) && self::checkExists($_SESSION['user_id']);
	}

	/**
	 * Generates a new activation key.
	 */
	public static function newActivationKey()
	{
		$alpha = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
		$string = '';
		for ($i = 0; $i < 16; $i++)
			$string .= $alpha[mt_rand(0, strlen($alpha) - 1)];
		return $string;
	}

	/**
	 * Checks a password for a given username against the database.
	 */
	public static function checkPassword($emailaddress, $password)
	{
		// Retrieve password hash for user matching the provided emailaddress.
		$password_hash = Registry::get('db')->queryValue('
			SELECT password_hash
			FROM users
			WHERE emailaddress = {string:emailaddress}',
			[
				'emailaddress' => $emailaddress,
			]);

		// If there's no hash, the user likely does not exist.
		if (!$password_hash)
			return false;

		return password_verify($password, $password_hash);
	}

	/**
	 * Computes a password hash.
	 */
	public static function computeHash($password)
	{
		$hash = password_hash($password, PASSWORD_DEFAULT);
		if (!$hash)
			throw new Exception('Hash creation failed!');
		return $hash;
	}

	/**
	 * Resets a password for a certain user.
	 */
	public static function updatePassword($id_user, $hash)
	{
		return Registry::get('db')->query('
			UPDATE users
			SET
				password_hash = {string:hash},
				reset_key = {string:blank}
			WHERE id_user = {int:id_user}',
			[
				'id_user' => $id_user,
				'hash' => $hash,
				'blank' => '',
			]);
	}
}