feat(captcha): Added Text Captcha provider (#1839)

* feat(captcha): Added `Text Captcha` provider

* Create TextCaptcha.php

* Updated

* Update composer.lock

* Updated

* Update config.php

* Update functions.php

* Update TextCaptcha.php

* Update TextCaptcha.php

* Update TextCaptcha.php

* Update TextCaptcha.php

* Update TextCaptcha.php

* Update TextCaptcha.php

* Update TextCaptcha.php
This commit is contained in:
Roman Kelesidis 2025-03-09 00:12:48 +07:00 committed by GitHub
commit 74ea1573b2
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 165 additions and 31 deletions

View file

@ -53,6 +53,7 @@
"arokettu/torrent-file": "^5.2.1", "arokettu/torrent-file": "^5.2.1",
"bugsnag/bugsnag": "^v3.29.1", "bugsnag/bugsnag": "^v3.29.1",
"claviska/simpleimage": "^4.0", "claviska/simpleimage": "^4.0",
"gregwar/captcha": "1.*",
"egulias/email-validator": "^4.0.1", "egulias/email-validator": "^4.0.1",
"filp/whoops": "^2.15", "filp/whoops": "^2.15",
"z4kn4fein/php-semver": "^v3.0.0", "z4kn4fein/php-semver": "^v3.0.0",

114
composer.lock generated
View file

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "9024100c87e72c5ee811638607aa15f5", "content-hash": "3cdb46350e69ff19cc07455ac9791423",
"packages": [ "packages": [
{ {
"name": "arokettu/bencode", "name": "arokettu/bencode",
@ -813,21 +813,21 @@
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Gemorroj/M3uParser.git", "url": "https://github.com/Gemorroj/M3uParser.git",
"reference": "fcb37acd137a6e1d6aa2ef3745e1bc7a6e0b46e6" "reference": "6e6a35df8d5410d8884c7dadcde611607aae3b12"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Gemorroj/M3uParser/zipball/fcb37acd137a6e1d6aa2ef3745e1bc7a6e0b46e6", "url": "https://api.github.com/repos/Gemorroj/M3uParser/zipball/6e6a35df8d5410d8884c7dadcde611607aae3b12",
"reference": "fcb37acd137a6e1d6aa2ef3745e1bc7a6e0b46e6", "reference": "6e6a35df8d5410d8884c7dadcde611607aae3b12",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=8.0.2" "php": ">=8.0.2"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^3.46", "friendsofphp/php-cs-fixer": "^3.68.5",
"phpstan/phpstan": "^1.10", "phpstan/phpstan": "^2",
"phpunit/phpunit": "^9.6" "phpunit/phpunit": "^9.6.22"
}, },
"default-branch": true, "default-branch": true,
"type": "library", "type": "library",
@ -855,7 +855,7 @@
"issues": "https://github.com/Gemorroj/M3uParser/issues", "issues": "https://github.com/Gemorroj/M3uParser/issues",
"source": "https://github.com/Gemorroj/M3uParser/tree/master" "source": "https://github.com/Gemorroj/M3uParser/tree/master"
}, },
"time": "2024-07-27T11:53:30+00:00" "time": "2025-03-03T18:16:38+00:00"
}, },
{ {
"name": "gigablah/sphinxphp", "name": "gigablah/sphinxphp",
@ -1026,6 +1026,63 @@
], ],
"time": "2024-07-20T21:45:45+00:00" "time": "2024-07-20T21:45:45+00:00"
}, },
{
"name": "gregwar/captcha",
"version": "v1.2.1",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Captcha.git",
"reference": "229d3cdfe33d6f1349e0aec94a26e9205a6db08e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Captcha/zipball/229d3cdfe33d6f1349e0aec94a26e9205a6db08e",
"reference": "229d3cdfe33d6f1349e0aec94a26e9205a6db08e",
"shasum": ""
},
"require": {
"ext-gd": "*",
"ext-mbstring": "*",
"php": ">=5.3.0",
"symfony/finder": "*"
},
"require-dev": {
"phpunit/phpunit": "^6.4"
},
"type": "library",
"autoload": {
"psr-4": {
"Gregwar\\": "src/Gregwar"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "http://www.gregwar.com/"
},
{
"name": "Jeremy Livingston",
"email": "jeremy.j.livingston@gmail.com"
}
],
"description": "Captcha generator",
"homepage": "https://github.com/Gregwar/Captcha",
"keywords": [
"bot",
"captcha",
"spam"
],
"support": {
"issues": "https://github.com/Gregwar/Captcha/issues",
"source": "https://github.com/Gregwar/Captcha/tree/v1.2.1"
},
"time": "2023-09-26T13:45:37+00:00"
},
{ {
"name": "guzzlehttp/guzzle", "name": "guzzlehttp/guzzle",
"version": "7.9.2", "version": "7.9.2",
@ -2026,6 +2083,7 @@
"issues": "https://github.com/nemorize/php-indexnow/issues", "issues": "https://github.com/nemorize/php-indexnow/issues",
"source": "https://github.com/nemorize/php-indexnow/tree/0.0.1" "source": "https://github.com/nemorize/php-indexnow/tree/0.0.1"
}, },
"abandoned": true,
"time": "2023-07-31T17:08:12+00:00" "time": "2023-07-31T17:08:12+00:00"
}, },
{ {
@ -3186,16 +3244,16 @@
}, },
{ {
"name": "symfony/mailer", "name": "symfony/mailer",
"version": "v6.4.13", "version": "v6.4.18",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mailer.git", "url": "https://github.com/symfony/mailer.git",
"reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663" "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mailer/zipball/c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", "url": "https://api.github.com/repos/symfony/mailer/zipball/e93a6ae2767d7f7578c2b7961d9d8e27580b2b11",
"reference": "c2f7e0d8d7ac8fe25faccf5d8cac462805db2663", "reference": "e93a6ae2767d7f7578c2b7961d9d8e27580b2b11",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3246,7 +3304,7 @@
"description": "Helps sending emails", "description": "Helps sending emails",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": { "support": {
"source": "https://github.com/symfony/mailer/tree/v6.4.13" "source": "https://github.com/symfony/mailer/tree/v6.4.18"
}, },
"funding": [ "funding": [
{ {
@ -3262,20 +3320,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-09-25T14:18:03+00:00" "time": "2025-01-24T15:27:15+00:00"
}, },
{ {
"name": "symfony/mime", "name": "symfony/mime",
"version": "v6.4.17", "version": "v6.4.19",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/mime.git", "url": "https://github.com/symfony/mime.git",
"reference": "ea87c8850a54ff039d3e0ab4ae5586dd4e6c0232" "reference": "ac537b6c55ccc2c749f3c979edfa9ec14aaed4f3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/mime/zipball/ea87c8850a54ff039d3e0ab4ae5586dd4e6c0232", "url": "https://api.github.com/repos/symfony/mime/zipball/ac537b6c55ccc2c749f3c979edfa9ec14aaed4f3",
"reference": "ea87c8850a54ff039d3e0ab4ae5586dd4e6c0232", "reference": "ac537b6c55ccc2c749f3c979edfa9ec14aaed4f3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3331,7 +3389,7 @@
"mime-type" "mime-type"
], ],
"support": { "support": {
"source": "https://github.com/symfony/mime/tree/v6.4.17" "source": "https://github.com/symfony/mime/tree/v6.4.19"
}, },
"funding": [ "funding": [
{ {
@ -3347,7 +3405,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-12-02T11:09:41+00:00" "time": "2025-02-17T21:23:52+00:00"
}, },
{ {
"name": "symfony/polyfill", "name": "symfony/polyfill",
@ -3689,16 +3747,16 @@
"packages-dev": [ "packages-dev": [
{ {
"name": "symfony/var-dumper", "name": "symfony/var-dumper",
"version": "v6.4.15", "version": "v6.4.18",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/var-dumper.git", "url": "https://github.com/symfony/var-dumper.git",
"reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80" "reference": "4ad10cf8b020e77ba665305bb7804389884b4837"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/var-dumper/zipball/38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", "url": "https://api.github.com/repos/symfony/var-dumper/zipball/4ad10cf8b020e77ba665305bb7804389884b4837",
"reference": "38254d5a5ac2e61f2b52f9caf54e7aa3c9d36b80", "reference": "4ad10cf8b020e77ba665305bb7804389884b4837",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -3754,7 +3812,7 @@
"dump" "dump"
], ],
"support": { "support": {
"source": "https://github.com/symfony/var-dumper/tree/v6.4.15" "source": "https://github.com/symfony/var-dumper/tree/v6.4.18"
}, },
"funding": [ "funding": [
{ {
@ -3770,7 +3828,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2024-11-08T15:28:48+00:00" "time": "2025-01-17T11:26:11+00:00"
} }
], ],
"aliases": [], "aliases": [],
@ -3784,6 +3842,6 @@
"platform": { "platform": {
"php": "^8.1 | ^8.2 | ^8.3 | ^8.4" "php": "^8.1 | ^8.2 | ^8.3 | ^8.4"
}, },
"platform-dev": [], "platform-dev": {},
"plugin-api-version": "2.3.0" "plugin-api-version": "2.6.0"
} }

View file

@ -675,7 +675,7 @@ $bb_cfg['group_avatars'] = [
// Captcha // Captcha
$bb_cfg['captcha'] = [ $bb_cfg['captcha'] = [
'disabled' => true, 'disabled' => true,
'service' => 'googleV3', // Available services: googleV2, googleV3, hCaptcha, yandex, cloudflare 'service' => 'googleV3', // Available services: text, googleV2, googleV3, hCaptcha, yandex, cloudflare
'public_key' => '', 'public_key' => '',
'secret_key' => '', 'secret_key' => '',
'theme' => 'light', // theming (available: light, dark) (working only if supported by captcha service) 'theme' => 'light', // theming (available: light, dark) (working only if supported by captcha service)

View file

@ -2057,7 +2057,7 @@ function bb_captcha(string $mode): bool|string
$settings['language'] = $bb_cfg['default_lang']; $settings['language'] = $bb_cfg['default_lang'];
// Checking captcha settings // Checking captcha settings
if (!$settings['disabled']) { if (!$settings['disabled'] && $settings['service'] !== 'text') {
if (empty($settings['public_key']) || empty($settings['secret_key'])) { if (empty($settings['public_key']) || empty($settings['secret_key'])) {
bb_die($lang['CAPTCHA_SETTINGS']); bb_die($lang['CAPTCHA_SETTINGS']);
} }
@ -2070,6 +2070,7 @@ function bb_captcha(string $mode): bool|string
'hCaptcha' => \TorrentPier\Captcha\HCaptcha::class, 'hCaptcha' => \TorrentPier\Captcha\HCaptcha::class,
'yandex' => \TorrentPier\Captcha\YandexSmartCaptcha::class, 'yandex' => \TorrentPier\Captcha\YandexSmartCaptcha::class,
'cloudflare' => \TorrentPier\Captcha\CloudflareTurnstileCaptcha::class, 'cloudflare' => \TorrentPier\Captcha\CloudflareTurnstileCaptcha::class,
'text' => \TorrentPier\Captcha\TextCaptcha::class
]; ];
if (!isset($captchaClasses[$settings['service']])) { if (!isset($captchaClasses[$settings['service']])) {
bb_die(sprintf('Captcha service (%s) not supported', $settings['service'])); bb_die(sprintf('Captcha service (%s) not supported', $settings['service']));

View file

@ -3073,6 +3073,7 @@ $lang['UPLOAD_ERRORS'] = [
$lang['CAPTCHA'] = 'Check that you are not a robot'; $lang['CAPTCHA'] = 'Check that you are not a robot';
$lang['CAPTCHA_WRONG'] = 'You could not confirm that you are not a robot'; $lang['CAPTCHA_WRONG'] = 'You could not confirm that you are not a robot';
$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>'; $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>';
$lang['CAPTCHA_OCCURS_BACKGROUND'] = 'The CAPTCHA verification occurs in the background';
// Sending email // Sending email
$lang['REPLY_TO'] = 'Reply to'; $lang['REPLY_TO'] = 'Reply to';

View file

@ -41,7 +41,9 @@ class GoogleCaptchaV3 implements CaptchaInterface
*/ */
public function get(): string public function get(): string
{ {
return " global $lang;
return "{$lang['CAPTCHA_OCCURS_BACKGROUND']}
<script src='https://www.google.com/recaptcha/api.js?render={$this->settings['public_key']}&lang={$this->settings['language']}'></script> <script src='https://www.google.com/recaptcha/api.js?render={$this->settings['public_key']}&lang={$this->settings['language']}'></script>
<script> <script>
grecaptcha.ready(function() { grecaptcha.ready(function() {

View file

@ -0,0 +1,71 @@
<?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 Gregwar\Captcha\CaptchaBuilder;
use Gregwar\Captcha\PhraseBuilder;
/**
* Class TextCaptcha
* @package TorrentPier\Captcha
*/
class TextCaptcha implements CaptchaInterface
{
/**
* CaptchaBuilder object
*
* @var CaptchaBuilder
*/
private CaptchaBuilder $captcha;
/**
* Constructor
*
* @param array $settings
*/
public function __construct(array $settings)
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
$this->captcha = new CaptchaBuilder;
}
/**
* Returns captcha widget
*
* @return string
*/
public function get(): string
{
$_SESSION['phrase'] = $this->captcha->getPhrase();
$this->captcha->build();
return "
<img src=" . $this->captcha->inline() . " /><br />
<input type='text' name='captcha_phrase' />
";
}
/**
* Checking captcha answer
*
* @return bool
*/
public function check(): bool
{
if (!isset($_POST['captcha_phrase']) || !isset($_SESSION['phrase'])) {
return false;
}
return PhraseBuilder::comparePhrases($_SESSION['phrase'], $_POST['captcha_phrase']);
}
}