Skip to content

Commit

Permalink
Merge pull request #25 from rtp-cgs/feature/curl-proxy-option
Browse files Browse the repository at this point in the history
Feature/curl proxy option
  • Loading branch information
Benjamin-K authored Dec 4, 2023
2 parents 1a2db45 + bb3d1e1 commit 1903598
Show file tree
Hide file tree
Showing 4 changed files with 172 additions and 15 deletions.
41 changes: 27 additions & 14 deletions Classes/FormElements/Recaptcha.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,44 +71,47 @@ public function onSubmit(FormRuntime $formRuntime, &$elementValue)
return;
}

$requestMethodString = strtolower($this->settings['requestMethod']);
if ($requestMethodString === 'curl') {
$requestMethod = new \ReCaptcha\RequestMethod\CurlPost();
} elseif ($requestMethodString === 'socket') {
$requestMethod = new \ReCaptcha\RequestMethod\SocketPost();
$requestMethodString = $this->settings['requestMethod'];

if (self::isReCaptchaRequestClass($requestMethodString)) {
$requestMethod = new $requestMethodString();
} else {
$requestMethod = new \ReCaptcha\RequestMethod\Post();
$requestMethod = match (strtolower($requestMethodString)) {
'curl' => new \ReCaptcha\RequestMethod\CurlPost(),
'socket' => new \ReCaptcha\RequestMethod\SocketPost(),
default => new \ReCaptcha\RequestMethod\Post(),
};
}

$properties = $this->getProperties();
$recaptcha = new \ReCaptcha\ReCaptcha($properties['secretKey'], $requestMethod);
$recaptcha = new \ReCaptcha\ReCaptcha($properties['secretKey'], $requestMethod);

if (!empty($properties['expectedHostname'])) {
$recaptcha->setExpectedHostname($properties['expectedHostname']);
}
/**
/**
* If one of the following three is set, it is the V3 Captcha.
* Action and Threshold can't be empty due to validators, we still
* Action and Threshold can't be empty due to validators, we still
* need to look if they are set because it could be the V2 Captcha.
*/
if(isset($properties['action'])) {
if (isset($properties['action'])) {
$recaptcha->setExpectedAction($properties['action']);
}
if(isset($properties['threshold'])) {
if (isset($properties['threshold'])) {
$recaptcha->setScoreThreshold($properties['threshold']);
}
/**
* Optional
*/
if(isset($properties['timeout'])) {
if (isset($properties['timeout'])) {
$recaptcha->setChallengeTimeout($properties['timeout']);
}

$resp = $recaptcha->verify($elementValue, $_SERVER['REMOTE_ADDR']);

if ($resp->isSuccess() === false) {

$processingRule =
$processingRule =
$this
->getRootForm()
->getProcessingRule($this->getIdentifier());
Expand All @@ -118,7 +121,7 @@ public function onSubmit(FormRuntime $formRuntime, &$elementValue)
* The Error 'Please check the box "I am not a robot" and try again.'
* Is not suitable for the V3 Captcha.
*/
if(isset($properties['action'])) {
if (isset($properties['action'])) {
$processingRule
->getProcessingMessages()
->addError(
Expand All @@ -139,4 +142,14 @@ public function onSubmit(FormRuntime $formRuntime, &$elementValue)
}
}
}

/**
* @param string $className
*
* @return bool
*/
protected static function isReCaptchaRequestClass(string $className)
{
return class_exists($className) && in_array('ReCaptcha\RequestMethod', class_implements($className), true);
}
}
141 changes: 141 additions & 0 deletions Classes/RequestMethod/CurlPostWithProxy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
<?php

namespace Wegmeister\Recaptcha\RequestMethod;

use ReCaptcha\ReCaptcha;
use ReCaptcha\RequestMethod;
use ReCaptcha\RequestMethod\Curl;
use ReCaptcha\RequestParameters;
use Neos\Flow\Annotations as Flow;

/**
* Copy of \ReCaptcha\RequestMethod\CurlPost()
* adding functionality for curl to work with a http proxy
*/
class CurlPostWithProxy implements RequestMethod
{
/**
* Curl connection to the reCAPTCHA service
*
* @var Curl
*/
private $curl;

/**
* URL for reCAPTCHA siteverify API
*
* @var string
*/
private $siteVerifyUrl;

/**
* Recaptcha settings
*
* @var array
*/
protected $settings;

/**
* @var string
*/
protected $proxyHost;

/**
* @var int
*/
protected $proxyPort;

/**
* Inject the settings
*
* @param array $settings The settings to inject.
*
* @return void
* @throws \Exception
*/
public function injectSettings(array $settings)
{
if (empty($settings['httpProxy'])) {
throw new \Exception("Missing configuration, please add the following settings: 'Wegmeister.Recaptcha.httpProxy'");
}

if(!is_string($settings['httpProxy'])){
throw new \Exception("Invalid configuration, the Wegmeister.Recaptcha.httpProxy option has to be a string.");
}

$httpProxyParts = explode(':', $settings['httpProxy']);
if(count($httpProxyParts) !== 2 || (int)$httpProxyParts[1] === 0){
throw new \Exception("Invalid configuration, the Wegmeister.Recaptcha.httpProxy option should have the following format: 'http://yourproxy.com:1234'");
}

$this->proxyHost = $httpProxyParts[0];
$this->proxyPort = $httpProxyParts[1];

$this->settings = $settings;
}


/**
* Only needed if you want to override the defaults
*
* @param Curl $curl Curl resource
* @param string $siteVerifyUrl URL for reCAPTCHA siteverify API
*/
public function __construct(Curl $curl = null, $siteVerifyUrl = null)
{
$this->curl = (is_null($curl)) ? new Curl() : $curl;
$this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl;
}

/**
* Submit the cURL request with the specified parameters.
*
* @param RequestParameters $params Request parameters
*
* @return string Body of the reCAPTCHA response
*/
public function submit(RequestParameters $params)
{
$handle = $this->curl->init($this->siteVerifyUrl);

$options = [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $params->toQueryString(),
CURLOPT_HTTPHEADER => [
'Content-Type: application/x-www-form-urlencoded',
],
CURLINFO_HEADER_OUT => false,
CURLOPT_HEADER => false,
CURLOPT_RETURNTRANSFER => true,
CURLOPT_SSL_VERIFYPEER => true,
];

$httpProxy = $this->settings['httpProxy'];
$this->emitHttpProxyRetrieved($httpProxy);

$options[CURLOPT_RETURNTRANSFER] = 1;
$options[CURLOPT_PROXY] = $this->proxyHost;
$options[CURLOPT_PROXYPORT] = $this->proxyPort;

$this->curl->setoptArray($handle, $options);

$response = $this->curl->exec($handle);
$this->curl->close($handle);

if ($response !== false) {
return $response;
}

return '{"success": false, "error-codes": ["' . ReCaptcha::E_CONNECTION_FAILED . '"]}';
}

/**
* @param string $httpProxy
*
* @return void
* @Flow\Signal
*/
protected function emitHttpProxyRetrieved(string &$httpProxy)
{
}
}
2 changes: 2 additions & 0 deletions Configuration/Settings.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,5 @@ Wegmeister:
# Available request methods: file_get_contents, curl, socket.
# If an invalid request method is applied, file_get_contents will be used.
requestMethod: 'file_get_contents'
# in the format of <proxy-hostname>:<port>
httpProxy: ''
3 changes: 2 additions & 1 deletion composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"description": "Form Element for the Flow Form Framework integrating Google's Recaptcha",
"require": {
"google/recaptcha": "^1.2",
"neos/form": "^4.0 || ^5.0.9"
"neos/form": "^4.0 || ^5.0.9",
"php": "^8.0"
},
"autoload": {
"psr-4": {
Expand Down

0 comments on commit 1903598

Please sign in to comment.