16 $this->mRoot->mDelegateManager->add(
'Legacy_RenderSystem.SetupXoopsTpl', array($this,
'addCSPHeaders'), XCUBE_DELEGATE_PRIORITY_FIRST);
19 $this->mRoot->mDelegateManager->add(
'Legacy_RenderSystem.RenderTheme', array($this,
'ensureCSPHeaders'), XCUBE_DELEGATE_PRIORITY_FIRST);
27 $log_dir = XOOPS_CACHE_PATH .
'/protector/logs';
28 if (!is_dir($log_dir)) {
29 @mkdir($log_dir, 0755,
true);
33 public function addCSPHeaders(&$xoopsTpl)
37 $this->logDebug(
'Headers already sent when addCSPHeaders was called');
42 $moduleHandler = xoops_gethandler(
'module');
43 $configHandler = xoops_gethandler(
'config');
45 $module = $moduleHandler->getByDirname(
'protector');
46 if (!is_object($module)) {
47 $this->logDebug(
'Protector module not found');
51 $configs = $configHandler->getConfigsByCat(0, $module->getVar(
'mid'));
54 if (empty($configs[
'enable_csp'])) {
55 $this->logDebug(
'CSP is disabled in Protector settings');
60 $policy = $this->buildCSPPolicy($configs);
63 header(
"Content-Security-Policy: " . $policy);
66 if (!empty($configs[
'csp_report_only'])) {
67 header(
"Content-Security-Policy-Report-Only: " . $policy);
71 if (!empty($configs[
'csp_legacy_support']) && is_object($xoopsTpl)) {
72 $meta_tag =
'<meta http-equiv="Content-Security-Policy" content="' . htmlspecialchars($policy, ENT_QUOTES) .
'">';
73 $xoopsTpl->assign(
'xoops_csp_meta', $meta_tag);
76 $metas = $xoopsTpl->get_template_vars(
'xoops_meta');
77 if (!is_array($metas)) {
80 $metas[
'csp'] = array(
'http-equiv' =>
'Content-Security-Policy',
'content' => $policy);
81 $xoopsTpl->assign(
'xoops_meta', $metas);
84 $this->logDebug(
'CSP headers added: ' . $policy);
88 public function ensureCSPHeaders(&$xoopsTpl)
91 if (!headers_sent() && !isset($GLOBALS[
'CSP_HEADERS_ADDED'])) {
92 $this->addCSPHeaders($xoopsTpl);
93 $GLOBALS[
'CSP_HEADERS_ADDED'] =
true;
97 private function buildCSPPolicy($configs)
102 if (!empty($configs[
'csp_default_src'])) {
103 $policy[] =
"default-src " . $configs[
'csp_default_src'];
105 $policy[] =
"default-src 'self'";
109 if (!empty($configs[
'csp_script_src'])) {
110 $policy[] =
"script-src " . $configs[
'csp_script_src'];
114 if (!empty($configs[
'csp_style_src'])) {
115 $policy[] =
"style-src " . $configs[
'csp_style_src'];
119 if (!empty($configs[
'csp_img_src'])) {
120 $policy[] =
"img-src " . $configs[
'csp_img_src'];
124 if (!empty($configs[
'csp_connect_src'])) {
125 $policy[] =
"connect-src " . $configs[
'csp_connect_src'];
129 if (!empty($configs[
'csp_font_src'])) {
130 $policy[] =
"font-src " . $configs[
'csp_font_src'];
134 if (!empty($configs[
'csp_object_src'])) {
135 $policy[] =
"object-src " . $configs[
'csp_object_src'];
139 if (!empty($configs[
'csp_media_src'])) {
140 $policy[] =
"media-src " . $configs[
'csp_media_src'];
144 if (!empty($configs[
'csp_frame_src'])) {
145 $policy[] =
"frame-src " . $configs[
'csp_frame_src'];
149 $report_uri = !empty($configs[
'csp_report_uri'])
150 ? $configs[
'csp_report_uri']
151 : XOOPS_URL .
'/modules/protector/csp-report.php';
153 $policy[] =
"report-uri " . $report_uri;
155 return implode(
'; ', $policy);
159 private function logDebug($message)
162 $moduleHandler = xoops_gethandler(
'module');
163 $configHandler = xoops_gethandler(
'config');
164 $module = $moduleHandler->getByDirname(
'protector');
166 if (is_object($module)) {
167 $configs = $configHandler->getConfigsByCat(0, $module->getVar(
'mid'));
170 if (!empty($configs[
'csp_debug'])) {
171 $log_file = XOOPS_CACHE_PATH .
'/protector/logs/csp_debug.log';
172 $log_entry = date(
'Y-m-d H:i:s') .
' - ' . $message .
"\n";
173 @file_put_contents($log_file, $log_entry, FILE_APPEND);
176 error_log(
'CSP: ' . $message);
preBlockFilter()
[Abstract] Executes the logic, when the controller executes preBlockFilter().