<?php

class XenForo_ControllerHelper_Login extends XenForo_ControllerHelper_Abstract
{
	public function userTfaConfirmationRequired(array $user)
	{
		$tfaModel = $this->_getTfaModel();

		if (!XenForo_Application::getConfig()->enableTfa)
		{
			return false;
		}

		if ($user['use_tfa'] && $tfaModel->userRequiresTfa($user['user_id']))
		{
			$trustedKey = $this->getUserTfaTrustedKey();
			if ($trustedKey && $tfaModel->getUserTrustedRecord($user['user_id'], $trustedKey))
			{
				// computer is trusted
			}
			else
			{
				return true;
			}
		}

		return false;
	}

	public function getUserTfaTrustedKey()
	{
		return XenForo_Helper_Cookie::getCookie('tfa_trust', $this->_controller->getRequest());
	}

	public function tfaRedirectIfRequiredPublic($userId, $redirect, $remember)
	{
		$user = $this->_getUserModel()->getFullUserById($userId);
		if (!$user)
		{
			return;
		}

		if ($this->userTfaConfirmationRequired($user))
		{
			$this->setTfaSessionCheck($user['user_id']);

			$response = $this->_controller->responseRedirect(
				XenForo_ControllerResponse_Redirect::SUCCESS,
				XenForo_Link::buildPublicLink('login/two-step', null, array(
					'redirect' => $redirect,
					'remember' => $remember ? 1 : 0
				))
			);
			throw $this->_controller->responseException($response);
		}
	}

	public function setTfaSessionCheck($userId)
	{
		$session = XenForo_Application::getSession();
		$session->set('tfaLoginUserId', $userId);
		$session->set('tfaLoginDate', time());
	}

	public function clearTfaSessionCheck()
	{
		$session = XenForo_Application::getSession();
		$session->remove('tfaLoginUserId');
		$session->remove('tfaLoginDate');
	}

	public function getUserForTfaCheck()
	{
		$session = XenForo_Application::getSession();
		$loginUserId = $session->get('tfaLoginUserId');

		if (XenForo_Visitor::getUserId() || !$loginUserId)
		{
			return null;
		}

		$tfaLoginDate = $session->get('tfaLoginDate');
		if (!$tfaLoginDate || time() - $tfaLoginDate > 900)
		{
			return null;
		}

		$user = $this->_getUserModel()->getFullUserById($loginUserId);
		if (!$user)
		{
			return null;
		}

		return $user;
	}

	public function triggerTfaCheck(array $user, $providerId, array $providers, array $userData)
	{
		if ($providerId && isset($providers[$providerId]))
		{
			$provider = $providers[$providerId];
		}
		else
		{
			/** @var XenForo_Tfa_AbstractProvider $provider */
			$provider = reset($providers);
		}

		$providerId = $provider->getProviderId();
		$providerData = unserialize($userData[$providerId]['provider_data']);

		$triggerData = $provider->triggerVerification(
			'login', $user, $this->_controller->getRequest()->getClientIp(false), $providerData
		);
		$this->_getTfaModel()->updateUserProvider($user['user_id'], $providerId, $providerData, true);

		return $viewParams = array(
			'providers' => $this->_getTfaModel()->prepareTfaProviderList($providers, $userData),

			'providerId' => $providerId,
			'provider' => $provider,
			'user' => $user,
			'providerData' => $providerData,
			'triggerData' => $triggerData
		);
	}

	public function assertNotTfaAttemptLimited($userId)
	{
		if ($this->_getTfaModel()->isTfaAttemptLimited($userId))
		{
			$controller = $this->_controller;
			throw $controller->responseException(
				$controller->responseError(new XenForo_Phrase('your_account_has_temporarily_been_locked_due_to_failed_login_attempts'))
			);
		}
	}

	public function runTfaValidation(array $user, $providerId, array $providers, array $userData)
	{
		if (!$providerId || !isset($providers[$providerId]))
		{
			return null;
		}

		/** @var XenForo_Tfa_AbstractProvider $provider */
		$provider = $providers[$providerId];
		$providerData = unserialize($userData[$providerId]['provider_data']);

		if (!$provider->verifyFromInput('login', $this->_controller->getInput(), $user, $providerData))
		{
			$this->_getTfaModel()->logFailedTfaAttempt($user['user_id']);

			return false;
		}

		$this->_getTfaModel()->updateUserProvider($user['user_id'], $providerId, $providerData, true);
		$this->_getTfaModel()->clearTfaAttemptsForUser($user['user_id']);

		return true;
	}

	public function setDeviceTrusted($userId)
	{
		$key = $this->_getTfaModel()->createTrustedKey($userId);
		XenForo_Helper_Cookie::setCookie('tfa_trust', $key, 86400 * 45, true);

		return $key;
	}

	/**
	 * @return XenForo_Model_User
	 */
	protected function _getUserModel()
	{
		return $this->_controller->getModelFromCache('XenForo_Model_User');
	}

	/**
	 * @return XenForo_Model_Tfa
	 */
	protected function _getTfaModel()
	{
		return $this->_controller->getModelFromCache('XenForo_Model_Tfa');
	}
}