<?php
/**
* @package RSForm! Pro
* @copyright (C) 2007-2022 www.rsjoomla.com
* @license GPL, http://www.gnu.org/copyleft/gpl.html
*/

defined('_JEXEC') or die;

use Joomla\CMS\HTML\HTMLHelper;
use Joomla\CMS\Language\Text;
use Joomla\CMS\Factory;
use Joomla\CMS\Http\HttpFactory;

require_once JPATH_ADMINISTRATOR.'/components/com_rsform/helpers/field.php';

class RSFormProFieldTurnstile extends RSFormProField
{
	// backend preview
	public function getPreviewInput()
	{
		return HTMLHelper::_('image', 'plg_system_rsfpturnstile/turnstile.png', 'Cloudflare Turnstile', null, true);
	}
	
	// functions used for rendering in front view
	public function getFormInput()
	{
		$formId			= $this->formId;
		$componentId	= $this->componentId;

		// If no site key has been setup, just show a warning
		$siteKey = RSFormProHelper::getConfig('turnstile.sitekey');
		if (!$siteKey)
		{
			return '<div>'.Text::_('PLG_SYSTEM_RSFPTURNSTILE_NO_SITE_KEY').'</div>';
		}

		// Need to load scripts one-time.
		$this->loadScripts();

		$attribs = array(
			'class' 	   => 'cf-turnstile',
			'data-sitekey' => $siteKey
		);

		$theme = strtolower($this->getProperty('THEME'));
		if ($theme !== 'autotheme')
		{
			$attribs['data-theme'] = $theme;
		}

		$out = '<div id="cf-turnstile-'.$componentId.'"';
		foreach ($attribs as $key => $value)
		{
			$out .= ' ' . htmlspecialchars($key, ENT_COMPAT, 'utf-8') . '="' . htmlspecialchars($value, ENT_COMPAT, 'utf-8') . '"';
		}
		$out .= '></div>';

		// Clear the token on page refresh
		Factory::getSession()->clear('com_rsform.turnstileCaptchaToken'.$formId);

		return $out;
	}

	public function processValidation($validationType = 'form', $submissionId = 0)
	{
		// Skip directory editing since it makes no sense
		if ($validationType == 'directory')
		{
			return true;
		}

		$formId 	 = $this->formId;
		$form       = RSFormProHelper::getForm($formId);
		$logged		= $form->RemoveCaptchaLogged ? Factory::getUser()->id : false;
		$secretKey 	= RSFormProHelper::getConfig('turnstile.secret');

		// validation:
		// if there's no session token
		// validate based on challenge & response codes
		// if valid, set the session token

		// session token gets cleared after form processes
		// session token gets cleared on page refresh as well

		if (!$secretKey)
		{
			Factory::getApplication()->enqueueMessage(Text::_('PLG_SYSTEM_RSFPTURNSTILE_MISSING_INPUT_SECRET'), 'error');
			return false;
		}

		if (!$logged)
		{
			$input 	  = Factory::getApplication()->input;
			$session  = Factory::getSession();
			$response = $input->post->get('cf-turnstile-response', '', 'raw');
			$task	  = strtolower($input->get('task', ''));
			$option	  = strtolower($input->get('option', ''));
			$isAjax	  = $option == 'com_rsform' && $task == 'ajaxvalidate';
			$isPage   = $input->getInt('page');

			// Already validated, move on
			if ($session->get('com_rsform.turnstileCaptchaToken'.$formId))
			{
				return true;
			}

			// Ajax requests don't validate Captcha on page change
			if ($isAjax && $isPage)
			{
				return true;
			}

			try
			{
				$http = HttpFactory::getHttp();
				if ($request = $http->post('https://challenges.cloudflare.com/turnstile/v0/siteverify', array('secret' => $secretKey, 'response' => $response)))
				{
					$json = json_decode($request->body);
				}
			}
			catch (Exception $e)
			{
				Factory::getApplication()->enqueueMessage($e->getMessage(), 'error');
				return false;
			}

			if (empty($json->success) || !$json->success)
			{
				if (!empty($json) && isset($json->{'error-codes'}) && is_array($json->{'error-codes'}))
				{
					foreach ($json->{'error-codes'} as $code)
					{
						Factory::getApplication()->enqueueMessage(Text::_('PLG_SYSTEM_RSFPTURNSTILE_'.strtoupper(str_replace('-', '_', $code))), 'error');
					}
				}

				return false;
			}
			elseif ($isAjax)
			{
				$session->set('com_rsform.turnstileCaptchaToken'.$formId, md5(uniqid($response)));
			}
		}

		return true;
	}

	protected function loadScripts()
	{
		static $loaded;

		if (!$loaded)
		{
			$loaded = true;

			RSFormProAssets::addCustomTag('<script src="https://challenges.cloudflare.com/turnstile/v0/api.js" async defer></script>');
		}
	}
}