Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions cleantalk.php
Original file line number Diff line number Diff line change
Expand Up @@ -615,11 +615,11 @@ function apbct_write_js_errors($data)


add_action('mec_booking_end_form_step_2', function () {
echo "<script>
if (typeof ctPublic.force_alt_cookies == 'undefined' || (ctPublic.force_alt_cookies !== 'undefined' && !ctPublic.force_alt_cookies)) {
echo apbct_get_inline_script_tag(
"if (typeof ctPublic.force_alt_cookies == 'undefined' || (ctPublic.force_alt_cookies !== 'undefined' && !ctPublic.force_alt_cookies)) {
ctNoCookieAttachHiddenFieldsToForms();
}
</script>";
}"
);
});

// Public actions
Expand Down
64 changes: 64 additions & 0 deletions inc/cleantalk-pluggable.php
Original file line number Diff line number Diff line change
Expand Up @@ -2298,3 +2298,67 @@ function apbct_get_email_encoder_pass_key()

return md5(Helper::ipGet() . $apbct->api_key . 'email_encoder');
}

/**
* Returns CSP nonce for CleanTalk inline scripts.
*
* @return string
*/
function apbct_get_csp_nonce()
{
/**
* Filter CSP nonce for CleanTalk inline scripts.
*
* @param string $nonce CSP nonce value for script tags.
*/
return (string) apply_filters('apbct_csp_nonce', '');
}

/**
* Returns inline script tag with optional CSP nonce.
*
* @param string $javascript JavaScript code.
* @param array<string, string|bool> $attributes Script tag attributes.
*
* @return string
*/
function apbct_get_inline_script_tag($javascript, $attributes = array())
{
$nonce = apbct_get_csp_nonce();
if ( $nonce !== '' ) {
$attributes['nonce'] = $nonce;
}

if ( function_exists('wp_get_inline_script_tag') ) {
return wp_get_inline_script_tag($javascript, $attributes);
}

$attr_string = '';
foreach ( $attributes as $name => $value ) {
if ( $value === true ) {
$attr_string .= ' ' . esc_attr($name);
} elseif ( $value !== false && $value !== null && $value !== '' ) {
$attr_string .= ' ' . esc_attr($name) . '="' . esc_attr((string) $value) . '"';
}
}

$javascript = preg_replace('#</script#i', '<\/script', $javascript);

return '<script' . $attr_string . '>' . $javascript . '</script>';
}

/**
* Returns allowed HTML tags for inline CleanTalk scripts passed through kses.
*
* @return array<string, array<string, bool>>
*/
function apbct_get_inline_script_kses()
{
return array(
'script' => array(
'type' => true,
'data-cookieconsent' => true,
'nonce' => true,
),
);
}
50 changes: 26 additions & 24 deletions inc/cleantalk-public.php
Original file line number Diff line number Diff line change
Expand Up @@ -594,28 +594,25 @@ function apbct_hook__wp_footer()
}";
}

$cookie_bot_asset = (class_exists('Cookiebot_WP')) ? 'data-cookieconsent="ignore"' : '';
$script_attrs = array();
if ( class_exists('Cookiebot_WP') ) {
$script_attrs['data-cookieconsent'] = 'ignore';
}

$script =
'<script ' . $cookie_bot_asset
. ">
document.addEventListener('DOMContentLoaded', function () {
$script = apbct_get_inline_script_tag(
"document.addEventListener('DOMContentLoaded', function () {
setTimeout(function(){
if( document.querySelectorAll('[name^=ct_checkjs]').length > 0 ) {
" . $send_way_asset . "
}
}," . $timeout . ")
})
</script>";
}," . $timeout . ")
})",
$script_attrs
);

echo Escape::escKses(
$script,
array(
'script' => array(
'type' => true,
'data-cookieconsent' => true
)
)
apbct_get_inline_script_kses()
);
}
}
Expand Down Expand Up @@ -674,18 +671,24 @@ function ct_add_hidden_fields(
return;
}

$script_attrs = array();
if ( class_exists('Cookiebot_WP') ) {
$script_attrs['data-cookieconsent'] = 'ignore';
}

$ct_input_challenge = sprintf("'%s'", is_null($ct_checkjs_key) ? $ct_checkjs_def : $ct_checkjs_key);
$field_id = $field_name . '_' . $field_id_hash;
$html = "<input type=\"hidden\" id=\"{$field_id}\" name=\"{$field_name}\" value=\"{$ct_checkjs_def}\" />
<script " . (class_exists('Cookiebot_WP') ? 'data-cookieconsent="ignore"' : '') . ">
setTimeout(function(){
$html = "<input type=\"hidden\" id=\"{$field_id}\" name=\"{$field_name}\" value=\"{$ct_checkjs_def}\" />"
. apbct_get_inline_script_tag(
"setTimeout(function(){
var ct_input_name = \"{$field_id}\";
if (document.getElementById(ct_input_name) !== null) {
var ct_input_value = document.getElementById(ct_input_name).value;
document.getElementById(ct_input_name).value = document.getElementById(ct_input_name).value.replace(ct_input_value, {$ct_input_challenge});
}
}, 1000);
</script>";
}, 1000);",
$script_attrs
);
}

