<?php
/**
 * ###############################################
 *
 * SWIFT Framework
 * _______________________________________________
 *
 * @author		Varun Shoor
 *
 * @package		SWIFT
 * @copyright	Copyright (c) 2001-2012, Kayako
 * @license		http://www.kayako.com/license
 * @link		http://www.kayako.com
 *
 * ###############################################
 */

/**
 * The User Controller
 *
 * @author Varun Shoor
 */
class Controller_User extends Controller_client
{
	/**
	 * Constructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __construct()
	{
		parent::__construct();

		$this->Language->Load('users');

		return true;
	}

	/**
	 * Destructor
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 */
	public function __destruct()
	{
		parent::__destruct();

		return true;
	}

	/**
	 * Login the user
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function Login()
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		/*
		 * BUG FIX - Ravi Sharma <ravi.sharma@kayako.com>
		 *
		 * SWIFT-3743 A Cross Site Request Forgery error on accessing /?/Base/User/Login if user is already logged in.
		 */
		if (($_SWIFT->Session->IsLoggedIn() && $_SWIFT->User instanceof SWIFT_User && $_SWIFT->User->GetIsClassLoaded()))
		{
			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		if (isset($_POST['scemail']) && $_POST['scemail'] != $this->Language->Get('loginenteremail'))
		{
			$this->Template->Assign('_userLoginEmail', htmlspecialchars($_POST['scemail']));
		}

		/**
		 * BUG FIX - Ravi Sharma <ravi.sharma@kayako.com>
		 *
		 * SWIFT-4248 Security issue (medium)
		 *
		 * Comments: System should automate the login if user is using remember me.
		 */
		$_cookieLoginEmail    = $this->Cookie->Get('scloginemail', true);
		$_cookieLoginPassword = $this->Cookie->Get('scloginpassword', true);
		$_cookieHashCheck     = $this->Cookie->Get('schashcheck');
		$_skipCSRF            = false;

		if (!empty($_cookieLoginEmail) && !empty($_cookieLoginPassword) && $_cookieHashCheck == sha1(SWIFT::Get('InstallationHash')) && empty($_POST['scemail'])) {
			$_POST['scemail']    = $_cookieLoginEmail;
			$_POST['scpassword'] = $_cookieLoginPassword;
			$_POST['rememberme'] = true;
			$_skipCSRF           = true;
		}

		/*
		 * BUG FIX - Ravi Sharma
		 *
		 * SWIFT-3445 CSRF in Login Functionality
		 *
		 * Comment: None
		 */
		// BEGIN CSRF HASH CHECK
		if (!$_skipCSRF && !in_array('header (Default)', SWIFT_Template::GetUpgradeRevertList()) && (!isset($_POST['_csrfhash']) || !SWIFT_Session::CheckCSRFHash($_POST['_csrfhash']))) {
			$this->UserInterface->Error(true, $this->Language->Get('msgcsrfhash'));

			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		// END CSRF HASH CHECK

		// Check for sanity of data
		if (!isset($_POST['scemail']) || !isset($_POST['scpassword']) || empty($_POST['scemail']) || empty($_POST['scpassword']))
		{
			$this->UserInterface->Error(true, $this->Language->Get('invaliduser'));

			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		/**
		 * Feature FIX : Saloni Dhall <saloni.dhall@kayako.com>
		 *
		 * SWIFT-4561 : Login failure lockout attempts lockout in the support center for end-users
		 *
		 */
		// Before Login, check to see if we can really log in this user..
		$_loginLogCheck = SWIFT_UserLoginLog::CanUserLogin($_POST['scemail']);
		if (!$_loginLogCheck[0]) {

			$_errorString = sprintf($this->Language->Get('loginlogerror'), round(SWIFT_UserLoginLog::GetLoginTimeline() / 60), $_loginLogCheck[1], SWIFT_UserLoginLog::GetLoginRetries());

			$this->UserInterface->Error(true, $_errorString);

			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		$_authenticationResult = SWIFT_User::Authenticate($_POST['scemail'], $_POST['scpassword'], true);

		// Authentication failed?
		if (!$_authenticationResult) {
			$this->Cookie->Delete('scloginemail');
			$this->Cookie->Delete('scloginpassword');

			$_errorString = SWIFT::Get('errorstring');

			if ($_SWIFT->Settings->Get('security_scloginlocked') == '1' && strcmp($_errorString, $_SWIFT->Language->Get('invaliduser')) == 0) {

				// Log the Login Attempt First
				SWIFT_UserLoginLog::Failure(array($_POST['scemail']), SWIFT_UserLoginLog::INTERFACE_CLIENT);

				$_loginLogCheck = SWIFT_UserLoginLog::CanUserLogin($_POST['scemail']);
				if ($_loginLogCheck[0] && $_loginLogCheck[1] > 0) {

					$_errorStringText = $this->Language->Get('loginlogwarning');

					$_errorString = sprintf($_errorStringText, $_loginLogCheck[1], SWIFT_UserLoginLog::GetLoginRetries());
				} else {
					$_errorString = sprintf($this->Language->Get('loginlogerror'), round(SWIFT_UserLoginLog::GetLoginTimeline() / 60), $_loginLogCheck[1], SWIFT_UserLoginLog::GetLoginRetries());
				}
			}

			$this->UserInterface->Error(true, $_errorString);

			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		// Check for sanity of loaded object
		if (!$_SWIFT->User instanceof SWIFT_User || !$_SWIFT->User->GetIsClassLoaded())
		{
			$this->UserInterface->Error(true, $this->Language->Get('invaliduser'));

			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		// Check for template group restriction..
		if ($_SWIFT->TemplateGroup->GetProperty('restrictgroups') == '1' && $_SWIFT->TemplateGroup->GetRegisteredUserGroupID() != $_SWIFT->User->GetProperty('usergroupid'))
		{
			$this->UserInterface->Error(true, $this->Language->Get('invalidusertgroupres'));

			$this->Load->Controller('Default')->Load->Index();

			return false;
		}

		// So by now we have the user object, we need to update the session record..
		$_SWIFT->Session->Update($_SWIFT->User->GetUserID());

		// Log the Login Attempt First
		SWIFT_UserLoginLog::Success($_SWIFT->User, SWIFT_UserLoginLog::INTERFACE_CLIENT);

		// Did the user check remember me?
		if (isset($_POST['rememberme']) && $_POST['rememberme'] == 1)
		{
			$this->Cookie->Set('schashcheck', sha1(SWIFT::Get('InstallationHash')), true, false);
			$this->Cookie->Set('scloginemail', $_POST['scemail'], true, true);
			$this->Cookie->Set('scloginpassword', $_POST['scpassword'], true, true);
		}

		/**
		 * Begin Hook: client_userlogin
		 */

		unset($_hookCode);
		($_hookCode = SWIFT_Hook::Execute('client_userlogin')) ? eval($_hookCode) : false;

		/**
		 * End Hook
		 */

		$_templateGroupCache = $this->Cache->Get('templategroupcache');
		$_templateGroupString = '';

		// If we dont have a custom template group to load and theres one set in cookie.. attempt to use it..
		if ($this->Cookie->GetVariable('client', 'templategroupid')) {
			$_templateGroupID = intval($this->Cookie->GetVariable('client', 'templategroupid'));
			$_templateGroupString = '/'.$_templateGroupCache[$_templateGroupID]['title'];
		}

		if ($_SWIFT->TemplateGroup->GetRegisteredUserGroupID() != $_SWIFT->User->GetProperty('usergroupid')) {
			foreach ($_templateGroupCache as $_key => $_val) {
				if ($_val["regusergroupid"] == $_SWIFT->User->GetProperty('usergroupid')) {
					$_templateGroupString = '/'.$_val["title"];
					break;
				}
			}
		}

		$_redirectAction = false;
		if (isset($_POST['_redirectAction']) && !empty($_POST['_redirectAction'])) {
			$_redirectAction = SWIFT::Get('basename') . $_templateGroupString.$_POST['_redirectAction'];
		}

		if (!empty($_redirectAction) && !strstr($_redirectAction, '/UserLostPassword/') && !strstr($_redirectAction, '/UserRegistration/')
				&& !strstr($_redirectAction, '/User/Login') && !strstr($_redirectAction, '/Backend/Order') && !strstr($_redirectAction, '/Backend/Trial')) {
			header("location: " . $_redirectAction);

			return true;
		}

		if ($_SWIFT->User->GetProperty('profileprompt') == '0')
		{
			// Redirect..
			header("location: " . SWIFT::Get('basename') . $_templateGroupString. '/Base/UserAccount/Profile/1');
		} else {
			// Redirect..
			header("location: " . SWIFT::Get('basename'). $_templateGroupString);
		}

		return true;
	}

	/**
	 * Log the user out
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function Logout()
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		// At the time of logout request, the entry must gets deleted from swsessions table.
		if ($_SWIFT->User instanceof SWIFT_User && $_SWIFT->User->GetIsClassLoaded()) {
			$_userID = $_SWIFT->User->GetUserID();
		} else {
			$_userID = 0;
		}

		$_SWIFT->Session->Update($_userID);

		// Destroying cookies...
		$this->Cookie->Delete('scloginemail');
		$this->Cookie->Delete('scloginpassword');

		// Redirect..
		header("location: " . SWIFT::Get('basename'));

		return true;
	}

	/**
	 * Retrieve the Profile Image
	 *
	 * @author Varun Shoor
	 * @param int $_userID The User ID
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function GetProfileImage($_userID = 0)
	{
		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);
		} else if (empty($_userID) || !is_numeric($_userID)) {
			return false;
		}

		/**
		 * BUG FIX - Ravi Sharma <ravi.sharma@kayako.com>
		 *
		 * SWIFT-4364 Security Issue.
		 *
		 * Comments: Suppressing the exceptions with try statement.
		 */
		try {
			$_SWIFT_UserObject             = new SWIFT_User(new SWIFT_DataID($_userID));
			$_SWIFT_UserProfileImageObject = SWIFT_UserProfileImage::RetrieveOnUser($_SWIFT_UserObject->GetUserID());
		} catch (SWIFT_Exception $_SWIFT_ExceptionObject) {
			return false;
		}

		if (!$_SWIFT_UserProfileImageObject instanceof SWIFT_UserProfileImage || !$_SWIFT_UserProfileImageObject->GetIsClassLoaded()) {
			return false;
		}

		$_SWIFT_UserProfileImageObject->Output();

		return true;
	}

	/**
	 * Display the Avatar
	 *
	 * @author Varun Shoor
	 * @param int $_userID The User ID
	 * @param string $_emailAddressHash (OPTIONAL) The Email Address Hash
	 * @param int $_preferredWidth (OPTIONAL) The Preferred Width
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function DisplayAvatar($_userID, $_emailAddressHash = '', $_preferredWidth = 60)
	{
		if (!$this->GetIsClassLoaded())
		{
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		}

		SWIFT_ProfileImage::OutputOnUserID($_userID, $_emailAddressHash, $_preferredWidth);

		return true;
	}

	/**
	 * Login from Staff CP
	 *
	 * @author Varun Shoor
	 * @return bool "true" on Success, "false" otherwise
	 * @throws SWIFT_Exception If the Class is not Loaded
	 */
	public function LoginFromStaff()
	{
		$_SWIFT = SWIFT::GetInstance();

		if (!$this->GetIsClassLoaded()) {
			throw new SWIFT_Exception(SWIFT_CLASSNOTLOADED);

			return false;
		} else if (!$_SWIFT->User instanceof SWIFT_User || !$_SWIFT->User->GetIsClassLoaded()) {
			throw new SWIFT_Exception('Unable to login as user. Invalid user object detected.');
		}

		$this->UserInterface->Info(true, sprintf($this->Language->Get('loggedinfromstaff'), htmlspecialchars($_SWIFT->User->GetProperty('fullname'))));

		$this->Load->Controller('Default')->Load->Index();

		return true;
	}
}
?>
