mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-27 17:00:52 +01:00
Add CaptchaQueries
This commit is contained in:
parent
819ce71c55
commit
dc903017ca
@ -1210,6 +1210,8 @@
|
||||
$config['error']['captcha'] = _('You seem to have mistyped the verification.');
|
||||
$config['error']['flag_undefined'] = _('The flag %s is undefined, your PHP version is too old!');
|
||||
$config['error']['flag_wrongtype'] = _('defined_flags_accumulate(): The flag %s is of the wrong type!');
|
||||
$config['error']['remote_io_error'] = _('IO error while interacting with a remote service.');
|
||||
$config['error']['local_io_error'] = _('IO error while interacting with a local resource or service.');
|
||||
|
||||
|
||||
// Moderator errors
|
||||
|
102
inc/service/captcha-queries.php
Normal file
102
inc/service/captcha-queries.php
Normal file
@ -0,0 +1,102 @@
|
||||
<?php // Verify captchas server side.
|
||||
namespace Vichan\Service;
|
||||
|
||||
use Vichan\Driver\HttpDriver;
|
||||
|
||||
defined('TINYBOARD') or exit;
|
||||
|
||||
|
||||
class RemoteCaptchaQuery {
|
||||
private HttpDriver $http;
|
||||
private string $secret;
|
||||
private string $endpoint;
|
||||
|
||||
|
||||
/**
|
||||
* Creates a new CaptchaRemoteQueries instance using the google recaptcha service.
|
||||
*
|
||||
* @param HttpDriver $http The http client.
|
||||
* @param string $secret Server side secret.
|
||||
* @return CaptchaRemoteQueries A new captcha query instance.
|
||||
*/
|
||||
public static function with_recaptcha(HttpDriver $http, string $secret): RemoteCaptchaQuery {
|
||||
return new self($http, $secret, 'https://www.google.com/recaptcha/api/siteverify');
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new CaptchaRemoteQueries instance using the hcaptcha service.
|
||||
*
|
||||
* @param HttpDriver $http The http client.
|
||||
* @param string $secret Server side secret.
|
||||
* @return CaptchaRemoteQueries A new captcha query instance.
|
||||
*/
|
||||
public static function with_hcaptcha(HttpDriver $http, string $secret): RemoteCaptchaQuery {
|
||||
return new self($http, $secret, 'https://hcaptcha.com/siteverify');
|
||||
}
|
||||
|
||||
private function __construct(HttpDriver $http, string $secret, string $endpoint) {
|
||||
$this->http = $http;
|
||||
$this->secret = $secret;
|
||||
$this->endpoint = $endpoint;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user at the remote ip passed the captcha.
|
||||
*
|
||||
* @param string $response User provided response.
|
||||
* @param string $remote_ip User ip.
|
||||
* @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 {
|
||||
$data = array(
|
||||
'secret' => $this->secret,
|
||||
'response' => $response,
|
||||
'remoteip' => $remote_ip
|
||||
);
|
||||
|
||||
$ret = $this->http->requestGet($this->endpoint, $data);
|
||||
$resp = json_decode($ret, true, 16, JSON_THROW_ON_ERROR);
|
||||
|
||||
return isset($resp['success']) && $resp['success'];
|
||||
}
|
||||
}
|
||||
|
||||
class NativeCaptchaQuery {
|
||||
private HttpDriver $http;
|
||||
private string $domain;
|
||||
private string $provider_check;
|
||||
|
||||
|
||||
/**
|
||||
* @param HttpDriver $http The http client.
|
||||
* @param string $domain The server's domain.
|
||||
* @param string $provider_check Path to the endpoint.
|
||||
*/
|
||||
function __construct(HttpDriver $http, string $domain, string $provider_check) {
|
||||
$this->http = $http;
|
||||
$this->domain = $domain;
|
||||
$this->provider_check = $provider_check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the user at the remote ip passed the native vichan captcha.
|
||||
*
|
||||
* @param string $extra Extra http parameters.
|
||||
* @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 $extra, string $user_text, string $user_cookie): bool {
|
||||
$data = array(
|
||||
'mode' => 'check',
|
||||
'text' => $user_text,
|
||||
'extra' => $extra,
|
||||
'cookie' => $user_cookie
|
||||
);
|
||||
|
||||
$ret = $this->http->requestGet($this->domain . '/' . $this->provider_check, $data);
|
||||
return $ret === '1';
|
||||
}
|
||||
}
|
136
post.php
136
post.php
@ -7,6 +7,7 @@ require_once 'inc/bootstrap.php';
|
||||
|
||||
use Vichan\AppContext;
|
||||
use Vichan\Driver\HttpDriver;
|
||||
use Vichan\Service\{RemoteCaptchaQuery, NativeCaptchaQuery};
|
||||
|
||||
/**
|
||||
* Utility functions
|
||||
@ -144,6 +145,7 @@ function ocr_image(array $config, string $img_path): string {
|
||||
return trim($ret);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Method handling functions
|
||||
*/
|
||||
@ -447,22 +449,32 @@ if (isset($_POST['delete'])) {
|
||||
if (count($report) > $config['report_limit'])
|
||||
error($config['error']['toomanyreports']);
|
||||
|
||||
if ($config['report_captcha'] && !isset($_POST['captcha_text'], $_POST['captcha_cookie'])) {
|
||||
error($config['error']['bot']);
|
||||
}
|
||||
|
||||
if ($config['report_captcha']) {
|
||||
$ch = curl_init($config['domain'].'/'.$config['captcha']['provider_check'] . "?" . http_build_query([
|
||||
'mode' => 'check',
|
||||
'text' => $_POST['captcha_text'],
|
||||
'extra' => $config['captcha']['extra'],
|
||||
'cookie' => $_POST['captcha_cookie']
|
||||
]));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$resp = curl_exec($ch);
|
||||
if (!isset($_POST['captcha_text'], $_POST['captcha_cookie'])) {
|
||||
error($config['error']['bot']);
|
||||
}
|
||||
|
||||
if ($resp !== '1') {
|
||||
error($config['error']['captcha']);
|
||||
try {
|
||||
$query = new NativeCaptchaQuery(
|
||||
$context->getHttpDriver(),
|
||||
$config['domain'],
|
||||
$config['captcha']['provider_check']
|
||||
);
|
||||
$success = $query->verify(
|
||||
$config['captcha']['extra'],
|
||||
$_POST['captcha_text'],
|
||||
$_POST['captcha_cookie']
|
||||
);
|
||||
|
||||
if (!$success) {
|
||||
error($config['error']['captcha']);
|
||||
}
|
||||
} catch (RuntimeException $e) {
|
||||
if ($config['syslog']) {
|
||||
_syslog(LOG_ERR, "Native captcha IO exception: {$e->getMessage()}");
|
||||
}
|
||||
error($config['error']['local_io_error']);
|
||||
}
|
||||
}
|
||||
|
||||
@ -552,62 +564,60 @@ if (isset($_POST['delete'])) {
|
||||
// Check if banned
|
||||
checkBan($board['uri']);
|
||||
|
||||
// Check for CAPTCHA right after opening the board so the "return" link is in there
|
||||
if ($config['recaptcha']) {
|
||||
if (!isset($_POST['g-recaptcha-response']))
|
||||
error($config['error']['bot']);
|
||||
// Check for CAPTCHA right after opening the board so the "return" link is in there.
|
||||
try {
|
||||
// With our custom captcha provider
|
||||
if ($config['captcha']['enabled'] || ($post['op'] && $config['new_thread_capt'])) {
|
||||
$query = new NativeCaptchaQuery($context->getHttpDriver(), $config['domain'], $config['captcha']['provider_check']);
|
||||
$success = $query->verify($config['captcha']['extra'], $_POST['captcha_text'], $_POST['captcha_cookie']);
|
||||
|
||||
// Check what reCAPTCHA has to say...
|
||||
$resp = json_decode(file_get_contents(sprintf('https://www.recaptcha.net/recaptcha/api/siteverify?secret=%s&response=%s&remoteip=%s',
|
||||
$config['recaptcha_private'],
|
||||
urlencode($_POST['g-recaptcha-response']),
|
||||
$_SERVER['REMOTE_ADDR'])), true);
|
||||
|
||||
if (!$resp['success']) {
|
||||
error($config['error']['captcha']);
|
||||
if (!$success) {
|
||||
error(
|
||||
$config['error']['captcha']
|
||||
. '<script>if (actually_load_captcha !== undefined) actually_load_captcha("'
|
||||
. $config['captcha']['provider_get']
|
||||
.'", "'
|
||||
. $config['captcha']['extra']
|
||||
. '");</script>'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
// hCaptcha
|
||||
if ($config['hcaptcha']) {
|
||||
if (!isset($_POST['h-captcha-response'])) {
|
||||
error($config['error']['bot']);
|
||||
// Remote 3rd party captchas.
|
||||
else {
|
||||
// recaptcha
|
||||
if ($config['recaptcha']) {
|
||||
if (!isset($_POST['g-recaptcha-response'])) {
|
||||
error($config['error']['bot']);
|
||||
}
|
||||
$response = $_POST['g-recaptcha-response'];
|
||||
$query = RemoteCaptchaQuery::with_recaptcha($context->getHttpDriver(), $config['recaptcha_private']);
|
||||
}
|
||||
// hCaptcha
|
||||
elseif ($config['hcaptcha']) {
|
||||
if (!isset($_POST['h-captcha-response'])) {
|
||||
error($config['error']['bot']);
|
||||
}
|
||||
$response = $_POST['g-recaptcha-response'];
|
||||
$query = RemoteCaptchaQuery::with_hcaptcha($context->getHttpDriver(), $config['hcaptcha_private']);
|
||||
}
|
||||
|
||||
$success = $query->verify($response, $_SERVER['REMOTE_ADDR']);
|
||||
if (!$success) {
|
||||
error($config['error']['captcha']);
|
||||
}
|
||||
}
|
||||
|
||||
$data = array(
|
||||
'secret' => $config['hcaptcha_private'],
|
||||
'response' => $_POST['h-captcha-response'],
|
||||
'remoteip' => $_SERVER['REMOTE_ADDR']
|
||||
);
|
||||
|
||||
$hcaptchaverify = curl_init();
|
||||
curl_setopt($hcaptchaverify, CURLOPT_URL, "https://hcaptcha.com/siteverify");
|
||||
curl_setopt($hcaptchaverify, CURLOPT_POST, true);
|
||||
curl_setopt($hcaptchaverify, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||
curl_setopt($hcaptchaverify, CURLOPT_RETURNTRANSFER, true);
|
||||
$hcaptcharesponse = curl_exec($hcaptchaverify);
|
||||
|
||||
$resp = json_decode($hcaptcharesponse, true); // Decoding $hcaptcharesponse instead of $response
|
||||
|
||||
if (!$resp['success']) {
|
||||
error($config['error']['captcha']);
|
||||
} catch (RuntimeException $e) {
|
||||
if ($config['syslog']) {
|
||||
_syslog(LOG_ERR, "Captcha IO exception: {$e->getMessage()}");
|
||||
}
|
||||
error($config['error']['remote_io_error']);
|
||||
} catch (JsonException $e) {
|
||||
if ($config['syslog']) {
|
||||
_syslog(LOG_ERR, "Bad JSON reply to captcha: {$e->getMessage()}");
|
||||
}
|
||||
error($config['error']['remote_io_error']);
|
||||
}
|
||||
// Same, but now with our custom captcha provider
|
||||
if (($config['captcha']['enabled']) || (($post['op']) && ($config['new_thread_capt'])) ) {
|
||||
$ch = curl_init($config['domain'].'/'.$config['captcha']['provider_check'] . "?" . http_build_query([
|
||||
'mode' => 'check',
|
||||
'text' => $_POST['captcha_text'],
|
||||
'extra' => $config['captcha']['extra'],
|
||||
'cookie' => $_POST['captcha_cookie']
|
||||
]));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$resp = curl_exec($ch);
|
||||
|
||||
if ($resp !== '1') {
|
||||
error($config['error']['captcha'] .
|
||||
'<script>if (actually_load_captcha !== undefined) actually_load_captcha("'.$config['captcha']['provider_get'].'", "'.$config['captcha']['extra'].'");</script>');
|
||||
}
|
||||
}
|
||||
|
||||
if (!(($post['op'] && $_POST['post'] == $config['button_newtopic']) ||
|
||||
(!$post['op'] && $_POST['post'] == $config['button_reply'])))
|
||||
|
Loading…
Reference in New Issue
Block a user