add_filter
Opened this issue · 2 comments
Hi, do you provide a filters (add_filter) so rules including dynamically generated nonce-xxx can be merged into the generated header ?
This could be a great feature.
thanks
A dedicated filter to customize the policies before they are output as HTTP Headers would indeed be appreciated.
Until then, I've created the following workaround that ensures any dynamically changed directives/policies are not persisted to the database (when saving changes from the plugin's settings page):
/**
* Determines if the CSP Manager is preparing to output HTTP Headers.
*
* Uses a PHP backtrace to locate calls from {@see \CSP_Manager\Core::csp_init()}.
*/
function is_csp_manager_doing_http_headers(): bool {
foreach ( debug_backtrace( DEBUG_BACKTRACE_IGNORE_ARGS, 6 ) as $call ) {
if (
isset( $call['function'], $call['class'] ) &&
'csp_init' === $call['function'] &&
'CSP_Manager\Core' === $call['class']
) {
return true;
}
}
return false;
}
/**
* Customizes the CSP Manager policies to include
* the staging environment for remote assets.
*
* @listens filter:option_csp_manager_admin
* @listens filter:option_csp_manager_loggedin
* @listens filter:option_csp_manager_frontend
*
* @param mixed $settings The CSP directives, policies, and options.
* @return mixed
*/
function filter_csp_manager_customize_settings( mixed $settings ): mixed {
if (
$settings === false ||
! isset( $settings['mode'] ) ||
'disabled' === $settings['mode'] ||
! is_csp_manager_doing_http_headers()
) {
return $settings;
}
$directives = [
'img-src' => 'https://example.com',
];
foreach ( $directives as $directive => $policy ) {
if (
isset( $settings[ 'enable_' . $directive ] ) &&
$settings[ 'enable_' . $directive ]
) {
$settings[ $directive ] = (
isset( $settings[ $directive ] )
? $settings[ $directive ] . ' '
: ''
) . $policy;
}
}
return $settings;
}
add_action( 'option_csp_manager_admin', 'filter_csp_manager_customize_settings', 10, 1 );
add_action( 'option_csp_manager_loggedin', 'filter_csp_manager_customize_settings', 10, 1 );
add_action( 'option_csp_manager_frontend', 'filter_csp_manager_customize_settings', 10, 1 );
What this does is mutate the three main options of the CSP Manager:
csp_manager_admin
csp_manager_loggedin
csp_manager_frontend
Via the option_{$option}
hook.
The function is_csp_manager_doing_http_headers()
is used to search through a slice of the PHP backtrace to determine if the filter function filter_csp_manager_customize_settings()
was called from CSP_Manager\Core::csp_init()
which handles the output of HTTP Headers.
The main purpose of this filter function, for my use case, is to append our staging environment's hostname (using example.com
for demonstration) to the img-src
directive to allow my localhost to fetch images from the staging environment if they are absent locally.
Fantastic. i will try it out ...