xref: /plugin/combo/action/pageprotection.php (revision 65e00826e4eceefc13be6f404ba5dcc7c44f243c)
1<?php
2
3require_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
4
5use ComboStrap\ExceptionBadArgument;
6use ComboStrap\ExceptionBadSyntax;
7use ComboStrap\ExecutionContext;
8use ComboStrap\FetcherPage;
9use ComboStrap\FileSystems;
10use ComboStrap\LogUtility;
11use ComboStrap\Web\Url;
12use ComboStrap\WikiPath;
13use ComboStrap\Identity;
14use ComboStrap\LowQualityPage;
15use ComboStrap\MarkupPath;
16use ComboStrap\PageProtection;
17use ComboStrap\PagePublicationDate;
18
19
20/**
21 *
22 */
23class action_plugin_combo_pageprotection extends DokuWiki_Action_Plugin
24{
25
26
27    public function register(Doku_Event_Handler $controller)
28    {
29
30
31        /**
32         * https://www.dokuwiki.org/devel:event:pageutils_id_hidepage
33         */
34        $controller->register_hook('PAGEUTILS_ID_HIDEPAGE', 'BEFORE', $this, 'handleHiddenCheck', array());
35
36        /**
37         * https://www.dokuwiki.org/devel:event:auth_acl_check
38         */
39        $controller->register_hook('AUTH_ACL_CHECK', 'AFTER', $this, 'handleAclCheck', array());
40
41        /**
42         * https://www.dokuwiki.org/devel:event:sitemap_generate
43         */
44        $controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handleSiteMapGenerate', array());
45
46        /**
47         * https://www.dokuwiki.org/devel:event:search_query_pagelookup
48         */
49        $controller->register_hook('SEARCH_QUERY_PAGELOOKUP', 'AFTER', $this, 'handleSearchPageLookup', array());
50
51        /**
52         * https://www.dokuwiki.org/devel:event:search_query_fullpage
53         */
54        $controller->register_hook('SEARCH_QUERY_FULLPAGE', 'AFTER', $this, 'handleSearchFullPage', array());
55
56        /**
57         * https://www.dokuwiki.org/devel:event:feed_data_process
58         */
59        $controller->register_hook('FEED_DATA_PROCESS', 'BEFORE', $this, 'handleRssFeed', array());
60
61
62        /**
63         * Robots meta
64         * https://www.dokuwiki.org/devel:event:tpl_metaheader_output
65         */
66        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleRobotsMeta', array());
67
68
69    }
70
71    /**
72     * Set page has hidden
73     * @param $event
74     * @param $param
75     */
76    function handleHiddenCheck(&$event, $param)
77    {
78
79        /**
80         * Only for public
81         */
82        if (Identity::isLoggedIn()) {
83            return;
84        }
85
86        $id = $event->data['id'];
87        if ($id == null) {
88            /**
89             * Happens in test when rendering
90             * with instructions only
91             */
92            return;
93        }
94        $page = MarkupPath::createMarkupFromId($id);
95
96        if ($page->isLowQualityPage()) {
97            if (LowQualityPage::getLowQualityProtectionMode() == PageProtection::CONF_VALUE_HIDDEN) {
98                $event->data['hidden'] = true;
99                return;
100            }
101        }
102        if ($page->isLatePublication()) {
103            if (PagePublicationDate::getLatePublicationProtectionMode() == PageProtection::CONF_VALUE_HIDDEN) {
104                $event->data['hidden'] = true;
105            }
106
107        }
108
109    }
110
111    /**
112     *
113     * https://www.dokuwiki.org/devel:event:auth_acl_check
114     * @param $event
115     * @param $param
116     */
117    function handleAclCheck(&$event, $param)
118    {
119        /**
120         * Only for public
121         *
122         * Note: user is also
123         * to be found at
124         * $user = $event->data['user'];
125         */
126        if (Identity::isLoggedIn()) {
127            return;
128        }
129
130        /**
131         * Are we on a page script
132         */
133        $imageScript = ["/lib/exe/mediamanager.php", "/lib/exe/detail.php"];
134        if (in_array($_SERVER['SCRIPT_NAME'], $imageScript)) {
135            // id may be null or end with a star
136            // this is not a image
137            return;
138        }
139
140        $id = $event->data['id'];
141        if ($id == null) {
142            /**
143             * Happens in test when rendering
144             * with instructions only
145             */
146            return;
147        }
148
149        $dokuPath = WikiPath::createFromUnknownRoot($id);
150        if ($dokuPath->isPage()) {
151
152            /**
153             * It should be only a page
154             * https://www.dokuwiki.org/devel:event:auth_acl_check
155             */
156            $page = MarkupPath::createMarkupFromId($id);
157
158            if ($page->isLowQualityPage()) {
159                if ($this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_ENABLE, true)) {
160                    $securityConf = $this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_MODE, PageProtection::CONF_VALUE_ACL);
161                    if ($securityConf == PageProtection::CONF_VALUE_ACL) {
162                        $event->result = AUTH_NONE;
163                        return;
164                    }
165                }
166            }
167            if ($page->isLatePublication()) {
168                if ($this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_ENABLE, true)) {
169                    $securityConf = $this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_MODE, PageProtection::CONF_VALUE_ACL);
170                    if ($securityConf == PageProtection::CONF_VALUE_ACL) {
171                        $event->result = AUTH_NONE;
172                        return;
173                    }
174                }
175            }
176
177        }
178
179    }
180
181    function handleSiteMapGenerate(&$event, $param)
182    {
183        $pageItems = $event->data["items"];
184        foreach ($pageItems as $key => $pageItem) {
185
186            try {
187                $url = Url::createFromString($pageItem->url);
188                $fetcherPage = FetcherPage::createPageFragmentFetcherFromUrl($url);
189            } catch (ExceptionBadArgument|ExceptionBadSyntax  $e) {
190                LogUtility::internalError("We were unable to build the page fetcher. Error: " . $e->getMessage(), "sitemap", $e);
191                continue;
192            }
193
194            $page = MarkupPath::createPageFromPathObject($fetcherPage->getSourcePath());
195            if ($page->isLowQualityPage() && LowQualityPage::isProtectionEnabled()) {
196
197                unset($event->data["items"][$key]);
198                continue;
199
200            }
201            if ($page->isLatePublication() && PagePublicationDate::isLatePublicationProtectionEnabled()) {
202                unset($event->data["items"][$key]);
203            }
204            /**
205             * Url rewrite
206             */
207            $urlAfterRewrite = $page->getCanonicalUrl()->toString();
208            $event->data["items"][$key]->url = $urlAfterRewrite;
209        }
210
211    }
212
213    /**
214     * @param $event
215     * @param $param
216     * The autocomplete do a search on page name
217     */
218    function handleSearchPageLookup(&$event, $param)
219    {
220        $this->excludePageFromSearch($event);
221    }
222
223    /**
224     * @param $event
225     * @param $param
226     * The search page do a search on page name
227     */
228    function handleSearchFullPage(&$event, $param)
229    {
230
231        $this->excludePageFromSearch($event);
232    }
233
234    /**
235     *
236     * @param $event
237     * @param $param
238     * The Rss
239     * https://www.dokuwiki.org/syndication
240     * Example
241     * https://example.com/feed.php?type=rss2&num=5
242     */
243    function handleRssFeed(&$event, $param)
244    {
245        $isLowQualityProtectionEnabled = LowQualityPage::isProtectionEnabled();
246        $isLatePublicationProtectionEnabled = PagePublicationDate::isLatePublicationProtectionEnabled();
247        if (!$isLatePublicationProtectionEnabled && !$isLowQualityProtectionEnabled) {
248            return;
249        }
250
251        $pagesToBeAdded = &$event->data["data"];
252        foreach ($pagesToBeAdded as $key => $data) {
253
254            // To prevent an Illegal string offset 'id'
255            if (isset($data["id"])) {
256
257                $page = MarkupPath::createMarkupFromId($data["id"]);
258
259                if ($page->isLowQualityPage() && $isLowQualityProtectionEnabled) {
260                    $protectionMode = LowQualityPage::getLowQualityProtectionMode();
261                    if ($protectionMode != PageProtection::CONF_VALUE_ROBOT) {
262                        unset($pagesToBeAdded[$key]);
263                    }
264                }
265
266                if ($page->isLatePublication() && $isLatePublicationProtectionEnabled) {
267                    $protectionMode = PagePublicationDate::getLatePublicationProtectionMode();
268                    if ($protectionMode != PageProtection::CONF_VALUE_ROBOT) {
269                        unset($pagesToBeAdded[$key]);
270                    }
271                }
272
273            }
274        }
275
276    }
277
278    /**
279     * @param $event
280     * @param array $protectionModes
281     */
282    private
283    function excludePageFromSearch(&$event, $protectionModes = [PageProtection::CONF_VALUE_ACL, PageProtection::CONF_VALUE_HIDDEN])
284    {
285
286        /**
287         * The value is always an array
288         * but as we got this error:
289         * ```
290         * array_keys() expects parameter 1 to be array
291         * ```
292         * The result is a list of page id
293         */
294        if (is_array($event->result)) {
295            foreach (array_keys($event->result) as $idx) {
296                $page = MarkupPath::createMarkupFromId($idx);
297                if ($page->isLowQualityPage()) {
298                    $securityConf = $this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_MODE);
299                    if (in_array($securityConf, $protectionModes)) {
300                        unset($event->result[$idx]);
301                        return;
302                    }
303                }
304                if ($page->isLatePublication()) {
305                    $securityConf = $this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_MODE);
306                    if (in_array($securityConf, [PageProtection::CONF_VALUE_ACL, PageProtection::CONF_VALUE_HIDDEN])) {
307                        unset($event->result[$idx]);
308                        return;
309                    }
310                }
311            }
312        }
313
314    }
315
316
317    /**
318     * Handle the meta robots
319     * https://www.dokuwiki.org/devel:event:tpl_metaheader_output
320     * @param $event
321     * @param $param
322     */
323    function handleRobotsMeta(&$event, $param)
324    {
325
326        $requestedPath = ExecutionContext::getActualOrCreateFromEnv()->getRequestedPath();
327
328        if (!FileSystems::exists($requestedPath)) {
329            return;
330        }
331
332        $page = MarkupPath::createPageFromPathObject($requestedPath);
333
334        /**
335         * No management for slot page
336         */
337        if ($page->isSlot()) {
338            return;
339        }
340
341        $protected = false;
342        $follow = "nofollow";
343        if ($page->isLowQualityPage() && LowQualityPage::isProtectionEnabled()) {
344            $protected = true;
345            if (LowQualityPage::getLowQualityProtectionMode() == PageProtection::CONF_VALUE_ACL) {
346                $follow = "nofollow";
347            } else {
348                $follow = "follow";
349            }
350        }
351        if ($page->isLatePublication() && PagePublicationDate::isLatePublicationProtectionEnabled()) {
352            $protected = true;
353            if (PagePublicationDate::getLatePublicationProtectionMode() == PageProtection::CONF_VALUE_ACL) {
354                $follow = "nofollow";
355            } else {
356                $follow = "follow";
357            }
358        }
359        if ($protected) {
360            foreach ($event->data['meta'] as $key => $meta) {
361                if (array_key_exists("name", $meta)) {
362                    /**
363                     * We may have several properties
364                     */
365                    if ($meta["name"] == "robots") {
366                        $event->data['meta'][$key]["content"] = "noindex,$follow";
367                    }
368                }
369            }
370        }
371    }
372
373}
374