diff --git a/composer.json b/composer.json index a2e906fe..4d020047 100644 --- a/composer.json +++ b/composer.json @@ -39,7 +39,6 @@ "inc/functions/net.php", "inc/functions/num.php", "inc/functions/theme.php", - "inc/service/captcha-queries.php", "inc/context.php" ] }, diff --git a/inc/Service/HCaptchaQuery.php b/inc/Service/HCaptchaQuery.php new file mode 100644 index 00000000..06e709af --- /dev/null +++ b/inc/Service/HCaptchaQuery.php @@ -0,0 +1,47 @@ +http = $http; + $this->secret = $secret; + $this->sitekey = $sitekey; + } + + public function responseField(): string { + return 'h-captcha-response'; + } + + public function verify(string $response, ?string $remote_ip): bool { + $data = [ + 'secret' => $this->secret, + 'response' => $response, + 'sitekey' => $this->sitekey + ]; + + if ($remote_ip !== null) { + $data['remoteip'] = $remote_ip; + } + + $ret = $this->http->requestGet('https://hcaptcha.com/siteverify', $data); + $resp = \json_decode($ret, true, 16, \JSON_THROW_ON_ERROR); + + return isset($resp['success']) && $resp['success']; + } +} diff --git a/inc/Service/ReCaptchaQuery.php b/inc/Service/ReCaptchaQuery.php new file mode 100644 index 00000000..32c39d3b --- /dev/null +++ b/inc/Service/ReCaptchaQuery.php @@ -0,0 +1,44 @@ +http = $http; + $this->secret = $secret; + } + + public function responseField(): string { + return 'g-recaptcha-response'; + } + + public function verify(string $response, ?string $remote_ip): bool { + $data = [ + 'secret' => $this->secret, + 'response' => $response + ]; + + if ($remote_ip !== null) { + $data['remoteip'] = $remote_ip; + } + + $ret = $this->http->requestGet('https://www.google.com/recaptcha/api/siteverify', $data); + $resp = \json_decode($ret, true, 16, \JSON_THROW_ON_ERROR); + + return isset($resp['success']) && $resp['success']; + } +} diff --git a/inc/Service/RemoteCaptchaQuery.php b/inc/Service/RemoteCaptchaQuery.php new file mode 100644 index 00000000..e525439a --- /dev/null +++ b/inc/Service/RemoteCaptchaQuery.php @@ -0,0 +1,24 @@ +http = $http; + $this->domain = $domain; + $this->provider_check = $provider_check; + $this->extra = $extra; + } + + /** + * Checks if the user at the remote ip passed the native vichan captcha. + * + * @param string $user_text Remote user's text input. + * @param string $user_cookie Remote user cookie. + * @return bool Returns true if the user passed the check. + * @throws RuntimeException Throws on IO errors. + */ + public function verify(string $user_text, string $user_cookie): bool { + $data = [ + 'mode' => 'check', + 'text' => $user_text, + 'extra' => $this->extra, + 'cookie' => $user_cookie + ]; + + $ret = $this->http->requestGet($this->domain . '/' . $this->provider_check, $data); + return $ret === '1'; + } +} diff --git a/inc/context.php b/inc/context.php index 9e5caef0..ee8dce7d 100644 --- a/inc/context.php +++ b/inc/context.php @@ -3,7 +3,7 @@ namespace Vichan; use Vichan\Data\Driver\{CacheDriver, HttpDriver, ErrorLogLogDriver, FileLogDriver, LogDriver, StderrLogDriver, SyslogLogDriver}; use Vichan\Service\HCaptchaQuery; -use Vichan\Service\NativeCaptchaQuery; +use Vichan\Service\SecureImageCaptchaQuery; use Vichan\Service\ReCaptchaQuery; use Vichan\Service\RemoteCaptchaQuery; @@ -71,12 +71,12 @@ function build_context(array $config): Context { throw new \RuntimeException('No remote captcha service available'); } }, - NativeCaptchaQuery::class => function($c) { + SecureImageCaptchaQuery::class => function($c) { $config = $c->get('config'); if ($config['captcha']['provider'] !== 'native') { throw new \RuntimeException('No native captcha service available'); } - return new NativeCaptchaQuery( + return new SecureImageCaptchaQuery( $c->get(HttpDriver::class), $config['domain'], $config['captcha']['native']['provider_check'], diff --git a/inc/service/captcha-queries.php b/inc/service/captcha-queries.php deleted file mode 100644 index 76d7acd8..00000000 --- a/inc/service/captcha-queries.php +++ /dev/null @@ -1,143 +0,0 @@ -http = $http; - $this->secret = $secret; - } - - public function responseField(): string { - return 'g-recaptcha-response'; - } - - public function verify(string $response, ?string $remote_ip): bool { - $data = [ - 'secret' => $this->secret, - 'response' => $response - ]; - - if ($remote_ip !== null) { - $data['remoteip'] = $remote_ip; - } - - $ret = $this->http->requestGet('https://www.google.com/recaptcha/api/siteverify', $data); - $resp = json_decode($ret, true, 16, JSON_THROW_ON_ERROR); - - return isset($resp['success']) && $resp['success']; - } -} - -class HCaptchaQuery implements RemoteCaptchaQuery { - private HttpDriver $http; - private string $secret; - private string $sitekey; - - /** - * Creates a new HCaptchaQuery using the hCaptcha service. - * - * @param HttpDriver $http The http client. - * @param string $secret Server side secret. - * @return HCaptchaQuery A new hCaptcha query instance. - */ - public function __construct(HttpDriver $http, string $secret, string $sitekey) { - $this->http = $http; - $this->secret = $secret; - $this->sitekey = $sitekey; - } - - public function responseField(): string { - return 'h-captcha-response'; - } - - public function verify(string $response, ?string $remote_ip): bool { - $data = [ - 'secret' => $this->secret, - 'response' => $response, - 'sitekey' => $this->sitekey - ]; - - if ($remote_ip !== null) { - $data['remoteip'] = $remote_ip; - } - - $ret = $this->http->requestGet('https://hcaptcha.com/siteverify', $data); - $resp = json_decode($ret, true, 16, JSON_THROW_ON_ERROR); - - return isset($resp['success']) && $resp['success']; - } -} - -interface RemoteCaptchaQuery { - /** - * Name of the response field in the form data expected by the implementation. - * - * @return string The name of the field. - */ - public function responseField(): string; - - /** - * Checks if the user at the remote ip passed the captcha. - * - * @param string $response User provided response. - * @param ?string $remote_ip User ip. Leave to null to only check the response value. - * @return bool Returns true if the user passed the captcha. - * @throws RuntimeException|JsonException Throws on IO errors or if it fails to decode the answer. - */ - public function verify(string $response, ?string $remote_ip): bool; -} - -class NativeCaptchaQuery { - private HttpDriver $http; - private string $domain; - private string $provider_check; - private string $extra; - - /** - * @param HttpDriver $http The http client. - * @param string $domain The server's domain. - * @param string $provider_check Path to the endpoint. - * @param string $extra Extra http parameters. - */ - function __construct(HttpDriver $http, string $domain, string $provider_check, string $extra) { - $this->http = $http; - $this->domain = $domain; - $this->provider_check = $provider_check; - $this->extra = $extra; - } - - /** - * Checks if the user at the remote ip passed the native vichan captcha. - * - * @param string $user_text Remote user's text input. - * @param string $user_cookie Remote user cookie. - * @return bool Returns true if the user passed the check. - * @throws RuntimeException Throws on IO errors. - */ - public function verify(string $user_text, string $user_cookie): bool { - $data = [ - 'mode' => 'check', - 'text' => $user_text, - 'extra' => $this->extra, - 'cookie' => $user_cookie - ]; - - $ret = $this->http->requestGet($this->domain . '/' . $this->provider_check, $data); - return $ret === '1'; - } -} diff --git a/post.php b/post.php index 65c48229..644be70d 100644 --- a/post.php +++ b/post.php @@ -7,7 +7,7 @@ require_once 'inc/bootstrap.php'; use Vichan\{Context, WebDependencyFactory}; use Vichan\Data\Driver\{LogDriver, HttpDriver}; -use Vichan\Service\{RemoteCaptchaQuery, NativeCaptchaQuery}; +use Vichan\Service\{RemoteCaptchaQuery, SecureImageCaptchaQuery}; use Vichan\Functions\Format; /** @@ -516,7 +516,7 @@ if (isset($_POST['delete'])) { } try { - $query = new NativeCaptchaQuery( + $query = new SecureImageCaptchaQuery( $context->get(HttpDriver::class), $config['domain'], $config['captcha']['provider_check'], @@ -636,7 +636,7 @@ if (isset($_POST['delete'])) { // With our custom captcha provider if (($provider === 'native' && !$new_thread_capt) || ($provider === 'native' && $new_thread_capt && $post['op'])) { - $query = $context->get(NativeCaptchaQuery::class); + $query = $context->get(SecureImageCaptchaQuery::class); $success = $query->verify($_POST['captcha_text'], $_POST['captcha_cookie']); if (!$success) {