xref: /plugin/combo/action/metacsp.php (revision 531e725cdb5a652164f2d97f556304e31f720033)
121913ab3SNickeau<?php
221913ab3SNickeau
3*531e725cSNickeauuse ComboStrap\Site;
421913ab3SNickeauuse ComboStrap\StringUtility;
521913ab3SNickeau
621913ab3SNickeauif (!defined('DOKU_INC')) die();
721913ab3SNickeau
821913ab3SNickeau/**
921913ab3SNickeau *
1021913ab3SNickeau * Adding security directive
1121913ab3SNickeau *
1221913ab3SNickeau */
1321913ab3SNickeauclass action_plugin_combo_metacsp extends DokuWiki_Action_Plugin
1421913ab3SNickeau{
1521913ab3SNickeau
1621913ab3SNickeau
1721913ab3SNickeau    function __construct()
1821913ab3SNickeau    {
1921913ab3SNickeau        // enable direct access to language strings
2021913ab3SNickeau        // ie $this->lang
2121913ab3SNickeau        $this->setupLocale();
2221913ab3SNickeau    }
2321913ab3SNickeau
2421913ab3SNickeau    public function register(Doku_Event_Handler $controller)
2521913ab3SNickeau    {
2621913ab3SNickeau        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'metaCsp', array());
2721913ab3SNickeau    }
2821913ab3SNickeau
2921913ab3SNickeau    /**
3021913ab3SNickeau     * Dokuwiki has already a canonical methodology
3121913ab3SNickeau     * https://www.dokuwiki.org/canonical
3221913ab3SNickeau     *
3321913ab3SNickeau     * @param $event
3421913ab3SNickeau     */
3521913ab3SNickeau    function metaCsp($event)
3621913ab3SNickeau    {
3721913ab3SNickeau
38*531e725cSNickeau
39*531e725cSNickeau        /**
40*531e725cSNickeau         * HTML meta directives
41*531e725cSNickeau         */
4221913ab3SNickeau        $directives = [
4321913ab3SNickeau            'block-all-mixed-content', // no http, https
4421913ab3SNickeau        ];
4521913ab3SNickeau
4621913ab3SNickeau        // Search if the CSP property is already present
4721913ab3SNickeau        $cspKey = null;
4821913ab3SNickeau        foreach ($event->data['meta'] as $key => $meta) {
4921913ab3SNickeau            if (isset($meta["http-equiv"])) {
5021913ab3SNickeau                if ($meta["http-equiv"] == "Content-Security-Policy") {
5121913ab3SNickeau                    $cspKey = $key;
5221913ab3SNickeau                }
5321913ab3SNickeau            }
5421913ab3SNickeau        }
5521913ab3SNickeau        if ($cspKey != null) {
5621913ab3SNickeau            $actualDirectives = StringUtility::explodeAndTrim($event->data['meta'][$cspKey]["content"], ",");
5721913ab3SNickeau            $directives = array_merge($actualDirectives, $directives);
5821913ab3SNickeau            $event->data['meta'][$cspKey] = [
5921913ab3SNickeau                "http-equiv" => "Content-Security-Policy",
6021913ab3SNickeau                "content" => join(", ", $directives)
6121913ab3SNickeau            ];
6221913ab3SNickeau        } else {
6321913ab3SNickeau            $event->data['meta'][] = [
6421913ab3SNickeau                "http-equiv" => "Content-Security-Policy",
6521913ab3SNickeau                "content" => join(",", $directives)
6621913ab3SNickeau            ];
6721913ab3SNickeau        }
6821913ab3SNickeau
69*531e725cSNickeau        /**
70*531e725cSNickeau         * Http header CSP directives
71*531e725cSNickeau         */
72*531e725cSNickeau        $httpHeaderReferer = $_SERVER['HTTP_REFERER'];
73*531e725cSNickeau        $httpDirectives = [];
74*531e725cSNickeau        if (strpos($httpHeaderReferer, Site::getUrl()) === false) {
75*531e725cSNickeau            // not same origin
7621913ab3SNickeau            $httpDirectives = [
7721913ab3SNickeau                "Content-Security-Policy: frame-ancestors 'none'", // the page cannot be used in a iframe (clickjacking),
7821913ab3SNickeau                "X-Frame-Options: deny" // the page cannot be used in a iframe (clickjacking) - deprecated for frame ancestores
7921913ab3SNickeau            ];
80*531e725cSNickeau        }
8121913ab3SNickeau        foreach ($httpDirectives as $httpDirective) {
8221913ab3SNickeau            header($httpDirective);
8321913ab3SNickeau        }
8421913ab3SNickeau
8521913ab3SNickeau    }
8621913ab3SNickeau
8721913ab3SNickeau}
88