mirror of
https://github.com/torrentpier/torrentpier
synced 2025-08-21 05:43:55 -07:00
feat(captcha): Added some new services 🤖 (#1771)
* feat(captcha): Added some new services * Updated * Updated * Update GoogleCaptchaV2.php * Updated * Updated * Create HCaptcha.php * Update HCaptcha.php * Update HCaptcha.php * Create YandexSmartCaptcha.php * Update YandexSmartCaptcha.php * Create CloudflareTurnstileCaptcha.php * Update CloudflareTurnstileCaptcha.php * Update config.php * Update functions.php * Update functions.php * Update functions.php * Update GoogleCaptchaV3.php * Update GoogleCaptchaV3.php * Update HCaptcha.php * Update YandexSmartCaptcha.php * Update CloudflareTurnstileCaptcha.php * Updated * Updated * Update functions.php * Updated * Updated * Update HCaptcha.php * Updated * Updated * Updated * Update functions.php * Update main.php * Updated * Update HCaptcha.php * Update HCaptcha.php * Update GoogleCaptchaV3.php * Update GoogleCaptchaV3.php * Updated * Updated * Update GoogleCaptchaV2.php * Update GoogleCaptchaV2.php
This commit is contained in:
parent
bf2509abe7
commit
d413c71718
9 changed files with 449 additions and 43 deletions
|
@ -670,12 +670,12 @@ $bb_cfg['group_avatars'] = [
|
|||
];
|
||||
|
||||
// Captcha
|
||||
// Get a Google reCAPTCHA API Key: https://www.google.com/recaptcha/admin
|
||||
$bb_cfg['captcha'] = [
|
||||
'disabled' => true,
|
||||
'service' => 'googleV3', // Available services: googleV2, googleV3, hCaptcha, yandex, cloudflare
|
||||
'public_key' => '',
|
||||
'secret_key' => '',
|
||||
'theme' => 'light', // theming (available: light, dark)
|
||||
'theme' => 'light', // theming (available: light, dark) (working only if supported by captcha service)
|
||||
];
|
||||
|
||||
// Atom feed
|
||||
|
|
|
@ -2044,56 +2044,50 @@ function hash_search($hash)
|
|||
}
|
||||
|
||||
/**
|
||||
* Функция для получения и проверки правильности ответа от Google ReCaptcha.
|
||||
*
|
||||
* @param $mode
|
||||
* @param string $callback
|
||||
* Function for checking captcha answer
|
||||
*
|
||||
* @param string $mode
|
||||
* @return bool|string
|
||||
*/
|
||||
function bb_captcha($mode, $callback = '')
|
||||
function bb_captcha(string $mode): bool|string
|
||||
{
|
||||
global $bb_cfg, $lang;
|
||||
|
||||
$secret = $bb_cfg['captcha']['secret_key'];
|
||||
$public = $bb_cfg['captcha']['public_key'];
|
||||
$cp_theme = $bb_cfg['captcha']['theme'] ?? 'light';
|
||||
$settings = $bb_cfg['captcha'];
|
||||
$settings['language'] = $bb_cfg['default_lang'];
|
||||
|
||||
if (!$bb_cfg['captcha']['disabled'] && (!$public || !$secret)) {
|
||||
bb_die($lang['CAPTCHA_SETTINGS']);
|
||||
// Checking captcha settings
|
||||
if (!$settings['disabled']) {
|
||||
if (empty($settings['public_key']) || empty($settings['secret_key'])) {
|
||||
bb_die($lang['CAPTCHA_SETTINGS']);
|
||||
}
|
||||
}
|
||||
|
||||
$reCaptcha = new \ReCaptcha\ReCaptcha($secret);
|
||||
|
||||
switch ($mode) {
|
||||
case 'get':
|
||||
return "
|
||||
<script type=\"text/javascript\">
|
||||
var onloadCallback = function() {
|
||||
grecaptcha.render('tp-captcha', {
|
||||
'sitekey' : '" . $public . "',
|
||||
'theme' : '" . $cp_theme . "',
|
||||
'callback' : '" . $callback . "'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<div id=\"tp-captcha\"></div>
|
||||
<script src=\"https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit\" async defer></script>";
|
||||
break;
|
||||
|
||||
case 'check':
|
||||
$resp = $reCaptcha->verify(
|
||||
request_var('g-recaptcha-response', ''),
|
||||
$_SERVER["REMOTE_ADDR"]
|
||||
);
|
||||
if ($resp->isSuccess()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
bb_simple_die(__FUNCTION__ . ": invalid mode '$mode'");
|
||||
// Selecting captcha service
|
||||
$captchaClasses = [
|
||||
'googleV2' => \TorrentPier\Captcha\GoogleCaptchaV2::class,
|
||||
'googleV3' => \TorrentPier\Captcha\GoogleCaptchaV3::class,
|
||||
'hCaptcha' => \TorrentPier\Captcha\HCaptcha::class,
|
||||
'yandex' => \TorrentPier\Captcha\YandexSmartCaptcha::class,
|
||||
'cloudflare' => \TorrentPier\Captcha\CloudflareTurnstileCaptcha::class,
|
||||
];
|
||||
if (!isset($captchaClasses[$settings['service']])) {
|
||||
bb_die(sprintf('Captcha service (%s) not supported', $settings['service']));
|
||||
}
|
||||
$captchaClass = $captchaClasses[$settings['service']];
|
||||
$captcha = new $captchaClass($settings);
|
||||
|
||||
// Selection mode
|
||||
if (isset($captcha)) {
|
||||
switch ($mode) {
|
||||
case 'get':
|
||||
case 'check':
|
||||
return $captcha->$mode();
|
||||
default:
|
||||
bb_die(sprintf('Invalid mode: %s', $mode));
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -3080,7 +3080,7 @@ $lang['UPLOAD_ERRORS'] = [
|
|||
// Captcha
|
||||
$lang['CAPTCHA'] = 'Check that you are not a robot';
|
||||
$lang['CAPTCHA_WRONG'] = 'You could not confirm that you are not a robot';
|
||||
$lang['CAPTCHA_SETTINGS'] = '<h2>ReCaptcha not being fully configured</h2><p>If you haven\'t already generated the keys, you can do it on <a href="https://www.google.com/recaptcha/admin">https://www.google.com/recaptcha/admin</a>.<br />After you generate the keys, you need to put them at the file library/config.php.</p>';
|
||||
$lang['CAPTCHA_SETTINGS'] = '<h2>Captcha is not fully configured</h2><p>Generate the keys using the dashboard of your captcha service, after you need to put them at the file library/config.php.</p>';
|
||||
|
||||
// Sending email
|
||||
$lang['REPLY_TO'] = 'Reply to';
|
||||
|
|
38
src/Captcha/CaptchaInterface.php
Normal file
38
src/Captcha/CaptchaInterface.php
Normal file
|
@ -0,0 +1,38 @@
|
|||
<?php
|
||||
/**
|
||||
* TorrentPier – Bull-powered BitTorrent tracker engine
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
|
||||
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
|
||||
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
|
||||
*/
|
||||
|
||||
namespace TorrentPier\Captcha;
|
||||
|
||||
/**
|
||||
* Interface CaptchaInterface
|
||||
* @package TorrentPier\Captcha
|
||||
*/
|
||||
interface CaptchaInterface
|
||||
{
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings);
|
||||
|
||||
/**
|
||||
* Returns captcha widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string;
|
||||
|
||||
/**
|
||||
* Checking captcha answer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check(): bool;
|
||||
}
|
75
src/Captcha/CloudflareTurnstileCaptcha.php
Normal file
75
src/Captcha/CloudflareTurnstileCaptcha.php
Normal file
|
@ -0,0 +1,75 @@
|
|||
<?php
|
||||
/**
|
||||
* TorrentPier – Bull-powered BitTorrent tracker engine
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
|
||||
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
|
||||
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
|
||||
*/
|
||||
|
||||
namespace TorrentPier\Captcha;
|
||||
|
||||
/**
|
||||
* Class CloudflareTurnstileCaptcha
|
||||
* @package TorrentPier\Captcha
|
||||
*/
|
||||
class CloudflareTurnstileCaptcha implements CaptchaInterface
|
||||
{
|
||||
/**
|
||||
* Captcha service settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $settings;
|
||||
|
||||
/**
|
||||
* Service verification endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $verifyEndpoint = 'https://challenges.cloudflare.com/turnstile/v0/siteverify';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns captcha widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string
|
||||
{
|
||||
return "
|
||||
<script src='https://challenges.cloudflare.com/turnstile/v0/api.js' async defer></script>
|
||||
<div class='cf-turnstile' data-sitekey='{$this->settings['public_key']}' data-language='{$this->settings['language']}' data-theme='" . ($this->settings['theme'] ?? 'light') . "'></div>
|
||||
";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking captcha answer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check(): bool
|
||||
{
|
||||
$turnstileResponse = $_POST['cf-turnstile-response'] ?? '';
|
||||
$postFields = "secret={$this->settings['secret_key']}&response=$turnstileResponse";
|
||||
|
||||
$ch = curl_init($this->verifyEndpoint);
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
|
||||
$response = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
|
||||
$responseData = json_decode($response);
|
||||
return $responseData->success;
|
||||
}
|
||||
}
|
69
src/Captcha/GoogleCaptchaV2.php
Normal file
69
src/Captcha/GoogleCaptchaV2.php
Normal file
|
@ -0,0 +1,69 @@
|
|||
<?php
|
||||
/**
|
||||
* TorrentPier – Bull-powered BitTorrent tracker engine
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
|
||||
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
|
||||
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
|
||||
*/
|
||||
|
||||
namespace TorrentPier\Captcha;
|
||||
|
||||
use ReCaptcha\ReCaptcha;
|
||||
|
||||
/**
|
||||
* Class GoogleCaptchaV2
|
||||
* @package TorrentPier\Captcha
|
||||
*/
|
||||
class GoogleCaptchaV2 implements CaptchaInterface
|
||||
{
|
||||
/**
|
||||
* Captcha service settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $settings;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns captcha widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string
|
||||
{
|
||||
return "
|
||||
<script type='text/javascript'>
|
||||
var onloadCallback = function() {
|
||||
grecaptcha.render('tp-captcha', {
|
||||
'sitekey': '{$this->settings['public_key']}',
|
||||
'theme': '" . ($this->settings['theme'] ?? 'light') . "'
|
||||
});
|
||||
};
|
||||
</script>
|
||||
<div id='tp-captcha'></div>
|
||||
<script src='https://www.google.com/recaptcha/api.js?onload=onloadCallback&render=explicit&hl={$this->settings['language']}' async defer></script>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking captcha answer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check(): bool
|
||||
{
|
||||
$reCaptcha = new ReCaptcha($this->settings['secret_key']);
|
||||
$resp = $reCaptcha->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
return $resp->isSuccess();
|
||||
}
|
||||
}
|
70
src/Captcha/GoogleCaptchaV3.php
Normal file
70
src/Captcha/GoogleCaptchaV3.php
Normal file
|
@ -0,0 +1,70 @@
|
|||
<?php
|
||||
/**
|
||||
* TorrentPier – Bull-powered BitTorrent tracker engine
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
|
||||
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
|
||||
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
|
||||
*/
|
||||
|
||||
namespace TorrentPier\Captcha;
|
||||
|
||||
use ReCaptcha\ReCaptcha;
|
||||
|
||||
/**
|
||||
* Class GoogleCaptchaV3
|
||||
* @package TorrentPier\Captcha
|
||||
*/
|
||||
class GoogleCaptchaV3 implements CaptchaInterface
|
||||
{
|
||||
/**
|
||||
* Captcha service settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $settings;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns captcha widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string
|
||||
{
|
||||
return "
|
||||
<script src='https://www.google.com/recaptcha/api.js?render={$this->settings['public_key']}&lang={$this->settings['language']}'></script>
|
||||
<script>
|
||||
grecaptcha.ready(function() {
|
||||
grecaptcha.execute('{$this->settings['public_key']}', { action:'validate_captcha' }).then(function(token) {
|
||||
document.getElementById('g-recaptcha-response').value = token;
|
||||
});
|
||||
});
|
||||
</script>
|
||||
<input type='hidden' id='g-recaptcha-response' name='g-recaptcha-response'>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking captcha answer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check(): bool
|
||||
{
|
||||
$reCaptcha = new ReCaptcha($this->settings['secret_key']);
|
||||
$resp = $reCaptcha
|
||||
->setScoreThreshold(0.5)
|
||||
->verify($_POST['g-recaptcha-response'], $_SERVER['REMOTE_ADDR']);
|
||||
|
||||
return $resp->isSuccess();
|
||||
}
|
||||
}
|
76
src/Captcha/HCaptcha.php
Normal file
76
src/Captcha/HCaptcha.php
Normal file
|
@ -0,0 +1,76 @@
|
|||
<?php
|
||||
/**
|
||||
* TorrentPier – Bull-powered BitTorrent tracker engine
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
|
||||
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
|
||||
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
|
||||
*/
|
||||
|
||||
namespace TorrentPier\Captcha;
|
||||
|
||||
/**
|
||||
* Class HCaptcha
|
||||
* @package TorrentPier\Captcha
|
||||
*/
|
||||
class HCaptcha implements CaptchaInterface
|
||||
{
|
||||
/**
|
||||
* Captcha service settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $settings;
|
||||
|
||||
/**
|
||||
* Service verification endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $verifyEndpoint = 'https://hcaptcha.com/siteverify';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns captcha widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string
|
||||
{
|
||||
return "
|
||||
<div class='h-captcha' data-sitekey='{$this->settings['public_key']}' data-theme='" . ($this->settings['theme'] ?? 'light') . "'></div>
|
||||
<script src='https://www.hCaptcha.com/1/api.js?hl={$this->settings['language']}' async defer></script>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking captcha answer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check(): bool
|
||||
{
|
||||
$data = [
|
||||
'secret' => $this->settings['secret_key'],
|
||||
'response' => $_POST['h-captcha-response'] ?? null,
|
||||
];
|
||||
|
||||
$verify = curl_init();
|
||||
curl_setopt($verify, CURLOPT_URL, $this->verifyEndpoint);
|
||||
curl_setopt($verify, CURLOPT_POST, true);
|
||||
curl_setopt($verify, CURLOPT_POSTFIELDS, http_build_query($data));
|
||||
curl_setopt($verify, CURLOPT_RETURNTRANSFER, true);
|
||||
$response = curl_exec($verify);
|
||||
|
||||
$responseData = json_decode($response);
|
||||
return $responseData->success;
|
||||
}
|
||||
}
|
84
src/Captcha/YandexSmartCaptcha.php
Normal file
84
src/Captcha/YandexSmartCaptcha.php
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
/**
|
||||
* TorrentPier – Bull-powered BitTorrent tracker engine
|
||||
*
|
||||
* @copyright Copyright (c) 2005-2025 TorrentPier (https://torrentpier.com)
|
||||
* @link https://github.com/torrentpier/torrentpier for the canonical source repository
|
||||
* @license https://github.com/torrentpier/torrentpier/blob/master/LICENSE MIT License
|
||||
*/
|
||||
|
||||
namespace TorrentPier\Captcha;
|
||||
|
||||
/**
|
||||
* Class YandexSmartCaptcha
|
||||
* @package TorrentPier\Captcha
|
||||
*/
|
||||
class YandexSmartCaptcha implements CaptchaInterface
|
||||
{
|
||||
/**
|
||||
* Captcha service settings
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private array $settings;
|
||||
|
||||
/**
|
||||
* Service verification endpoint
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private string $verifyEndpoint = 'https://smartcaptcha.yandexcloud.net/validate';
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $settings
|
||||
*/
|
||||
public function __construct(array $settings)
|
||||
{
|
||||
$this->settings = $settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns captcha widget
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get(): string
|
||||
{
|
||||
return "
|
||||
<script src='https://smartcaptcha.yandexcloud.net/captcha.js' defer></script>
|
||||
<div id='captcha-container' style='width: 402px;' class='smart-captcha' data-sitekey='{$this->settings['public_key']}' data-hl='{$this->settings['language']}'></div>";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checking captcha answer
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function check(): bool
|
||||
{
|
||||
$ch = curl_init($this->verifyEndpoint);
|
||||
$args = [
|
||||
'secret' => $this->settings['secret_key'],
|
||||
'token' => $_POST['smart-token'] ?? null,
|
||||
'ip' => $_SERVER['REMOTE_ADDR'],
|
||||
];
|
||||
|
||||
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
|
||||
curl_setopt($ch, CURLOPT_POST, true);
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($args));
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
|
||||
$serverOutput = curl_exec($ch);
|
||||
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
curl_close($ch);
|
||||
|
||||
if ($httpCode !== 200) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$resp = json_decode($serverOutput);
|
||||
return ($resp->status === 'ok');
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue