167 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
			
		
		
	
	
			167 lines
		
	
	
		
			3.8 KiB
		
	
	
	
		
			PHP
		
	
	
	
	
	
<?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
 | 
						|
{
 | 
						|
	const DEFAULT_RESET_TIMEOUT = 30;
 | 
						|
 | 
						|
	/**
 | 
						|
	 * 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 = :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);
 | 
						|
	}
 | 
						|
 | 
						|
	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;
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * 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;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function consumeResetKey($id_user)
 | 
						|
	{
 | 
						|
		return Registry::get('db')->query('
 | 
						|
			UPDATE users
 | 
						|
			SET reset_key = NULL,
 | 
						|
				reset_blocked_until = NULL
 | 
						|
			WHERE id_user = {int:id_user}',
 | 
						|
			['id_user' => $id_user]);
 | 
						|
	}
 | 
						|
 | 
						|
	public static function getResetTimeOut($id_user)
 | 
						|
	{
 | 
						|
		$resetTime = Registry::get('db')->queryValue('
 | 
						|
			SELECT reset_blocked_until
 | 
						|
			FROM users
 | 
						|
			WHERE id_user = {int:id_user}',
 | 
						|
			['id_user' => $id_user]);
 | 
						|
 | 
						|
		return max(0, $resetTime - time());
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Verifies whether the user is currently logged in.
 | 
						|
	 */
 | 
						|
	public static function isLoggedIn()
 | 
						|
	{
 | 
						|
		if (!isset($_SESSION['user_id']))
 | 
						|
			return false;
 | 
						|
 | 
						|
		try
 | 
						|
		{
 | 
						|
			$exists = Member::fromId($_SESSION['user_id']);
 | 
						|
			return true;
 | 
						|
		}
 | 
						|
		catch (NotFoundException $e)
 | 
						|
		{
 | 
						|
			return false;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * 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;
 | 
						|
	}
 | 
						|
 | 
						|
	public static function setResetKey($id_user)
 | 
						|
	{
 | 
						|
		return Registry::get('db')->query('
 | 
						|
			UPDATE users
 | 
						|
			SET reset_key = {string:key},
 | 
						|
				reset_blocked_until = UNIX_TIMESTAMP() + ' . static::DEFAULT_RESET_TIMEOUT . '
 | 
						|
			WHERE id_user = {int:id}',
 | 
						|
			[
 | 
						|
				'id' => $id_user,
 | 
						|
				'key' => self::newActivationKey(),
 | 
						|
			]);
 | 
						|
	}
 | 
						|
 | 
						|
	/**
 | 
						|
	 * Resets a password for a certain user.
 | 
						|
	 */
 | 
						|
	public static function updatePassword($id_user, $hash)
 | 
						|
	{
 | 
						|
		return Registry::get('db')->query('
 | 
						|
			UPDATE users
 | 
						|
			SET
 | 
						|
				password_hash = :hash,
 | 
						|
				reset_key = :blank
 | 
						|
			WHERE id_user = :id_user',
 | 
						|
			[
 | 
						|
				'id_user' => $id_user,
 | 
						|
				'hash' => $hash,
 | 
						|
				'blank' => '',
 | 
						|
			]);
 | 
						|
	}
 | 
						|
 | 
						|
	public static function updateResetTimeOut($id_user)
 | 
						|
	{
 | 
						|
		$currentResetTimeOut = static::getResetTimeOut($id_user);
 | 
						|
 | 
						|
		// New timeout: between 30 seconds, double the current timeout, and a full day
 | 
						|
		$newResetTimeOut = min(max(static::DEFAULT_RESET_TIMEOUT, $currentResetTimeOut * 2), 60 * 60 * 24);
 | 
						|
 | 
						|
		$success = Registry::get('db')->query('
 | 
						|
			UPDATE users
 | 
						|
			SET reset_blocked_until = {int:new_time_out}
 | 
						|
			WHERE id_user = {int:id_user}',
 | 
						|
			[
 | 
						|
				'id_user' => $id_user,
 | 
						|
				'new_time_out' => time() + $newResetTimeOut,
 | 
						|
			]);
 | 
						|
 | 
						|
		if (!$success)
 | 
						|
			throw new UnexpectedValueException('Could not set password reset timeout!');
 | 
						|
 | 
						|
		return $newResetTimeOut;
 | 
						|
	}
 | 
						|
}
 |