diff --git a/app/Config/Honeypot.php b/app/Config/Honeypot.php
index 179b01546902..67ebcb0ee74c 100644
--- a/app/Config/Honeypot.php
+++ b/app/Config/Honeypot.php
@@ -24,10 +24,19 @@ class Honeypot extends BaseConfig
/**
* Honeypot HTML Template
*/
- public string $template = '';
+ public string $template = '';
/**
* Honeypot container
+ *
+ * If you enabled CSP, you can remove `style="display:none"`.
*/
public string $container = '
{template}
';
+
+ /**
+ * The id attribute for Honeypot container tag
+ *
+ * Used when CSP is enabled.
+ */
+ public string $containerId = 'hpc';
}
diff --git a/system/Honeypot/Honeypot.php b/system/Honeypot/Honeypot.php
index fdd8fe95168b..7ab0cd36737e 100644
--- a/system/Honeypot/Honeypot.php
+++ b/system/Honeypot/Honeypot.php
@@ -46,6 +46,8 @@ public function __construct(HoneypotConfig $config)
$this->config->container = '
{template}
';
}
+ $this->config->containerId ??= 'hpc';
+
if ($this->config->template === '') {
throw HoneypotException::forNoTemplate();
}
@@ -70,10 +72,26 @@ public function hasContent(RequestInterface $request)
*/
public function attachHoneypot(ResponseInterface $response)
{
+ if ($response->getCSP()->enabled()) {
+ // Add id attribute to the container tag.
+ $this->config->container = str_ireplace(
+ '>{template}',
+ ' id="' . $this->config->containerId . '">{template}',
+ $this->config->container
+ );
+ }
+
$prepField = $this->prepareTemplate($this->config->template);
$body = $response->getBody();
$body = str_ireplace('', $prepField . '', $body);
+
+ if ($response->getCSP()->enabled()) {
+ // Add style tag for the container tag in the head tag.
+ $style = '';
+ $body = str_ireplace('', $style . '', $body);
+ }
+
$response->setBody($body);
}
diff --git a/tests/system/Honeypot/HoneypotTest.php b/tests/system/Honeypot/HoneypotTest.php
index 5b9c0c0073d8..b87ce3fe3c48 100644
--- a/tests/system/Honeypot/HoneypotTest.php
+++ b/tests/system/Honeypot/HoneypotTest.php
@@ -11,6 +11,7 @@
namespace CodeIgniter\Honeypot;
+use CodeIgniter\Config\Factories;
use CodeIgniter\Config\Services;
use CodeIgniter\Filters\Filters;
use CodeIgniter\Honeypot\Exceptions\HoneypotException;
@@ -18,6 +19,8 @@
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\Response;
use CodeIgniter\Test\CIUnitTestCase;
+use Config\App;
+use Config\Honeypot as HoneypotConfig;
/**
* @backupGlobals enabled
@@ -28,7 +31,7 @@
*/
final class HoneypotTest extends CIUnitTestCase
{
- private \Config\Honeypot $config;
+ private HoneypotConfig $config;
private Honeypot $honeypot;
/**
@@ -41,14 +44,16 @@ final class HoneypotTest extends CIUnitTestCase
protected function setUp(): void
{
parent::setUp();
- $this->config = new \Config\Honeypot();
+
+ $this->config = new HoneypotConfig();
$this->honeypot = new Honeypot($this->config);
unset($_POST[$this->config->name]);
$_SERVER['REQUEST_METHOD'] = 'POST';
$_POST[$this->config->name] = 'hey';
- $this->request = Services::request(null, false);
- $this->response = Services::response();
+
+ $this->request = Services::request(null, false);
+ $this->response = Services::response();
}
public function testAttachHoneypot()
@@ -66,16 +71,35 @@ public function testAttachHoneypotAndContainer()
{
$this->response->setBody('');
$this->honeypot->attachHoneypot($this->response);
- $expected = '';
+ $expected = '';
$this->assertSame($expected, $this->response->getBody());
$this->config->container = '
{template}
';
$this->response->setBody('');
$this->honeypot->attachHoneypot($this->response);
- $expected = '';
+ $expected = '';
$this->assertSame($expected, $this->response->getBody());
}
+ public function testAttachHoneypotAndContainerWithCSP()
+ {
+ $this->resetServices();
+
+ $config = new App();
+ $config->CSPEnabled = true;
+ Factories::injectMock('config', 'App', $config);
+ $this->response = Services::response($config, false);
+
+ $this->config = new HoneypotConfig();
+ $this->honeypot = new Honeypot($this->config);
+
+ $this->response->setBody('');
+ $this->honeypot->attachHoneypot($this->response);
+
+ $regex = '!!u';
+ $this->assertMatchesRegularExpression($regex, $this->response->getBody());
+ }
+
public function testHasntContent()
{
unset($_POST[$this->config->name]);
@@ -147,7 +171,7 @@ public function testHoneypotFilterAfter()
public function testEmptyConfigContainer()
{
- $config = new \Config\Honeypot();
+ $config = new HoneypotConfig();
$config->container = '';
$honeypot = new Honeypot($config);
@@ -159,7 +183,7 @@ public function testEmptyConfigContainer()
public function testNoTemplateConfigContainer()
{
- $config = new \Config\Honeypot();
+ $config = new HoneypotConfig();
$config->container = '';
$honeypot = new Honeypot($config);
diff --git a/user_guide_src/source/changelogs/v4.3.0.rst b/user_guide_src/source/changelogs/v4.3.0.rst
index 7fdb8038d6d4..4ea3b567cf68 100644
--- a/user_guide_src/source/changelogs/v4.3.0.rst
+++ b/user_guide_src/source/changelogs/v4.3.0.rst
@@ -291,6 +291,7 @@ The following items are affected:
- Typography class: Creation of ``br`` tag
- View Parser: The ``nl2br`` filter
+- Honeypot: ``input`` tag
- Form helper
- HTML helper
- Common Functions
@@ -364,3 +365,4 @@ Bugs Fixed
- Fixed a bug when all types of ``Prepared Queries`` were returning a ``Result`` object instead of a bool value for write-type queries.
- Fixed a bug with variable filtering in JSON requests using with ``IncomingRequest::getVar()`` or ``IncomingRequest::getJsonVar()`` methods.
- Fixed a bug when variable type may be changed when using a specified index with ``IncomingRequest::getVar()`` or ``IncomingRequest::getJsonVar()`` methods.
+- Fixed a bug that Honeypot field appears when CSP is enabled. See also :ref:`upgrade-430-honeypot-and-csp`.
diff --git a/user_guide_src/source/installation/upgrade_430.rst b/user_guide_src/source/installation/upgrade_430.rst
index 5d7192822c31..04f44a03f4b4 100644
--- a/user_guide_src/source/installation/upgrade_430.rst
+++ b/user_guide_src/source/installation/upgrade_430.rst
@@ -216,6 +216,16 @@ Database
- The ``Model::update()`` method now raises a ``DatabaseException`` if it generates an SQL
statement without a WHERE clause. If you need to update all records in a table, use Query Builder instead. E.g., ``$model->builder()->update($data)``.
+.. _upgrade-430-honeypot-and-csp:
+
+Honeypot and CSP
+================
+
+When CSP is enabled, id attribute ``id="hpc"`` will be injected into the container tag
+for the Honeypot field to hide the field. If the id is already used in your views, you need to change it
+with ``Config\Honeypot::$containerId``.
+And you can remove ``style="display:none"`` in ``Config\Honeypot::$container``.
+
Others
======
@@ -260,6 +270,10 @@ Config
- app/Config/Exceptions.php
- Two additional public properties were added: ``$logDeprecations`` and ``$deprecationLogLevel``.
See See :ref:`logging_deprecation_warnings` for details.
+- app/Config/Honeypot.php
+ - The new property ``$containerId`` is added to set id attribute value for the container tag
+ when CSP is enabled.
+ - The ``input`` tag in the property ``$template`` value has been changed to HTML5 compatible.
- app/Config/Logger.php
- The property ``$threshold`` has been changed to ``9`` in other than ``production``
environment.
diff --git a/user_guide_src/source/libraries/honeypot.rst b/user_guide_src/source/libraries/honeypot.rst
index cdaa4eb1eb52..e034e0dc08db 100644
--- a/user_guide_src/source/libraries/honeypot.rst
+++ b/user_guide_src/source/libraries/honeypot.rst
@@ -1,9 +1,9 @@
-=====================
+##############
Honeypot Class
-=====================
+##############
The Honeypot Class makes it possible to determine when a Bot makes a request to a CodeIgniter4 application,
-if it's enabled in ``Application\Config\Filters.php`` file. This is done by attaching form fields to any form,
+if it's enabled in **app\Config\Filters.php** file. This is done by attaching form fields to any form,
and this form field is hidden from a human but accessible to a Bot. When data is entered into the field, it's
assumed the request is coming from a Bot, and you can throw a ``HoneypotException``.
@@ -11,25 +11,30 @@ assumed the request is coming from a Bot, and you can throw a ``HoneypotExceptio
:local:
:depth: 2
+*****************
Enabling Honeypot
-=====================
+*****************
To enable a Honeypot, changes have to be made to the **app/Config/Filters.php**. Just uncomment honeypot
from the ``$globals`` array, like:
.. literalinclude:: honeypot/001.php
-A sample Honeypot filter is bundled, as ``system/Filters/Honeypot.php``.
-If it is not suitable, make your own at ``app/Filters/Honeypot.php``,
+A sample Honeypot filter is bundled, as **system/Filters/Honeypot.php**.
+If it is not suitable, make your own at **app/Filters/Honeypot.php**,
and modify the ``$aliases`` in the configuration appropriately.
+********************
Customizing Honeypot
-=====================
+********************
Honeypot can be customized. The fields below can be set either in
**app/Config/Honeypot.php** or in **.env**.
-* ``hidden`` - true|false to control visibility of the honeypot field; default is ``true``
-* ``label`` - HTML label for the honeypot field, default is 'Fill This Field'
-* ``name`` - name of the HTML form field used for the template; default is 'honeypot'
-* ``template`` - form field template used for the honeypot; default is ''
+* ``$hidden`` - ``true`` or ``false`` to control visibility of the honeypot field; default is ``true``
+* ``$label`` - HTML label for the honeypot field, default is ``'Fill This Field'``
+* ``$name`` - name of the HTML form field used for the template; default is ``'honeypot'``
+* ``$template`` - form field template used for the honeypot; default is ``''``
+* ``$container`` - container tag for the template; default is ``'
{template}
'``.
+ If you enables CSP, you can remove ``style="display:none"``.
+* ``$containerId`` - [Since v4.3.0] this setting is used only when you enables CSP. You can change the id attribute for the container tag; default is ``'hpc'``
diff --git a/user_guide_src/source/libraries/honeypot/001.php b/user_guide_src/source/libraries/honeypot/001.php
index f0dbf7e64d57..573010145976 100644
--- a/user_guide_src/source/libraries/honeypot/001.php
+++ b/user_guide_src/source/libraries/honeypot/001.php
@@ -6,14 +6,18 @@
class Filters extends BaseConfig
{
+ // ...
+
public $globals = [
'before' => [
'honeypot',
// 'csrf',
+ // 'invalidchars',
],
'after' => [
'toolbar',
'honeypot',
+ // 'secureheaders',
],
];