// Simplify JS code and Fixing issue with wpautop()
Expand All @@ -696,17 +699,16 @@ function ct_add_hidden_fields(
} else {
echo Escape::escKses(
$html,
array(
'script' => array(
'type' => true,
'data-cookieconsent' => true
),
array_merge(
apbct_get_inline_script_kses(),
array(
'input' => array(
'type' => true,
'id' => true,
'name' => true,
'value' => true
)
)
)
);
}
Expand Down
12 changes: 6 additions & 6 deletions lib/Cleantalk/Antispam/Integrations/CleantalkExternalForms.php
Original file line number Diff line number Diff line change
Expand Up @@ -163,11 +163,11 @@ private function constructOriginExternalForm($action, $method)
</html>';

// Cookiebot chunk
$bot_chunk = class_exists('Cookiebot_WP') ? 'data-cookieconsent="ignore"' : '';
$bot_attrs = class_exists('Cookiebot_WP') ? array('data-cookieconsent' => 'ignore') : array();

// HTML form clearing script
$script = "<script " . $bot_chunk . ">
let form = document.forms[0];
$script = apbct_get_inline_script_tag(
"let form = document.forms[0];
let availabilitySubmit = false;
for (let i = 0; i < form.length; i++) {
let typeElem = form[i].getAttribute('type');
Expand All @@ -182,9 +182,9 @@ private function constructOriginExternalForm($action, $method)
form.removeChild(objects[0]);
}
}
form.submit();
</script>
";
form.submit();",
$bot_attrs
);

$form_template = str_replace('%METHOD', $method, $form_template);
$form_template = str_replace('%ACTION', $action, $form_template);
Expand Down
9 changes: 4 additions & 5 deletions lib/Cleantalk/ApbctWP/Firewall/AntiCrawler.php
Original file line number Diff line number Diff line change
Expand Up @@ -459,12 +459,11 @@ public static function setCookie()
{
global $apbct;

$script =
"<script>
window.addEventListener('DOMContentLoaded', function () {
$script = apbct_get_inline_script_tag(
"window.addEventListener('DOMContentLoaded', function () {
ctSetCookie( " . json_encode(self::COOKIE_NAME__ANTIBOT) . ", '" . apbct_get_anti_bot_cookie_hash($apbct->api_key, $apbct->data['salt']) . "', 0 );
});
</script>";
});"
);

echo $script;
}
Expand Down
15 changes: 10 additions & 5 deletions lib/Cleantalk/ApbctWP/Localize/CtPublicFunctionsLocalize.php
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,15 @@ public static function getData()

public static function getCode()
{
return '
<script data-no-defer="1" data-ezscrex="false" data-cfasync="false" data-pagespeed-no-defer data-cookieconsent="ignore">
var ' . self::NAME . ' = ' . json_encode(self::getData()) . '
</script>
';
return apbct_get_inline_script_tag(
'var ' . self::NAME . ' = ' . json_encode(self::getData()),
array(
'data-no-defer' => '1',
'data-ezscrex' => 'false',
Comment thread
Copilot marked this conversation as resolved.
'data-cfasync' => 'false',
'data-pagespeed-no-defer' => true,
'data-cookieconsent' => 'ignore',
)
);
}
}
15 changes: 10 additions & 5 deletions lib/Cleantalk/ApbctWP/Localize/CtPublicLocalize.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,10 +50,15 @@ public static function getData()

public static function getCode()
{
return '
<script data-no-defer="1" data-ezscrex="false" data-cfasync="false" data-pagespeed-no-defer data-cookieconsent="ignore">
var ' . self::NAME . ' = ' . json_encode(self::getData()) . '
</script>
';
return apbct_get_inline_script_tag(
'var ' . self::NAME . ' = ' . json_encode(self::getData()),
array(
'data-no-defer' => '1',
'data-ezscrex' => 'false',
Comment thread
Copilot marked this conversation as resolved.
'data-cfasync' => 'false',
'data-pagespeed-no-defer' => true,
'data-cookieconsent' => 'ignore',
)
);
}
}
57 changes: 57 additions & 0 deletions tests/ApbctWP/TestCspNonce.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

use Cleantalk\ApbctWP\State;

class TestCspNonce extends \PHPUnit\Framework\TestCase
{
/** @var mixed */
private $original_apbct;

protected function setUp(): void
{
parent::setUp();
global $apbct;
$this->original_apbct = $apbct;
$apbct = new State('cleantalk', array('settings', 'data', 'errors', 'remote_calls', 'stats', 'fw_stats'));
}

protected function tearDown(): void
{
remove_all_filters('apbct_csp_nonce');
global $apbct;
$apbct = $this->original_apbct;
parent::tearDown();
}

public function testInlineScriptTagWithoutNonce()
{
$tag = apbct_get_inline_script_tag('var test = 1;');

$this->assertStringContainsString('var test = 1;', $tag);
$this->assertStringNotContainsString('nonce=', $tag);
}

public function testInlineScriptTagWithNonceFilter()
{
add_filter('apbct_csp_nonce', function () {
return 'test-nonce-value';
});

$tag = apbct_get_inline_script_tag('var test = 1;');

$this->assertStringContainsString('nonce="test-nonce-value"', $tag);
}

public function testLocalizeScriptsIncludeNonceWhenFilterIsSet()
{
add_filter('apbct_csp_nonce', function () {
return 'localize-nonce';
});

$functions_tag = \Cleantalk\ApbctWP\Localize\CtPublicFunctionsLocalize::getCode();
$public_tag = \Cleantalk\ApbctWP\Localize\CtPublicLocalize::getCode();

$this->assertStringContainsString('nonce="localize-nonce"', $functions_tag);
$this->assertStringContainsString('nonce="localize-nonce"', $public_tag);
}
}
Loading