mirror of
https://github.com/vichan-devel/vichan.git
synced 2024-11-14 19:07:39 +01:00
Share REST call code and separate components via dependency injection
This commit is contained in:
parent
c3de90075e
commit
3016d69428
@ -32,7 +32,9 @@
|
|||||||
"inc/mod/auth.php",
|
"inc/mod/auth.php",
|
||||||
"inc/lock.php",
|
"inc/lock.php",
|
||||||
"inc/queue.php",
|
"inc/queue.php",
|
||||||
"inc/functions.php"
|
"inc/functions.php",
|
||||||
|
"inc/driver/http-driver.php",
|
||||||
|
"inc/service/captcha-queries.php"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"license": "Tinyboard + vichan",
|
"license": "Tinyboard + vichan",
|
||||||
|
@ -1232,6 +1232,8 @@
|
|||||||
$config['error']['captcha'] = _('You seem to have mistyped the verification.');
|
$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_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']['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
|
// Moderator errors
|
||||||
|
28
inc/context.php
Normal file
28
inc/context.php
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
<?php
|
||||||
|
namespace Vichan;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
use Vichan\Driver\{HttpDriver, HttpDrivers};
|
||||||
|
|
||||||
|
|
||||||
|
interface Context {
|
||||||
|
public function getHttpDriver(): HttpDriver;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AppContext implements Context {
|
||||||
|
private array $config;
|
||||||
|
private ?HttpDriver $http;
|
||||||
|
|
||||||
|
|
||||||
|
public function __construct(array $config) {
|
||||||
|
$this->config = $config;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHttpDriver(): HttpDriver {
|
||||||
|
if (is_null($this->http)) {
|
||||||
|
$this->http = HttpDrivers::getHttpDriver($this->config['upload_by_url_timeout'], $this->config['max_filesize']);
|
||||||
|
}
|
||||||
|
return $this->http;
|
||||||
|
}
|
||||||
|
}
|
151
inc/driver/http-driver.php
Normal file
151
inc/driver/http-driver.php
Normal file
@ -0,0 +1,151 @@
|
|||||||
|
<?php // Honestly this is just a wrapper for cURL. Still useful to mock it and have an OOP API on PHP 7.
|
||||||
|
namespace Vichan\Driver;
|
||||||
|
|
||||||
|
use RuntimeException;
|
||||||
|
|
||||||
|
defined('TINYBOARD') or exit;
|
||||||
|
|
||||||
|
|
||||||
|
class HttpDrivers {
|
||||||
|
private const DEFAULT_USER_AGENT = 'Tinyboard';
|
||||||
|
|
||||||
|
|
||||||
|
public static function getHttpDriver(int $timeout, int $max_file_size): HttpDriver {
|
||||||
|
return new HttpDriver($timeout, self::DEFAULT_USER_AGENT, $max_file_size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class HttpDriver {
|
||||||
|
private mixed $inner;
|
||||||
|
private int $timeout;
|
||||||
|
private string $user_agent;
|
||||||
|
private int $max_file_size;
|
||||||
|
|
||||||
|
|
||||||
|
private function resetTowards(string $url, int $timeout): void {
|
||||||
|
curl_reset($this->inner);
|
||||||
|
curl_setopt_array($this->inner, array(
|
||||||
|
CURLOPT_URL => $url,
|
||||||
|
CURLOPT_TIMEOUT => $this->timeout,
|
||||||
|
CURLOPT_USERAGENT => $this->user_agent,
|
||||||
|
CURLOPT_PROTOCOLS => CURLPROTO_HTTP | CURLPROTO_HTTPS,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setSizeLimit(): void {
|
||||||
|
// Adapted from: https://stackoverflow.com/a/17642638
|
||||||
|
curl_setopt($this->inner, CURLOPT_NOPROGRESS, false);
|
||||||
|
|
||||||
|
if (PHP_MAJOR_VERSION >= 8 && PHP_MINOR_VERSION >= 2) {
|
||||||
|
curl_setopt($this->inner, CURLOPT_XFERINFOFUNCTION, function($res, $next_dl, $dl, $next_up, $up) {
|
||||||
|
return (int)($dl <= $this->max_file_size);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
curl_setopt($this->inner, CURLOPT_PROGRESSFUNCTION, function($res, $next_dl, $dl, $next_up, $up) {
|
||||||
|
return (int)($dl <= $this->max_file_size);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function __construct($timeout, $user_agent, $max_file_size) {
|
||||||
|
$this->inner = curl_init();
|
||||||
|
$this->timeout = $timeout;
|
||||||
|
$this->user_agent = $user_agent;
|
||||||
|
$this->max_file_size = $max_file_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
function __destruct() {
|
||||||
|
curl_close($this->inner);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a GET request.
|
||||||
|
*
|
||||||
|
* @param string $endpoint Uri endpoint.
|
||||||
|
* @param ?array $data Optional GET parameters.
|
||||||
|
* @param int $timeout Optional request timeout in seconds. Use the default timeout if 0.
|
||||||
|
* @return string Returns the body of the response.
|
||||||
|
* @throws RuntimeException Throws on IO error.
|
||||||
|
*/
|
||||||
|
public function requestGet(string $endpoint, ?array $data, int $timeout = 0): string {
|
||||||
|
if (!empty($data)) {
|
||||||
|
$endpoint .= '?' . http_build_query($data);
|
||||||
|
}
|
||||||
|
if ($timeout == 0) {
|
||||||
|
$timeout = $this->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resetTowards($endpoint, $timeout);
|
||||||
|
curl_setopt($this->inner, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
$ret = curl_exec($this->inner);
|
||||||
|
|
||||||
|
if ($ret === false) {
|
||||||
|
throw new \RuntimeException(curl_error($this->inner));
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Execute a POST request.
|
||||||
|
*
|
||||||
|
* @param string $endpoint Uri endpoint.
|
||||||
|
* @param ?array $data Optional POST parameters.
|
||||||
|
* @param int $timeout Optional request timeout in seconds. Use the default timeout if 0.
|
||||||
|
* @return string Returns the body of the response.
|
||||||
|
* @throws RuntimeException Throws on IO error.
|
||||||
|
*/
|
||||||
|
public function requestPost(string $endpoint, ?array $data, int $timeout = 0): string {
|
||||||
|
if ($timeout == 0) {
|
||||||
|
$timeout = $this->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resetTowards($endpoint, $timeout);
|
||||||
|
curl_setopt($this->inner, CURLOPT_POST, true);
|
||||||
|
if (!empty($data)) {
|
||||||
|
curl_setopt($this->inner, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||||
|
}
|
||||||
|
curl_setopt($this->inner, CURLOPT_RETURNTRANSFER, true);
|
||||||
|
$ret = curl_exec($this->inner);
|
||||||
|
|
||||||
|
if ($ret === false) {
|
||||||
|
throw new \RuntimeException(curl_error($this->inner));
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Download the url's target with curl.
|
||||||
|
*
|
||||||
|
* @param string $url Url to the file to download.
|
||||||
|
* @param ?array $data Optional GET parameters.
|
||||||
|
* @param resource $fd File descriptor to save the content to.
|
||||||
|
* @param int $timeout Optional request timeout in seconds. Use the default timeout if 0.
|
||||||
|
* @return bool Returns true on success, false if the file was too large.
|
||||||
|
* @throws RuntimeException Throws on IO error.
|
||||||
|
*/
|
||||||
|
public function requestGetInto(string $endpoint, ?array $data, mixed $fd, int $timeout = 0): bool {
|
||||||
|
if (!empty($data)) {
|
||||||
|
$endpoint .= '?' . http_build_query($data);
|
||||||
|
}
|
||||||
|
if ($timeout == 0) {
|
||||||
|
$timeout = $this->timeout;
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->resetTowards($endpoint, $timeout);
|
||||||
|
curl_setopt($this->inner, CURLOPT_FAILONERROR, true);
|
||||||
|
curl_setopt($this->inner, CURLOPT_FOLLOWLOCATION, false);
|
||||||
|
curl_setopt($this->inner, CURLOPT_FILE, $fd);
|
||||||
|
curl_setopt($this->inner, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
||||||
|
$this->setSizeLimit();
|
||||||
|
$ret = curl_exec($this->inner);
|
||||||
|
|
||||||
|
if ($ret === false) {
|
||||||
|
if (curl_errno($this->inner) === CURLE_ABORTED_BY_CALLBACK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new \RuntimeException(curl_error($this->inner));
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
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 withRecaptcha(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 withHCaptcha(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';
|
||||||
|
}
|
||||||
|
}
|
190
post.php
190
post.php
@ -5,6 +5,10 @@
|
|||||||
|
|
||||||
require_once 'inc/bootstrap.php';
|
require_once 'inc/bootstrap.php';
|
||||||
|
|
||||||
|
use Vichan\AppContext;
|
||||||
|
use Vichan\Driver\HttpDriver;
|
||||||
|
use Vichan\Service\{RemoteCaptchaQuery, NativeCaptchaQuery};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Utility functions
|
* Utility functions
|
||||||
*/
|
*/
|
||||||
@ -61,54 +65,27 @@ function strip_symbols($input) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Download the url's target with curl.
|
|
||||||
*
|
|
||||||
* @param string $url Url to the file to download.
|
|
||||||
* @param int $timeout Request timeout in seconds.
|
|
||||||
* @param File $fd File descriptor to save the content to.
|
|
||||||
* @return null|string Returns a string on error.
|
|
||||||
*/
|
|
||||||
function download_file_into($url, $timeout, $fd) {
|
|
||||||
$err = null;
|
|
||||||
$curl = curl_init();
|
|
||||||
curl_setopt($curl, CURLOPT_URL, $url);
|
|
||||||
curl_setopt($curl, CURLOPT_FAILONERROR, true);
|
|
||||||
curl_setopt($curl, CURLOPT_FOLLOWLOCATION, false);
|
|
||||||
curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 5);
|
|
||||||
curl_setopt($curl, CURLOPT_TIMEOUT, $timeout);
|
|
||||||
curl_setopt($curl, CURLOPT_USERAGENT, 'Tinyboard');
|
|
||||||
curl_setopt($curl, CURLOPT_FILE, $fd);
|
|
||||||
curl_setopt($curl, CURLOPT_PROTOCOLS, CURLPROTO_HTTP | CURLPROTO_HTTPS);
|
|
||||||
curl_setopt($curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
|
|
||||||
|
|
||||||
if (curl_exec($curl) === false) {
|
|
||||||
$err = curl_error($curl);
|
|
||||||
}
|
|
||||||
|
|
||||||
curl_close($curl);
|
|
||||||
return $err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Download a remote file from the given url.
|
* Download a remote file from the given url.
|
||||||
* The file is deleted at shutdown.
|
* The file is deleted at shutdown.
|
||||||
*
|
*
|
||||||
|
* @param HttpDriver $http The http client.
|
||||||
* @param string $file_url The url to download the file from.
|
* @param string $file_url The url to download the file from.
|
||||||
* @param int $request_timeout Timeout to retrieve the file.
|
* @param int $request_timeout Timeout to retrieve the file.
|
||||||
* @param array $extra_extensions Allowed file extensions.
|
* @param array $extra_extensions Allowed file extensions.
|
||||||
* @param string $tmp_dir Temporary directory to save the file into.
|
* @param string $tmp_dir Temporary directory to save the file into.
|
||||||
* @param array $error_array An array with error codes, used to create exceptions on failure.
|
* @param array $error_array An array with error codes, used to create exceptions on failure.
|
||||||
* @return array Returns an array describing the file on success.
|
* @return array|false Returns an array describing the file on success, or false if the file was too large
|
||||||
* @throws Exception on error.
|
* @throws InvalidArgumentException|RuntimeException Throws on invalid arguments and IO errors.
|
||||||
*/
|
*/
|
||||||
function download_file_from_url($file_url, $request_timeout, $allowed_extensions, $tmp_dir, &$error_array) {
|
function download_file_from_url(HttpDriver $http, $file_url, $request_timeout, $allowed_extensions, $tmp_dir, &$error_array) {
|
||||||
if (!preg_match('@^https?://@', $file_url)) {
|
if (!preg_match('@^https?://@', $file_url)) {
|
||||||
throw new InvalidArgumentException($error_array['invalidimg']);
|
throw new InvalidArgumentException($error_array['invalidimg']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mb_strpos($file_url, '?') !== false) {
|
$param_idx = mb_strpos($file_url, '?');
|
||||||
$url_without_params = mb_substr($file_url, 0, mb_strpos($file_url, '?'));
|
if ($param_idx !== false) {
|
||||||
|
$url_without_params = mb_substr($file_url, 0, $param_idx);
|
||||||
} else {
|
} else {
|
||||||
$url_without_params = $file_url;
|
$url_without_params = $file_url;
|
||||||
}
|
}
|
||||||
@ -128,10 +105,13 @@ function download_file_from_url($file_url, $request_timeout, $allowed_extensions
|
|||||||
|
|
||||||
$fd = fopen($tmp_file, 'w');
|
$fd = fopen($tmp_file, 'w');
|
||||||
|
|
||||||
$dl_err = download_file_into($fd, $request_timeout, $fd);
|
try {
|
||||||
|
$success = $http->requestGetInto($url_without_params, null, $fd, $request_timeout);
|
||||||
|
if (!$success) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
fclose($fd);
|
fclose($fd);
|
||||||
if ($dl_err !== null) {
|
|
||||||
throw new Exception($error_array['nomove'] . '<br/>Curl says: ' . $dl_err);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
@ -165,6 +145,7 @@ function ocr_image(array $config, string $img_path): string {
|
|||||||
return trim($ret);
|
return trim($ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Trim an image's EXIF metadata
|
* Trim an image's EXIF metadata
|
||||||
*
|
*
|
||||||
@ -190,6 +171,7 @@ function strip_image_metadata(string $img_path): int {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
$dropped_post = false;
|
$dropped_post = false;
|
||||||
|
$context = new AppContext($config);
|
||||||
|
|
||||||
// Is it a post coming from NNTP? Let's extract it and pretend it's a normal post.
|
// Is it a post coming from NNTP? Let's extract it and pretend it's a normal post.
|
||||||
if (isset($_GET['Newsgroups']) && $config['nntpchan']['enabled']) {
|
if (isset($_GET['Newsgroups']) && $config['nntpchan']['enabled']) {
|
||||||
@ -487,23 +469,33 @@ if (isset($_POST['delete'])) {
|
|||||||
if (count($report) > $config['report_limit'])
|
if (count($report) > $config['report_limit'])
|
||||||
error($config['error']['toomanyreports']);
|
error($config['error']['toomanyreports']);
|
||||||
|
|
||||||
if ($config['report_captcha'] && !isset($_POST['captcha_text'], $_POST['captcha_cookie'])) {
|
|
||||||
|
if ($config['report_captcha']) {
|
||||||
|
if (!isset($_POST['captcha_text'], $_POST['captcha_cookie'])) {
|
||||||
error($config['error']['bot']);
|
error($config['error']['bot']);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($config['report_captcha']) {
|
try {
|
||||||
$ch = curl_init($config['domain'].'/'.$config['captcha']['provider_check'] . "?" . http_build_query([
|
$query = new NativeCaptchaQuery(
|
||||||
'mode' => 'check',
|
$context->getHttpDriver(),
|
||||||
'text' => $_POST['captcha_text'],
|
$config['domain'],
|
||||||
'extra' => $config['captcha']['extra'],
|
$config['captcha']['provider_check']
|
||||||
'cookie' => $_POST['captcha_cookie']
|
);
|
||||||
]));
|
$success = $query->verify(
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
$config['captcha']['extra'],
|
||||||
$resp = curl_exec($ch);
|
$_POST['captcha_text'],
|
||||||
|
$_POST['captcha_cookie']
|
||||||
|
);
|
||||||
|
|
||||||
if ($resp !== '1') {
|
if (!$success) {
|
||||||
error($config['error']['captcha']);
|
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']);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$reason = escape_markup_modifiers($_POST['reason']);
|
$reason = escape_markup_modifiers($_POST['reason']);
|
||||||
@ -598,62 +590,60 @@ if (isset($_POST['delete'])) {
|
|||||||
// Check if banned
|
// Check if banned
|
||||||
checkBan($board['uri']);
|
checkBan($board['uri']);
|
||||||
|
|
||||||
// Check for CAPTCHA right after opening the board so the "return" link is in there
|
// Check for CAPTCHA right after opening the board so the "return" link is in there.
|
||||||
if ($config['recaptcha']) {
|
try {
|
||||||
if (!isset($_POST['g-recaptcha-response']))
|
// With our custom captcha provider
|
||||||
error($config['error']['bot']);
|
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...
|
if (!$success) {
|
||||||
$resp = json_decode(file_get_contents(sprintf('https://www.recaptcha.net/recaptcha/api/siteverify?secret=%s&response=%s&remoteip=%s',
|
error(
|
||||||
$config['recaptcha_private'],
|
$config['error']['captcha']
|
||||||
urlencode($_POST['g-recaptcha-response']),
|
. '<script>if (actually_load_captcha !== undefined) actually_load_captcha("'
|
||||||
$_SERVER['REMOTE_ADDR'])), true);
|
. $config['captcha']['provider_get']
|
||||||
|
.'", "'
|
||||||
if (!$resp['success']) {
|
. $config['captcha']['extra']
|
||||||
error($config['error']['captcha']);
|
. '");</script>'
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// 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::withRecaptcha($context->getHttpDriver(), $config['recaptcha_private']);
|
||||||
|
}
|
||||||
// hCaptcha
|
// hCaptcha
|
||||||
if ($config['hcaptcha']) {
|
elseif ($config['hcaptcha']) {
|
||||||
if (!isset($_POST['h-captcha-response'])) {
|
if (!isset($_POST['h-captcha-response'])) {
|
||||||
error($config['error']['bot']);
|
error($config['error']['bot']);
|
||||||
}
|
}
|
||||||
|
$response = $_POST['g-recaptcha-response'];
|
||||||
|
$query = RemoteCaptchaQuery::withHCaptcha($context->getHttpDriver(), $config['hcaptcha_private']);
|
||||||
|
}
|
||||||
|
|
||||||
$data = array(
|
$success = $query->verify($response, $_SERVER['REMOTE_ADDR']);
|
||||||
'secret' => $config['hcaptcha_private'],
|
if (!$success) {
|
||||||
'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']);
|
error($config['error']['captcha']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Same, but now with our custom captcha provider
|
} catch (RuntimeException $e) {
|
||||||
if (($config['captcha']['enabled']) || (($post['op']) && ($config['new_thread_capt'])) ) {
|
if ($config['syslog']) {
|
||||||
$ch = curl_init($config['domain'].'/'.$config['captcha']['provider_check'] . "?" . http_build_query([
|
_syslog(LOG_ERR, "Captcha IO exception: {$e->getMessage()}");
|
||||||
'mode' => 'check',
|
}
|
||||||
'text' => $_POST['captcha_text'],
|
error($config['error']['remote_io_error']);
|
||||||
'extra' => $config['captcha']['extra'],
|
} catch (JsonException $e) {
|
||||||
'cookie' => $_POST['captcha_cookie']
|
if ($config['syslog']) {
|
||||||
]));
|
_syslog(LOG_ERR, "Bad JSON reply to captcha: {$e->getMessage()}");
|
||||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
}
|
||||||
$resp = curl_exec($ch);
|
error($config['error']['remote_io_error']);
|
||||||
|
}
|
||||||
|
|
||||||
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']) ||
|
if (!(($post['op'] && $_POST['post'] == $config['button_newtopic']) ||
|
||||||
(!$post['op'] && $_POST['post'] == $config['button_reply'])))
|
(!$post['op'] && $_POST['post'] == $config['button_reply'])))
|
||||||
@ -757,7 +747,21 @@ if (isset($_POST['delete'])) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$_FILES['file'] = download_file_from_url($_POST['file_url'], $config['upload_by_url_timeout'], $allowed_extensions, $config['tmp'], $config['error']);
|
$ret = download_file_from_url(
|
||||||
|
$context->getHttpDriver(),
|
||||||
|
$_POST['file_url'],
|
||||||
|
$config['upload_by_url_timeout'],
|
||||||
|
$allowed_extensions,
|
||||||
|
$config['tmp'],
|
||||||
|
$config['error']
|
||||||
|
);
|
||||||
|
if ($ret === false) {
|
||||||
|
error(sprintf3($config['error']['filesize'], array(
|
||||||
|
'filesz' => 'more than that',
|
||||||
|
'maxsz' => number_format($config['max_filesize'])
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
$_FILES['file'] = $ret;
|
||||||
} catch (Exception $e) {
|
} catch (Exception $e) {
|
||||||
error($e->getMessage());
|
error($e->getMessage());
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user