xref: /plugin/combo/action/webcode.php (revision 977ce05d19d8dab0a70c9a27f8da0b7039299e82)
1<?php
2
3use ComboStrap\ExceptionCombo;
4use ComboStrap\Identity;
5use ComboStrap\PluginUtility;
6use ComboStrap\Site;
7use ComboStrap\TplUtility;
8
9if (!defined('DOKU_INC')) die();
10
11/**
12 *
13 */
14class  action_plugin_combo_webcode extends DokuWiki_Action_Plugin
15{
16
17    const CALL_ID = "webcode";
18    const MARKI_PARAM = "marki";
19
20
21    function register(Doku_Event_Handler $controller)
22    {
23        /**
24         * To serve fragment
25         */
26        $controller->register_hook('AJAX_CALL_UNKNOWN', 'BEFORE', $this, '_ajax_call');
27
28        /**
29         * To enforce security
30         */
31        $controller->register_hook('COMMON_WIKIPAGE_SAVE', 'BEFORE', $this, '_enforceSecurity');
32
33    }
34
35    /**
36     * handle ajax requests
37     * @param $event Doku_Event
38     *
39     * {@link html_show()}
40     *
41     * https://www.dokuwiki.org/devel:plugin_programming_tips#handle_json_ajax_request
42     *
43     * CSRF checks are only for logged in users
44     * This is public ({@link getSecurityToken()}
45     */
46    function _ajax_call(&$event)
47    {
48
49        if ($event->data !== self::CALL_ID) {
50            return;
51        }
52        //no other ajax call handlers needed
53        $event->stopPropagation();
54        $event->preventDefault();
55
56
57        global $INPUT;
58        $marki = $INPUT->str(self::MARKI_PARAM);
59        $title = $INPUT->str('title') ?: "ComboStrap WebCode - Dokuwiki Renderer";
60
61
62        header('Content-Type: text/html; charset=utf-8');
63
64        /**
65         * Conf
66         */
67        PluginUtility::setConf(action_plugin_combo_css::CONF_DISABLE_DOKUWIKI_STYLESHEET, true);
68
69        /**
70         * Main content happens before the headers
71         * to set the headers right
72         */
73        global $conf;
74        $conf["renderer_xhtml"] = "xhtml";
75
76        global $ID;
77        $keep = $ID;
78        try {
79            $ID = "ajax_webcode_" . md5($marki);
80            $mainContent = p_render('xhtml', p_get_instructions($marki), $info);
81
82            /**
83             * Html
84             */
85            $htmlBeforeHeads = '<!DOCTYPE html>' . DOKU_LF;
86            $htmlBeforeHeads .= '<html lang="en">' . DOKU_LF;
87            $htmlBeforeHeads .= '<head>' . DOKU_LF;
88            $htmlBeforeHeads .= "  <title>$title</title>" . DOKU_LF;
89            // we echo because the tpl function just flush
90            echo $htmlBeforeHeads;
91
92            if (Site::isStrapTemplate()) {
93
94                /**
95                 * The strap header function
96                 */
97                try {
98                    Site::loadStrapUtilityTemplateIfPresentAndSameVersion();
99                    TplUtility::registerHeaderHandler();
100                } catch (ExceptionCombo $e) {
101                    \ComboStrap\LogUtility::log2file("Error while registering the header handler on webcode ajax call. Error: {$e->getMessage()}");
102                }
103
104            }
105
106            /**
107             * To delete the not needed headers for an export
108             * such as manifest, alternate, ...
109             */
110            global $EVENT_HANDLER;
111            $EVENT_HANDLER->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, '_delete_not_needed_headers');
112
113            /**
114             * meta headers
115             */
116            tpl_metaheaders();
117
118
119            $htmlAfterHeads = '</head>' . DOKU_LF;
120            $htmlAfterHeads .= '<body>' . DOKU_LF;
121            $htmlAfterHeads .= $mainContent . DOKU_LF;
122            $htmlAfterHeads .= '</body>' . DOKU_LF;
123            $htmlAfterHeads .= '</html>' . DOKU_LF;
124            echo $htmlAfterHeads;
125            http_response_code(200);
126
127        } finally {
128            $ID = $keep;
129        }
130
131    }
132
133    /**
134     * Dynamically called in the previous function
135     * to delete the head
136     * * @param $event Doku_Event
137     */
138    public function _delete_not_needed_headers(Doku_Event &$event)
139    {
140        $data = &$event->data;
141
142        foreach ($data as $tag => &$heads) {
143            switch ($tag) {
144                case "link":
145                    $deletedRel = ["manifest", "search", "start", "alternate", "contents"];
146                    foreach ($heads as $id => $headAttributes) {
147                        if (isset($headAttributes['rel'])) {
148                            $rel = $headAttributes['rel'];
149                            if (in_array($rel, $deletedRel)) {
150                                unset($heads[$id]);
151                            }
152                        }
153                    }
154                    break;
155                case "meta":
156                    $deletedMeta = ["robots"];
157                    foreach ($heads as $id => $headAttributes) {
158                        if (isset($headAttributes['name'])) {
159                            $rel = $headAttributes['name'];
160                            if (in_array($rel, $deletedMeta)) {
161                                unset($heads[$id]);
162                            }
163                        }
164                    }
165                    break;
166                case "script":
167                    foreach ($heads as $id => $headAttributes) {
168                        if (isset($headAttributes['src'])) {
169                            $src = $headAttributes['src'];
170                            if (strpos($src, "lib/exe/js.php") !== false) {
171                                unset($heads[$id]);
172                            }
173                        }
174                    }
175            }
176        }
177    }
178
179    /**
180     * @param $event Doku_Event https://www.dokuwiki.org/devel:event:common_wikipage_save
181     * @return void
182     */
183    function _enforceSecurity(Doku_Event &$event)
184    {
185
186        $data = $event->data;
187        $text = $data["newContent"];
188        $pattern = PluginUtility::getContainerTagPattern(syntax_plugin_combo_webcode::TAG);
189        $result = preg_match("/" . $pattern . "/ms", $text);
190        if ($result === 0) {
191            return;
192        }
193
194        $isAdmin = Identity::isAdmin();
195        $isMember = Identity::isMember("@" . action_plugin_combo_svg::CONF_SVG_UPLOAD_GROUP_NAME);
196        if (!($isAdmin || $isMember)) {
197            $event->preventDefault();
198        }
199
200    }
201
202}
203