mirror of
https://github.com/phpbb/phpbb.git
synced 2025-08-13 12:14:06 +02:00
Merge pull request #6737 from marc1706/feature/captcha_v2
[feature/captcha_v2] Refactor captcha classes and implement turnstile captcha
This commit is contained in:
@@ -11,11 +11,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
use phpbb\captcha\plugins\confirm_type;
|
||||
use phpbb\captcha\plugins\incomplete;
|
||||
use phpbb\config\config;
|
||||
use phpbb\language\language;
|
||||
use phpbb\request\request;
|
||||
use phpbb\template\template;
|
||||
use phpbb\user;
|
||||
|
||||
class phpbb_captcha_incomplete_test extends phpbb_test_case
|
||||
class phpbb_captcha_incomplete_test extends phpbb_database_test_case
|
||||
{
|
||||
protected config $config;
|
||||
|
||||
@@ -32,21 +36,34 @@ class phpbb_captcha_incomplete_test extends phpbb_test_case
|
||||
$this->assigned_vars = array_merge($this->assigned_vars, $vars);
|
||||
}
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->createXMLDataSet(__DIR__ . '/../fixtures/empty.xml');
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
global $phpbb_root_path, $phpEx;
|
||||
|
||||
$this->config = new config([]);
|
||||
$this->template = $this->getMockBuilder('\phpbb\template\twig\twig')
|
||||
->setMethods(['assign_vars'])
|
||||
->onlyMethods(['assign_vars'])
|
||||
->disableOriginalConstructor()
|
||||
->getMock();
|
||||
$this->template->method('assign_vars')
|
||||
->willReturnCallback([$this, 'assign_vars']);
|
||||
$db = $this->new_dbal();
|
||||
$language = $this->createMock(language::class);
|
||||
$request = $this->createMock(request::class);
|
||||
$user = $this->createMock(user::class);
|
||||
|
||||
$this->incomplete_captcha = new incomplete(
|
||||
$this->config,
|
||||
$db,
|
||||
$language,
|
||||
$request,
|
||||
$this->template,
|
||||
$user,
|
||||
$phpbb_root_path,
|
||||
$phpEx
|
||||
);
|
||||
@@ -57,29 +74,25 @@ class phpbb_captcha_incomplete_test extends phpbb_test_case
|
||||
$this->assertTrue($this->incomplete_captcha->is_available());
|
||||
$this->assertFalse($this->incomplete_captcha->is_solved());
|
||||
$this->assertFalse($this->incomplete_captcha->validate());
|
||||
$this->assertSame('CAPTCHA_INCOMPLETE', incomplete::get_name());
|
||||
$this->incomplete_captcha->init(0);
|
||||
$this->incomplete_captcha->execute();
|
||||
$this->incomplete_captcha->execute_demo();
|
||||
$this->assertFalse($this->incomplete_captcha->has_config());
|
||||
$this->incomplete_captcha->set_name('foo');
|
||||
$this->assertSame('CAPTCHA_INCOMPLETE', $this->incomplete_captcha->get_name());
|
||||
$this->incomplete_captcha->init(confirm_type::UNDEFINED);
|
||||
$this->assertEmpty($this->assigned_vars);
|
||||
$this->assertEmpty($this->incomplete_captcha->get_demo_template(0));
|
||||
}
|
||||
|
||||
public function test_get_generator_class(): void
|
||||
{
|
||||
$this->expectException(\phpbb\exception\runtime_exception::class);
|
||||
$this->incomplete_captcha->get_generator_class();
|
||||
$this->assertEmpty($this->incomplete_captcha->get_error());
|
||||
$this->assertSame(0, $this->incomplete_captcha->get_attempt_count());
|
||||
}
|
||||
|
||||
public function test_get_tempate(): void
|
||||
{
|
||||
$this->incomplete_captcha->init(CONFIRM_REG);
|
||||
$this->incomplete_captcha->init(confirm_type::REGISTRATION);
|
||||
$this->assertSame('captcha_incomplete.html', $this->incomplete_captcha->get_template());
|
||||
$this->assertEquals('CONFIRM_INCOMPLETE', $this->assigned_vars['CONFIRM_LANG']);
|
||||
|
||||
$this->assigned_vars = [];
|
||||
|
||||
$this->incomplete_captcha->init(CONFIRM_POST);
|
||||
$this->incomplete_captcha->init(confirm_type::POST);
|
||||
$this->assertSame('captcha_incomplete.html', $this->incomplete_captcha->get_template());
|
||||
$this->assertEquals('CONFIRM_INCOMPLETE', $this->assigned_vars['CONFIRM_LANG']);
|
||||
}
|
||||
|
261
tests/captcha/legacy_wrapper_test.php
Normal file
261
tests/captcha/legacy_wrapper_test.php
Normal file
@@ -0,0 +1,261 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
use phpbb\captcha\plugins\confirm_type;
|
||||
use phpbb\captcha\plugins\legacy_wrapper;
|
||||
|
||||
class phpbb_captcha_legacy_wrapper_test extends phpbb_test_case
|
||||
{
|
||||
private $legacy_captcha;
|
||||
private $legacy_wrapper;
|
||||
|
||||
public function setUp(): void
|
||||
{
|
||||
$this->legacy_captcha = $this->createMock(stdClass::class);
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
}
|
||||
|
||||
public function test_is_available_with_method_exists(): void
|
||||
{
|
||||
// Simulate is_available method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['is_available'])
|
||||
->getMock();
|
||||
$this->legacy_captcha->method('is_available')->willReturn(true);
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
|
||||
$this->assertTrue($this->legacy_wrapper->is_available());
|
||||
}
|
||||
|
||||
public function test_is_available_without_method_exists(): void
|
||||
{
|
||||
// Simulate is_available method does not exist in the legacy captcha
|
||||
$this->assertFalse($this->legacy_wrapper->is_available());
|
||||
}
|
||||
|
||||
public function test_has_config_with_method_exists(): void
|
||||
{
|
||||
// Simulate has_config method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['has_config'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('has_config')->willReturn(true);
|
||||
|
||||
$this->assertTrue($this->legacy_wrapper->has_config());
|
||||
}
|
||||
|
||||
public function test_has_config_without_method_exists(): void
|
||||
{
|
||||
// Simulate has_config method does not exist in the legacy captcha
|
||||
$this->assertFalse($this->legacy_wrapper->has_config());
|
||||
}
|
||||
|
||||
public function test_get_name_with_method_exists(): void
|
||||
{
|
||||
// Simulate get_name method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['get_name'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('get_name')->willReturn('LegacyCaptchaName');
|
||||
|
||||
$this->assertSame('LegacyCaptchaName', $this->legacy_wrapper->get_name());
|
||||
}
|
||||
|
||||
public function test_get_name_without_method_exists(): void
|
||||
{
|
||||
// Simulate get_name method does not exist in the legacy captcha
|
||||
$this->assertSame('', $this->legacy_wrapper->get_name());
|
||||
}
|
||||
|
||||
public function test_set_name_with_method_exists(): void
|
||||
{
|
||||
// Simulate set_name method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['set_name'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->expects($this->once())->method('set_name')->with('NewName');
|
||||
|
||||
$this->legacy_wrapper->set_name('NewName');
|
||||
}
|
||||
|
||||
public function test_init_with_method_exists(): void
|
||||
{
|
||||
// Simulate init method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['init'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->expects($this->once())->method('init')->with(confirm_type::REGISTRATION->value);
|
||||
|
||||
$this->legacy_wrapper->init(confirm_type::REGISTRATION);
|
||||
}
|
||||
|
||||
public function test_get_hidden_fields_with_method_exists(): void
|
||||
{
|
||||
// Simulate get_hidden_fields method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['get_hidden_fields'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('get_hidden_fields')->willReturn(['field1' => 'value1']);
|
||||
|
||||
$this->assertSame(['field1' => 'value1'], $this->legacy_wrapper->get_hidden_fields());
|
||||
}
|
||||
|
||||
public function test_get_hidden_fields_without_method_exists(): void
|
||||
{
|
||||
// Simulate get_hidden_fields method does not exist in the legacy captcha
|
||||
$this->assertSame([], $this->legacy_wrapper->get_hidden_fields());
|
||||
}
|
||||
|
||||
public function test_validate_with_error(): void
|
||||
{
|
||||
// Simulate validate method returns an error
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['validate'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('validate')->willReturn('Captcha Error');
|
||||
|
||||
$this->assertFalse($this->legacy_wrapper->validate());
|
||||
$this->assertSame('Captcha Error', $this->legacy_wrapper->get_error());
|
||||
}
|
||||
|
||||
public function test_validate_without_method_exists(): void
|
||||
{
|
||||
$this->assertFalse($this->legacy_wrapper->validate());
|
||||
}
|
||||
|
||||
public function test_validate_without_error(): void
|
||||
{
|
||||
// Simulate validate method does not return an error
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['validate'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('validate')->willReturn(null);
|
||||
|
||||
$this->assertTrue($this->legacy_wrapper->validate());
|
||||
}
|
||||
|
||||
public function test_is_solved_with_method_exists(): void
|
||||
{
|
||||
// Simulate is_solved method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['is_solved'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('is_solved')->willReturn(true);
|
||||
|
||||
$this->assertTrue($this->legacy_wrapper->is_solved());
|
||||
}
|
||||
|
||||
public function test_is_solved_without_method_exists(): void
|
||||
{
|
||||
// Simulate is_solved method does not exist in the legacy captcha
|
||||
$this->assertFalse($this->legacy_wrapper->is_solved());
|
||||
}
|
||||
|
||||
public function test_reset_with_method_exists(): void
|
||||
{
|
||||
// Simulate reset method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['reset'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->expects($this->once())->method('reset');
|
||||
|
||||
$this->legacy_wrapper->reset();
|
||||
}
|
||||
|
||||
public function test_get_attempt_count_with_method_exists(): void
|
||||
{
|
||||
// Simulate get_attempt_count method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['get_attempt_count'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('get_attempt_count')->willReturn(5);
|
||||
|
||||
$this->assertSame(5, $this->legacy_wrapper->get_attempt_count());
|
||||
}
|
||||
|
||||
public function test_get_attempt_count_without_method_exists(): void
|
||||
{
|
||||
// Simulate get_attempt_count method does not exist in the legacy captcha
|
||||
$this->assertSame(PHP_INT_MAX, $this->legacy_wrapper->get_attempt_count());
|
||||
}
|
||||
|
||||
public function test_get_template_with_method_exists(): void
|
||||
{
|
||||
// Simulate get_template method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['get_template'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('get_template')->willReturn('template_content');
|
||||
|
||||
$this->assertSame('template_content', $this->legacy_wrapper->get_template());
|
||||
}
|
||||
|
||||
public function test_get_template_without_method_exists(): void
|
||||
{
|
||||
// Simulate get_template method does not exist in the legacy captcha
|
||||
$this->assertSame('', $this->legacy_wrapper->get_template());
|
||||
}
|
||||
|
||||
public function test_get_demo_template_with_method_exists(): void
|
||||
{
|
||||
// Simulate get_demo_template method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['get_demo_template'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->method('get_demo_template')->willReturn('demo_template_content');
|
||||
|
||||
$this->assertSame('demo_template_content', $this->legacy_wrapper->get_demo_template());
|
||||
}
|
||||
|
||||
public function test_get_demo_template_without_method_exists(): void
|
||||
{
|
||||
// Simulate get_demo_template method does not exist in the legacy captcha
|
||||
$this->assertSame('', $this->legacy_wrapper->get_demo_template());
|
||||
}
|
||||
|
||||
public function test_garbage_collect_with_method_exists(): void
|
||||
{
|
||||
// Simulate garbage_collect method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['garbage_collect'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->expects($this->once())->method('garbage_collect')->with(confirm_type::REGISTRATION->value);
|
||||
|
||||
$this->legacy_wrapper->garbage_collect(confirm_type::REGISTRATION);
|
||||
}
|
||||
|
||||
public function test_acp_page_with_method_exists(): void
|
||||
{
|
||||
// Simulate acp_page method exists in the legacy captcha
|
||||
$this->legacy_captcha = $this->getMockBuilder(stdClass::class)
|
||||
->addMethods(['acp_page'])
|
||||
->getMock();
|
||||
$this->legacy_wrapper = new legacy_wrapper($this->legacy_captcha);
|
||||
$this->legacy_captcha->expects($this->once())->method('acp_page')->with(1, 'module');
|
||||
|
||||
$this->legacy_wrapper->acp_page(1, 'module');
|
||||
}
|
||||
}
|
@@ -41,10 +41,6 @@ class phpbb_captcha_qa_test extends \phpbb_database_test_case
|
||||
|
||||
public function test_is_installed()
|
||||
{
|
||||
$this->assertFalse($this->qa->is_installed());
|
||||
|
||||
$this->qa->install();
|
||||
|
||||
$this->assertTrue($this->qa->is_installed());
|
||||
}
|
||||
|
||||
|
547
tests/captcha/turnstile_test.php
Normal file
547
tests/captcha/turnstile_test.php
Normal file
@@ -0,0 +1,547 @@
|
||||
<?php
|
||||
/**
|
||||
*
|
||||
* This file is part of the phpBB Forum Software package.
|
||||
*
|
||||
* @copyright (c) phpBB Limited <https://www.phpbb.com>
|
||||
* @license GNU General Public License, version 2 (GPL-2.0)
|
||||
*
|
||||
* For full copyright and license information, please see
|
||||
* the docs/CREDITS.txt file.
|
||||
*
|
||||
*/
|
||||
|
||||
use phpbb\captcha\plugins\confirm_type;
|
||||
use phpbb\captcha\plugins\turnstile;
|
||||
use phpbb\config\config;
|
||||
use phpbb\db\driver\driver_interface;
|
||||
use phpbb\form\form_helper;
|
||||
use phpbb\language\language;
|
||||
use phpbb\log\log_interface;
|
||||
use phpbb\request\request;
|
||||
use phpbb\request\request_interface;
|
||||
use phpbb\template\template;
|
||||
use phpbb\user;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
require_once __DIR__ . '/../../phpBB/includes/functions_acp.php';
|
||||
|
||||
class phpbb_captcha_turnstile_test extends \phpbb_database_test_case
|
||||
{
|
||||
/** @var turnstile */
|
||||
protected $turnstile;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $config;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $db;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $language;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $log;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $request;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $template;
|
||||
|
||||
/** @var PHPUnit\Framework\MockObject\MockObject */
|
||||
protected $user;
|
||||
|
||||
public function getDataSet()
|
||||
{
|
||||
return $this->createXMLDataSet(__DIR__ . '/../fixtures/empty.xml');
|
||||
}
|
||||
|
||||
protected function setUp(): void
|
||||
{
|
||||
// Mock the dependencies
|
||||
$this->config = $this->createMock(config::class);
|
||||
$this->db = $this->new_dbal();
|
||||
$this->language = $this->createMock(language::class);
|
||||
$this->log = $this->createMock(log_interface::class);
|
||||
$this->request = $this->createMock(request::class);
|
||||
$this->template = $this->createMock(template::class);
|
||||
$this->user = $this->createMock(user::class);
|
||||
|
||||
$this->language->method('lang')->willReturnArgument(0);
|
||||
|
||||
// Instantiate the turnstile class with the mocked dependencies
|
||||
$this->turnstile = new turnstile(
|
||||
$this->config,
|
||||
$this->db,
|
||||
$this->language,
|
||||
$this->log,
|
||||
$this->request,
|
||||
$this->template,
|
||||
$this->user
|
||||
);
|
||||
}
|
||||
|
||||
public function test_is_available(): void
|
||||
{
|
||||
// Test when both sitekey and secret are present
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_secret', 'secret_value'],
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, 'confirm_id'],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->assertTrue($this->turnstile->is_available());
|
||||
|
||||
$this->assertEquals(0, $this->turnstile->get_attempt_count());
|
||||
}
|
||||
|
||||
public function test_attempt_count_increase(): void
|
||||
{
|
||||
// Test when both sitekey and secret are present
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_secret', 'secret_value'],
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, 'confirm_id'],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->turnstile->init(confirm_type::REGISTRATION);
|
||||
$this->assertFalse($this->turnstile->validate());
|
||||
|
||||
$confirm_id_reflection = new \ReflectionProperty($this->turnstile, 'confirm_id');
|
||||
$confirm_id = $confirm_id_reflection->getValue($this->turnstile);
|
||||
|
||||
$this->request = $this->createMock(request::class);
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, $confirm_id],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->turnstile = new turnstile(
|
||||
$this->config,
|
||||
$this->db,
|
||||
$this->language,
|
||||
$this->log,
|
||||
$this->request,
|
||||
$this->template,
|
||||
$this->user
|
||||
);
|
||||
|
||||
$this->turnstile->init(confirm_type::REGISTRATION);
|
||||
$this->assertEquals(1, $this->turnstile->get_attempt_count());
|
||||
|
||||
// Run some garbage collection
|
||||
$this->turnstile->garbage_collect(confirm_type::REGISTRATION);
|
||||
|
||||
// Start again at 0 after garbage collection
|
||||
$this->turnstile->init(confirm_type::REGISTRATION);
|
||||
$this->assertEquals(0, $this->turnstile->get_attempt_count());
|
||||
}
|
||||
|
||||
public function test_reset(): void
|
||||
{
|
||||
// Test when both sitekey and secret are present
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_secret', 'secret_value'],
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, 'confirm_id'],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->turnstile->init(confirm_type::REGISTRATION);
|
||||
$this->assertFalse($this->turnstile->validate());
|
||||
$this->turnstile->reset();
|
||||
|
||||
$confirm_id_reflection = new \ReflectionProperty($this->turnstile, 'confirm_id');
|
||||
$confirm_id = $confirm_id_reflection->getValue($this->turnstile);
|
||||
|
||||
$this->request = $this->createMock(request::class);
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, $confirm_id],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->turnstile = new turnstile(
|
||||
$this->config,
|
||||
$this->db,
|
||||
$this->language,
|
||||
$this->log,
|
||||
$this->request,
|
||||
$this->template,
|
||||
$this->user
|
||||
);
|
||||
|
||||
$this->turnstile->init(confirm_type::REGISTRATION);
|
||||
// Should be zero attempts since we reset the captcha
|
||||
$this->assertEquals(0, $this->turnstile->get_attempt_count());
|
||||
}
|
||||
|
||||
public function test_get_hidden_fields(): void
|
||||
{
|
||||
// Test when both sitekey and secret are present
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_secret', 'secret_value'],
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, 'confirm_id'],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->turnstile->init(confirm_type::REGISTRATION);
|
||||
$this->assertFalse($this->turnstile->validate());
|
||||
$this->turnstile->reset();
|
||||
|
||||
$confirm_id_reflection = new \ReflectionProperty($this->turnstile, 'confirm_id');
|
||||
$confirm_id = $confirm_id_reflection->getValue($this->turnstile);
|
||||
|
||||
$this->assertEquals(
|
||||
[
|
||||
'confirm_id' => $confirm_id,
|
||||
'confirm_code' => '',
|
||||
],
|
||||
$this->turnstile->get_hidden_fields(),
|
||||
);
|
||||
$this->assertEquals('CONFIRM_CODE_WRONG', $this->turnstile->get_error());
|
||||
}
|
||||
|
||||
public function test_not_available(): void
|
||||
{
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, 'confirm_id'],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
// Test when sitekey or secret is missing
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', ''],
|
||||
['captcha_turnstile_secret', 'secret_value'],
|
||||
]);
|
||||
|
||||
$this->assertFalse($this->turnstile->is_available());
|
||||
}
|
||||
|
||||
public function test_get_name(): void
|
||||
{
|
||||
$this->assertEquals('CAPTCHA_TURNSTILE', $this->turnstile->get_name());
|
||||
}
|
||||
|
||||
public function test_set_Name(): void
|
||||
{
|
||||
$this->turnstile->set_name('custom_service');
|
||||
$service_name_property = new \ReflectionProperty($this->turnstile, 'service_name');
|
||||
$service_name_property->setAccessible(true);
|
||||
$this->assertEquals('custom_service', $service_name_property->getValue($this->turnstile));
|
||||
}
|
||||
|
||||
public function test_validate_without_response(): void
|
||||
{
|
||||
// Test when there is no Turnstile response
|
||||
$this->request->method('variable')->with('cf-turnstile-response')->willReturn('');
|
||||
|
||||
$this->assertFalse($this->turnstile->validate());
|
||||
}
|
||||
|
||||
public function test_validate_with_response_success(): void
|
||||
{
|
||||
// Mock the request and response from the Turnstile API
|
||||
$this->request->method('variable')->with('cf-turnstile-response')->willReturn('valid_response');
|
||||
$this->request->method('header')->with('CF-Connecting-IP')->willReturn('127.0.0.1');
|
||||
|
||||
// Mock the GuzzleHttp client and response
|
||||
$client_mock = $this->createMock(Client::class);
|
||||
$response_mock = $this->createMock(Response::class);
|
||||
|
||||
$client_mock->method('request')->willReturn($response_mock);
|
||||
$response_mock->method('getBody')->willReturn(json_encode(['success' => true]));
|
||||
|
||||
// Mock config values for secret
|
||||
$this->config->method('offsetGet')->willReturn('secret_value');
|
||||
|
||||
// Use reflection to inject the mocked client into the turnstile class
|
||||
$reflection = new \ReflectionClass($this->turnstile);
|
||||
$client_property = $reflection->getProperty('client');
|
||||
$client_property->setAccessible(true);
|
||||
$client_property->setValue($this->turnstile, $client_mock);
|
||||
|
||||
// Validate that the CAPTCHA was solved successfully
|
||||
$this->assertTrue($this->turnstile->validate());
|
||||
}
|
||||
|
||||
public function test_validate_with_guzzle_exception(): void
|
||||
{
|
||||
// Mock the request and response from the Turnstile API
|
||||
$this->request->method('variable')->with('cf-turnstile-response')->willReturn('valid_response');
|
||||
$this->request->method('header')->with('CF-Connecting-IP')->willReturn('127.0.0.1');
|
||||
|
||||
// Mock the GuzzleHttp client and response
|
||||
$client_mock = $this->createMock(Client::class);
|
||||
|
||||
$request_mock = $this->createMock(\GuzzleHttp\Psr7\Request::class);
|
||||
$exception = new \GuzzleHttp\Exception\ConnectException('Failed at connecting', $request_mock);
|
||||
$client_mock->method('request')->willThrowException($exception);
|
||||
|
||||
// Mock config values for secret
|
||||
$this->config->method('offsetGet')->willReturn('secret_value');
|
||||
|
||||
// Use reflection to inject the mocked client into the turnstile class
|
||||
$reflection = new \ReflectionClass($this->turnstile);
|
||||
$client_property = $reflection->getProperty('client');
|
||||
$client_property->setAccessible(true);
|
||||
$client_property->setValue($this->turnstile, $client_mock);
|
||||
|
||||
// Validatation fails due to guzzle exception
|
||||
$this->assertFalse($this->turnstile->validate());
|
||||
}
|
||||
|
||||
public function test_validate_previous_solve(): void
|
||||
{
|
||||
// Use reflection to inject the mocked client into the turnstile class
|
||||
$reflection = new \ReflectionClass($this->turnstile);
|
||||
$confirm_id = $reflection->getProperty('confirm_id');
|
||||
$confirm_id->setValue($this->turnstile, 'confirm_id');
|
||||
$code_property = $reflection->getProperty('code');
|
||||
$code_property->setValue($this->turnstile, 'test_code');
|
||||
$confirm_code_property = $reflection->getProperty('confirm_code');
|
||||
$confirm_code_property->setValue($this->turnstile, 'test_code');
|
||||
|
||||
// Validate that the CAPTCHA was solved successfully
|
||||
$this->assertTrue($this->turnstile->validate());
|
||||
$this->assertTrue($this->turnstile->is_solved());
|
||||
}
|
||||
|
||||
public function test_has_config(): void
|
||||
{
|
||||
$this->assertTrue($this->turnstile->has_config());
|
||||
}
|
||||
|
||||
public function test_get_client(): void
|
||||
{
|
||||
$turnstile_reflection = new \ReflectionClass($this->turnstile);
|
||||
$get_client_method = $turnstile_reflection->getMethod('get_client');
|
||||
$get_client_method->setAccessible(true);
|
||||
$client_property = $turnstile_reflection->getProperty('client');
|
||||
$client_property->setAccessible(true);
|
||||
|
||||
$this->assertFalse($client_property->isInitialized($this->turnstile));
|
||||
$client = $get_client_method->invoke($this->turnstile);
|
||||
$this->assertNotNull($client);
|
||||
$this->assertInstanceOf(\GuzzleHttp\Client::class, $client);
|
||||
$this->assertTrue($client === $get_client_method->invoke($this->turnstile));
|
||||
}
|
||||
|
||||
public function test_validate_with_response_failure(): void
|
||||
{
|
||||
// Mock the request and response from the Turnstile API
|
||||
$this->request->method('variable')->with('cf-turnstile-response')->willReturn('valid_response');
|
||||
$this->request->method('header')->with('CF-Connecting-IP')->willReturn('127.0.0.1');
|
||||
|
||||
// Mock the GuzzleHttp client and response
|
||||
$client_mock = $this->createMock(Client::class);
|
||||
$response_mock = $this->createMock(Response::class);
|
||||
|
||||
$client_mock->method('request')->willReturn($response_mock);
|
||||
$response_mock->method('getBody')->willReturn(json_encode(['success' => false]));
|
||||
|
||||
// Mock config values for secret
|
||||
$this->config->method('offsetGet')->willReturn('secret_value');
|
||||
|
||||
// Use reflection to inject the mocked client into the turnstile class
|
||||
$reflection = new \ReflectionClass($this->turnstile);
|
||||
$client_property = $reflection->getProperty('client');
|
||||
$client_property->setAccessible(true);
|
||||
$client_property->setValue($this->turnstile, $client_mock);
|
||||
|
||||
// Validate that the CAPTCHA was not solved
|
||||
$this->assertFalse($this->turnstile->validate());
|
||||
}
|
||||
|
||||
public function test_get_template(): void
|
||||
{
|
||||
// Mock is_solved to return false
|
||||
$is_solved_property = new \ReflectionProperty($this->turnstile, 'solved');
|
||||
$is_solved_property->setAccessible(true);
|
||||
$is_solved_property->setValue($this->turnstile, false);
|
||||
|
||||
// Mock the template assignments
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_theme', 'light'],
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['confirm_id', '', false, request_interface::REQUEST, 'confirm_id'],
|
||||
['confirm_code', '', false, request_interface::REQUEST, 'confirm_code']
|
||||
]);
|
||||
|
||||
$this->template->expects($this->once())->method('assign_vars')->with([
|
||||
'S_TURNSTILE_AVAILABLE' => $this->turnstile->is_available(),
|
||||
'TURNSTILE_SITEKEY' => 'sitekey_value',
|
||||
'TURNSTILE_THEME' => 'light',
|
||||
'U_TURNSTILE_SCRIPT' => 'https://challenges.cloudflare.com/turnstile/v0/api.js',
|
||||
'CONFIRM_TYPE_REGISTRATION' => confirm_type::UNDEFINED->value,
|
||||
]);
|
||||
|
||||
$this->assertEquals('captcha_turnstile.html', $this->turnstile->get_template());
|
||||
|
||||
$is_solved_property->setValue($this->turnstile, true);
|
||||
$this->assertEquals('', $this->turnstile->get_template());
|
||||
}
|
||||
|
||||
public function test_get_demo_template(): void
|
||||
{
|
||||
// Mock the config assignments
|
||||
$this->config->method('offsetGet')->willReturn('light');
|
||||
|
||||
$this->template->expects($this->once())->method('assign_vars')->with([
|
||||
'TURNSTILE_THEME' => 'light',
|
||||
'U_TURNSTILE_SCRIPT' => 'https://challenges.cloudflare.com/turnstile/v0/api.js',
|
||||
]);
|
||||
|
||||
$this->assertEquals('captcha_turnstile_acp_demo.html', $this->turnstile->get_demo_template());
|
||||
}
|
||||
|
||||
public function test_acp_page_display(): void
|
||||
{
|
||||
global $phpbb_container, $phpbb_dispatcher, $template;
|
||||
|
||||
$phpbb_container = new phpbb_mock_container_builder();
|
||||
$form_helper = new form_helper($this->config, $this->request, $this->user);
|
||||
$phpbb_container->set('form_helper', $form_helper);
|
||||
$this->user->data['user_id'] = ANONYMOUS;
|
||||
$this->user->data['user_form_salt'] = 'foobar';
|
||||
|
||||
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
|
||||
$template = $this->template;
|
||||
|
||||
// Mock the template assignments
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_theme', 'light'],
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturn('');
|
||||
|
||||
$expected = [
|
||||
1 => [
|
||||
'TURNSTILE_THEME' => 'light',
|
||||
'U_TURNSTILE_SCRIPT' => 'https://challenges.cloudflare.com/turnstile/v0/api.js',
|
||||
],
|
||||
2 => [
|
||||
'CAPTCHA_PREVIEW' => 'captcha_turnstile_acp_demo.html',
|
||||
'CAPTCHA_NAME' => '',
|
||||
'CAPTCHA_TURNSTILE_THEME' => 'light',
|
||||
'CAPTCHA_TURNSTILE_THEMES' => ['light', 'dark', 'auto'],
|
||||
'U_ACTION' => 'test_u_action',
|
||||
],
|
||||
];
|
||||
$matcher = $this->exactly(count($expected));
|
||||
$this->template
|
||||
->expects($matcher)
|
||||
->method('assign_vars')
|
||||
->willReturnCallback(function ($template_data) use ($matcher, $expected) {
|
||||
$callNr = $matcher->getInvocationCount();
|
||||
$this->assertEquals($expected[$callNr], $template_data);
|
||||
});
|
||||
|
||||
$module_mock = new ModuleMock();
|
||||
|
||||
$this->turnstile->acp_page('', $module_mock);
|
||||
}
|
||||
|
||||
public function test_acp_page_submit_without_form(): void
|
||||
{
|
||||
global $language, $phpbb_container, $phpbb_dispatcher, $template;
|
||||
|
||||
$language = $this->language;
|
||||
$phpbb_container = new phpbb_mock_container_builder();
|
||||
$form_helper = new form_helper($this->config, $this->request, $this->user);
|
||||
$phpbb_container->set('form_helper', $form_helper);
|
||||
$this->user->data['user_id'] = ANONYMOUS;
|
||||
$this->user->data['user_form_salt'] = 'foobar';
|
||||
|
||||
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
|
||||
$template = $this->template;
|
||||
|
||||
// Mock the template assignments
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_theme', 'light'],
|
||||
]);
|
||||
|
||||
$this->request->method('is_set_post')->willReturnMap([
|
||||
['creation_time', ''],
|
||||
['submit', true]
|
||||
]);
|
||||
|
||||
$this->setExpectedTriggerError(E_USER_NOTICE, 'FORM_INVALID');
|
||||
|
||||
$module_mock = new ModuleMock();
|
||||
|
||||
$this->turnstile->acp_page('', $module_mock);
|
||||
}
|
||||
|
||||
public function test_acp_page_submit_valid(): void
|
||||
{
|
||||
global $language, $phpbb_container, $phpbb_dispatcher, $template;
|
||||
|
||||
$language = $this->language;
|
||||
$phpbb_container = new phpbb_mock_container_builder();
|
||||
$form_helper = new form_helper($this->config, $this->request, $this->user);
|
||||
$phpbb_container->set('form_helper', $form_helper);
|
||||
$this->user->data['user_id'] = ANONYMOUS;
|
||||
$this->user->data['user_form_salt'] = 'foobar';
|
||||
|
||||
$phpbb_dispatcher = new phpbb_mock_event_dispatcher();
|
||||
$template = $this->template;
|
||||
|
||||
$form_tokens = $form_helper->get_form_tokens('acp_captcha');
|
||||
|
||||
// Mock the template assignments
|
||||
$this->config->method('offsetGet')->willReturnMap([
|
||||
['captcha_turnstile_sitekey', 'sitekey_value'],
|
||||
['captcha_turnstile_theme', 'light'],
|
||||
]);
|
||||
$this->config['form_token_lifetime'] = 3600;
|
||||
|
||||
$this->request->method('is_set_post')->willReturnMap([
|
||||
['creation_time', true],
|
||||
['form_token', true],
|
||||
['submit', true]
|
||||
]);
|
||||
|
||||
$this->request->method('variable')->willReturnMap([
|
||||
['creation_time', 0, false, request_interface::REQUEST, $form_tokens['creation_time']],
|
||||
['form_token', '', false, request_interface::REQUEST, $form_tokens['form_token']],
|
||||
['captcha_turnstile_sitekey', '', false, request_interface::REQUEST, 'newsitekey'],
|
||||
['captcha_turnstile_theme', 'light', false, request_interface::REQUEST, 'auto'],
|
||||
]);
|
||||
|
||||
$this->setExpectedTriggerError(E_USER_NOTICE, 'CONFIG_UPDATED');
|
||||
|
||||
$module_mock = new ModuleMock();
|
||||
sleep(1); // sleep for a second to ensure form token validation succeeds
|
||||
|
||||
$this->turnstile->acp_page('', $module_mock);
|
||||
}
|
||||
}
|
||||
|
||||
class ModuleMock
|
||||
{
|
||||
public string $tpl_name = '';
|
||||
public string $page_title = '';
|
||||
public string $u_action = 'test_u_action';
|
||||
}
|
Reference in New Issue
Block a user