<?php
/*======================================================================*\
|| #################################################################### ||
|| # vBulletin 3.8.12 - reCAPTCHA v3 (Invisible) Upgrade              # ||
|| # ---------------------------------------------------------------- # ||
|| # Patched by: Antigravity AI Agent                                 # ||
|| #################################################################### ||
\*======================================================================*/

if (!isset($GLOBALS['vbulletin']->db))
{
	exit;
}

/**
* Human Verification class for reCAPTCHA v3 Verification
*
* @package		vBulletin
*/
class vB_HumanVerify_reCAPTCHA extends vB_HumanVerify_Abstract
{
	/**
	* Constructor
	*
	* @return	void
	*/
	public function __construct(&$registry)
	{
		parent::__construct($registry);
	}

	/**
	* displays the reCAPTCHA v3 html/js
	*
	* @return	string
	*/
	public function fetch_library()
	{
		global $stylevar, $vbulletin;

		$humanverify = array();
		$humanverify['theme'] = $this->registry->options['hv_recaptcha_theme'];

		if (preg_match('#^([a-z]{2})-?#i', $stylevar['languagecode'], $matches))
		{
			$humanverify['langcode'] = strtolower($matches[1]);
		}

		$template = fetch_template('humanverify_recaptcha');
		// Fix for unescaped quotes in template causing ParseError
		if (strpos($template, '\"') === false)
		{
			$template = addslashes($template);
		}
		eval('$output = "' . $template . '";');

		return $output;
	}

	/**
	* output the reCAPTCHA v3 token (used by register.php etc)
	*
	* @param	string	Variable prefix
	* @return	string
	*/
	public function output_token($var_prefix = 'humanverify')
	{
		return $this->fetch_library();
	}

	/**
	* verify the v3 token and score
	*
	* @param	array	Values given by user 'input' and 'hash'
	*
	* @return	bool
	*/
	public function verify_token($input)
	{
		// Fallback to $_POST if GPC is not registered
		$token = !empty($this->registry->GPC['g-recaptcha-response']) ? $this->registry->GPC['g-recaptcha-response'] : $_POST['g-recaptcha-response'];

		if (empty($token))
		{
			$this->error = 'humanverify_recaptcha_challenge';
			return false;
		}

		require_once(DIR . '/includes/class_vurl.php');
		$vurl = new vB_vURL($this->registry);
		$vurl->set_option(VURL_URL, 'https://www.google.com/recaptcha/api/siteverify');
		$vurl->set_option(VURL_POST, 1);
		$vurl->set_option(VURL_POSTFIELDS, http_build_query(array(
			'secret'   => $this->registry->options['hv_recaptcha_privatekey'],
			'remoteip' => $this->registry->ipaddress,
			'response' => $token,
		)));
		$vurl->set_option(VURL_RETURNTRANSFER, 1);
		$result = $vurl->exec();

		if ($result)
		{
			// Handle cases where $result is a string (body) or an array (vB_vURL result)
			$body = is_array($result) ? $result['body'] : $result;
			$response = json_decode($body, true);
			
			// For v3, we check success AND score
			if (is_array($response) && !empty($response['success']) && isset($response['score']) && $response['score'] >= 0.5)
			{
				return true;
			}

			if (is_array($response) && isset($response['error-codes']) && is_array($response['error-codes']))
			{
				switch ($response['error-codes'][0])
				{
					case 'missing-input-secret':
					case 'invalid-input-secret':
						$this->error = 'humanverify_recaptcha_privatekey';
						break;
					case 'missing-input-response':
					case 'invalid-input-response':
					case 'timeout-or-duplicate':
						$this->error = 'humanverify_recaptcha_challenge';
						break;
					default:
						$this->error = 'humanverify_recaptcha_parameters';
				}
			}
			else if (is_array($response) && isset($response['success']) && !$response['success'])
			{
				$this->error = 'humanverify_recaptcha_parameters';
			}
			else
			{
				// If score is too low or response is malformed
				$this->error = 'humanverify_recaptcha_parameters';
			}
		}
		else
		{
			$this->error = 'humanverify_recaptcha_unreachable';
		}

		return false;
	}

	/**
	* expected answer - unknown for reCAPTCHA
	*
	* @return	string
	*/
	public function fetch_answer()
	{
		return '';
	}
}
?>