<?php

/* 
* 
* StopBotters Model, this should be the same for all plugins. 
* However, the following steps should be updated *1 -> *4
*/


class Tac_FoolBotHoneyPot_Model_StopBotters extends XenForo_Model
{

	public function stopBottersErrors($pluginName, $input, $apiKey, $validateIP = 1, $validateEmail = 1, $validateUsername = 1)
	{
			
		// then check the local db for this IP address 
		if (!$responseError = $this->localStopBottersResponse())
		{
			// a stopBotters report and request at the same time will be faster (don't need to wait for 2 respsonses)
			$responseError = $this->repquest($pluginName, $input, $apiKey, $validateIP, $validateEmail, $validateUsername);
			// add the resonse for this IP address locally so we do need to re-request if this IP address occurs with the next hour
			$this->localStopBottersSubmit($responseError);
		}

		if($responseError == "Bot not detected") // prevents repeated local submits of human attempts
		{
			return;	
		}
	
		
			
		return $responseError;
	}	

	public function getLocalStopBottersById($id)
	{
		return $this->_getDb()->fetchRow('
			SELECT *
			FROM sf_stopbotters
			WHERE id = ?
		', $id);
	}
	
		
	public function localStopBottersSubmit($response = "")
	{	
		$ip_address = $this->getIp();
		$known_bot = ($response ? 1 : 0);		
		$sbWriter = XenForo_DataWriter::create('Tac_FoolBotHoneyPot_DataWriter_StopBotters');
		$sbWriter->set('ip_address', $ip_address);
		$sbWriter->set('known_bot', $known_bot);
		$sbWriter->set('time_stamp', time());
		$sbWriter->save();					
	}
	
	public function localStopBottersResponse()
	{	
		$timeLim = time() - 300; // only get response if less than 5 minutes old (limits the query size, and bots dont often try for more than 5 mis)
		$ip_address = $this->getIp();	
		
		$row = $this->_getDb()->fetchRow('
			SELECT *
			FROM sf_stopbotters
			WHERE ip_address = ?
			AND time_stamp > ?
		', array($ip_address, $timeLim));
		
		$errors = array();

		// we are only doing a local IP look up, so if we find a match, send the IP response back		
		if($row && $row["known_bot"] == 1)
		{
			
			$errors[] = new XenForo_Phrase('fbhp_stopbotters_found_the_following_param_in_their_database').' ip_address: '.$ip_address;
			return $errors;
		}
		
		if($row && $row["known_bot"] == 0)
		{
			return "Bot not detected";
		}
		
		return false;
		
	}
	

	
	/*
	* Combines sendToStopBotters and isKnownBot, but only one request needed
	*/
	
	public function repquest($pluginName, $input = "", $apiKey, $validateIP = 1, $validateEmail = 1, $validateUsername = 1)
	{
		
		$email_address = '';
		$username = '';
		
		if($input)
		{	
			$data = $input->filter(array(
				'username'   => XenForo_Input::STRING,
				'email'      => XenForo_Input::STRING,
			)); 
			// This will genreally be true... except when we have FBHP installed 
			// (I know...! It does unusual things you wouldn't usualy do... It's a pest.. but very effective!) 		
			$username = $data['username'];
			$email_address = $data['email'];
					
			$addOnModel = $this->getModelFromCache('XenForo_Model_AddOn');
			if (($addon = $addOnModel->getAddOnById('FoolBotHoneyPot')) && !empty($addon['active']) )
			{
				$uuids = $this->getModelFromCache('Tac_FoolBotHoneyPot_Model_HoneyPot')->getFeildUUIDs();			 
				$uuidData = $input->filter(array(
					$uuids['1']  => XenForo_Input::STRING, // 'visible to humans username'
					$uuids['2']  => XenForo_Input::STRING, // 'visible to humans email'
				));	
				
				// set username & email if visible is populated		
				// but if invisable ones have been chnaged, use them
				$username = ($data['username'] != "abaf1b4e8d0e34afa3" ? $data['username'] : $uuidData[$uuids['1']]); // 'visible to humans username'
				$email_address = 	($data['email'] != "x@819978f0-0b0f-11e2-892e-0800200c9a66.com" ? $data['email'] : $uuidData[$uuids['2']]); // 'visible to humans email'
				
			}
		}
		
		$ip = $this->getIp();		
		
		$updatePath = XenForo_Link::buildPublicLink('register/key-update-fbhp');
		$updateUrl = XenForo_Link::convertUriToAbsoluteUri($updatePath, true);
		
		$u = ($validateUsername == 1 ? 1 : 0); 
		$i = ($validateIP == 1 ? 1 : 0); 
		$e = ($validateEmail == 1 ? 1 : 0);  
			
		$jsonRequest = 'http://www.stopbotters.com/repquest.php?opt=1&ip_address='.$ip.
					($username ? '&username='.rawurlencode($username) : '').
					($email_address ? '&email='.rawurlencode($email_address) : '').
					'&server_name='.$_SERVER['SERVER_NAME'].
					'&detection_method='.$pluginName.
					'&key='.$apiKey.
					'&u='.$u.'&i='.$i.'&e='.$e.
					'&update='.$updateUrl;
		
		
		try
		{
			
			// first check session (since response will not change in session, IP will stay the same)
			$jsonResponse = XenForo_Application::getSession()->get('SBJsonResponse');
			
			if(!$jsonResponse)
			{
				$client = XenForo_Helper_Http::getClient($jsonRequest);
				$jsonResponse = $client->request('GET');
				XenForo_Application::getSession()->set('SBJsonResponse', $jsonResponse);	
			}
			
			
			

			if ($jsonResponse && $jsonResponse->getStatus() == 200)
			{
				
				$json = json_decode($jsonResponse->getBody(),true);
				if($json == NULL)
				{	    		
		   	 		return false;
				}				
				
				
				
				if($json)
				{
					// return errors depending on what params are found for this bot
					$errors = array();
					if(($json['ip_address'] == $ip) && ($validateIP == 1))
					{
						$errors[] = new XenForo_Phrase('fbhp_stopbotters_found_the_following_param_in_their_database').' ip_address: '.$ip; // *4 update (and below) to your own phrase (I havent passed the array in, since this phrase should be set by the plugin)
					}
					if(strtolower($json['email_address']) == strtolower($email_address) && ($validateEmail == 1))
					{
						$errors[] = new XenForo_Phrase('fbhp_stopbotters_found_the_following_param_in_their_database').' email_address: '.$email_address;
					}
					if(strtolower($json['username']) == strtolower($username) && ($validateUsername == 1))
					{
						$errors[] = new XenForo_Phrase('fbhp_stopbotters_found_the_following_param_in_their_database').' username: '.$username;
					}
					
						
					
					if($errors)
					{
						return $errors;
					}		
				}
			}
			
			return false;
		}
		catch (Zend_Http_Exception $e)
		{
			// no need to do anything, if the JSON site is down we don't want to stop registration / throw up errors to the user
			//XenForo_Error::logException($e, false);
		}
	

	}

	
	/*
	* Alow StopBotters to update the key so that requests can only be made by authorised sites
	*/
	public function updateKey($input = "", $apiKey)
	{
		// only update the key if
		// 1) The previous key sent is correct 
		// 2) The new key is the correct format
				
		if(!$input)
		{
			return false;
		}

		$data = $input->filter(array(
			'oldKey'   => XenForo_Input::STRING,
			'newKey'      => XenForo_Input::STRING,
		)); 
		
					
		$oldKey = $data['oldKey'];
		$newKey = $data['newKey'];

		if($oldKey != $apiKey)
		{
			return false;
		}		

		$optionId = $this->getOptionIdbyValue($apiKey);
			
		$db = $this->_getDb();
		XenForo_Db::beginTransaction($db);			
		$dw = XenForo_DataWriter::create('XenForo_DataWriter_Option');
		$dw->setExistingData($optionId);
		$dw->setOption(XenForo_DataWriter_Option::OPTION_REBUILD_CACHE, false);
		$dw->set('option_value', $newKey);
		$dw->save();
		$this->getModelFromCache('XenForo_Model_Option')->rebuildOptionCache();
		XenForo_Db::commit($db);

		return true;
	}
	
	/*
	* a dynamic way to get the OptionId for the api key (less params needed to set up stopBotters in the actionRegister)
	* The OptionId will be different for each plugin
	* This is only called if we already have the correct API key 
	*/
	
	public function getOptionIdbyValue($val) 
	{
		return $this->_getDb()->fetchRow('
			SELECT option_id
			FROM xf_option 
			WHERE option_value = ?
			AND addon_id = \'FoolBotHoneyPot\'
		', $val);
	}

	/*
	* send back the Data array
	* Also check for dynamic uuids of FBHP	
	*/
	public function getData($input)
	{
		
		$data = $input->filter(array(
				'username'   => XenForo_Input::STRING,
				'email'      => XenForo_Input::STRING,
				'timezone'   => XenForo_Input::STRING,
				'gender'     => XenForo_Input::STRING,
				'dob_day'    => XenForo_Input::UINT,
				'dob_month'  => XenForo_Input::UINT,
				'dob_year'   => XenForo_Input::UINT,
			));
		
		$addOnModel = $this->getModelFromCache('XenForo_Model_AddOn');
		if (($addon = $addOnModel->getAddOnById('FoolBotHoneyPot')) && !empty($addon['active']) )
		{
			$uuids = $this->getModelFromCache('Tac_FoolBotHoneyPot_Model_HoneyPot')->getFeildUUIDs();			 
			$uuidData = $input->filter(array(
				$uuids['1']  => XenForo_Input::STRING, // 'visible to humans username'
				$uuids['2']  => XenForo_Input::STRING, // 'visible to humans email'
				$uuids['5']  => XenForo_Input::STRING, // 'visible timezone'
				$uuids['6']  => XenForo_Input::STRING, // 'visible gender'
			));	

			 	 
				$data['username'] 		= $uuidData[$uuids['1']]; // 'visible to humans username'
				$data['email'] 			= $uuidData[$uuids['2']]; // 'visible to humans email'
				$data['timezone'] 		= $uuidData[$uuids['5']]; // 'visible timezone'
				$data['gender'] 		= $uuidData[$uuids['6']]; // 'visible gender'
		}
	
		return $data;
			
	}
	
	

	public function getIp($ipAddress = null)
	{
		if ($ipAddress === null)
		{
			return (isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : 0);
		}
	}

	
	
	
	public function convertIpToLong($ipAddress = null)
	{
		if ($ipAddress === null)
		{
			$ipAddress = $this->getIp();
		}

		if (is_string($ipAddress) && strpos($ipAddress, '.'))
		{
			$ipAddress = ip2long($ipAddress);
		}
		return sprintf('%u', $ipAddress);
	}


}



