xref: /plugin/combo/action/pageprotection.php (revision f9161b9db4419ab2bfdc8f5da41b5289ebbfb3af)
15f891b7eSNickeau<?php
25f891b7eSNickeau
35b0932efSgerardnicorequire_once(__DIR__ . '/../vendor/autoload.php');
45f891b7eSNickeau
565e00826Sgerardnicouse ComboStrap\ExceptionBadArgument;
665e00826Sgerardnicouse ComboStrap\ExceptionBadSyntax;
75b0932efSgerardnicouse ComboStrap\ExceptionNotEnabled;
804fd306cSNickeauuse ComboStrap\ExecutionContext;
965e00826Sgerardnicouse ComboStrap\FetcherPage;
1004fd306cSNickeauuse ComboStrap\FileSystems;
11c3437056SNickeauuse ComboStrap\Identity;
125b0932efSgerardnicouse ComboStrap\LogUtility;
135f891b7eSNickeauuse ComboStrap\LowQualityPage;
1404fd306cSNickeauuse ComboStrap\MarkupPath;
155f891b7eSNickeauuse ComboStrap\PageProtection;
16c3437056SNickeauuse ComboStrap\PagePublicationDate;
175b0932efSgerardnicouse ComboStrap\Robots;
185b0932efSgerardnicouse ComboStrap\Web\Url;
195b0932efSgerardnicouse ComboStrap\WikiPath;
205f891b7eSNickeau
21c3437056SNickeau
225f891b7eSNickeau/**
235f891b7eSNickeau *
245f891b7eSNickeau */
255f891b7eSNickeauclass action_plugin_combo_pageprotection extends DokuWiki_Action_Plugin
265f891b7eSNickeau{
275f891b7eSNickeau
285f891b7eSNickeau
295f891b7eSNickeau    public function register(Doku_Event_Handler $controller)
305f891b7eSNickeau    {
315f891b7eSNickeau
325f891b7eSNickeau
335f891b7eSNickeau        /**
345f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:pageutils_id_hidepage
355f891b7eSNickeau         */
365f891b7eSNickeau        $controller->register_hook('PAGEUTILS_ID_HIDEPAGE', 'BEFORE', $this, 'handleHiddenCheck', array());
3785e82846SNickeau
385f891b7eSNickeau        /**
395f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:auth_acl_check
405f891b7eSNickeau         */
415f891b7eSNickeau        $controller->register_hook('AUTH_ACL_CHECK', 'AFTER', $this, 'handleAclCheck', array());
4285e82846SNickeau
4385e82846SNickeau        /**
4485e82846SNickeau         * https://www.dokuwiki.org/devel:event:sitemap_generate
4585e82846SNickeau         */
4685e82846SNickeau        $controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handleSiteMapGenerate', array());
475f891b7eSNickeau
485f891b7eSNickeau        /**
495f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:search_query_pagelookup
505f891b7eSNickeau         */
515f891b7eSNickeau        $controller->register_hook('SEARCH_QUERY_PAGELOOKUP', 'AFTER', $this, 'handleSearchPageLookup', array());
525f891b7eSNickeau
535f891b7eSNickeau        /**
545f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:search_query_fullpage
555f891b7eSNickeau         */
565f891b7eSNickeau        $controller->register_hook('SEARCH_QUERY_FULLPAGE', 'AFTER', $this, 'handleSearchFullPage', array());
5785e82846SNickeau
585f891b7eSNickeau        /**
595f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:feed_data_process
605f891b7eSNickeau         */
6185e82846SNickeau        $controller->register_hook('FEED_DATA_PROCESS', 'BEFORE', $this, 'handleRssFeed', array());
625f891b7eSNickeau
635f891b7eSNickeau
6485e82846SNickeau        /**
6585e82846SNickeau         * Robots meta
6685e82846SNickeau         * https://www.dokuwiki.org/devel:event:tpl_metaheader_output
6785e82846SNickeau         */
6885e82846SNickeau        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleRobotsMeta', array());
6985e82846SNickeau
705f891b7eSNickeau
715f891b7eSNickeau    }
725f891b7eSNickeau
735f891b7eSNickeau    /**
7485e82846SNickeau     * Set page has hidden
755f891b7eSNickeau     * @param $event
765f891b7eSNickeau     * @param $param
775f891b7eSNickeau     */
785f891b7eSNickeau    function handleHiddenCheck(&$event, $param)
795f891b7eSNickeau    {
805f891b7eSNickeau
8185e82846SNickeau        /**
8285e82846SNickeau         * Only for public
8385e82846SNickeau         */
8485e82846SNickeau        if (Identity::isLoggedIn()) {
8585e82846SNickeau            return;
8685e82846SNickeau        }
875f891b7eSNickeau
8885e82846SNickeau        $id = $event->data['id'];
8985e82846SNickeau        if ($id == null) {
9085e82846SNickeau            /**
9185e82846SNickeau             * Happens in test when rendering
9285e82846SNickeau             * with instructions only
9385e82846SNickeau             */
9485e82846SNickeau            return;
9585e82846SNickeau        }
9604fd306cSNickeau        $page = MarkupPath::createMarkupFromId($id);
9785e82846SNickeau
9885e82846SNickeau        if ($page->isLowQualityPage()) {
9985e82846SNickeau            if (LowQualityPage::getLowQualityProtectionMode() == PageProtection::CONF_VALUE_HIDDEN) {
10085e82846SNickeau                $event->data['hidden'] = true;
10185e82846SNickeau                return;
10285e82846SNickeau            }
10385e82846SNickeau        }
10485e82846SNickeau        if ($page->isLatePublication()) {
105c3437056SNickeau            if (PagePublicationDate::getLatePublicationProtectionMode() == PageProtection::CONF_VALUE_HIDDEN) {
1065f891b7eSNickeau                $event->data['hidden'] = true;
1075f891b7eSNickeau            }
1085f891b7eSNickeau
1095f891b7eSNickeau        }
1105f891b7eSNickeau
11185e82846SNickeau    }
11285e82846SNickeau
1135f891b7eSNickeau    /**
11485e82846SNickeau     *
11585e82846SNickeau     * https://www.dokuwiki.org/devel:event:auth_acl_check
1165f891b7eSNickeau     * @param $event
1175f891b7eSNickeau     * @param $param
1185f891b7eSNickeau     */
1195f891b7eSNickeau    function handleAclCheck(&$event, $param)
1205f891b7eSNickeau    {
12185e82846SNickeau        /**
12285e82846SNickeau         * Only for public
12385e82846SNickeau         *
12485e82846SNickeau         * Note: user is also
12585e82846SNickeau         * to be found at
12685e82846SNickeau         * $user = $event->data['user'];
12785e82846SNickeau         */
12885e82846SNickeau        if (Identity::isLoggedIn()) {
12985e82846SNickeau            return;
13085e82846SNickeau        }
1315f891b7eSNickeau
13232b85071SNickeau        /**
13321913ab3SNickeau         * Are we on a page script
13432b85071SNickeau         */
13521913ab3SNickeau        $imageScript = ["/lib/exe/mediamanager.php", "/lib/exe/detail.php"];
13621913ab3SNickeau        if (in_array($_SERVER['SCRIPT_NAME'], $imageScript)) {
13721913ab3SNickeau            // id may be null or end with a star
13821913ab3SNickeau            // this is not a image
1395f891b7eSNickeau            return;
14021913ab3SNickeau        }
14132b85071SNickeau
14221913ab3SNickeau        $id = $event->data['id'];
14304fd306cSNickeau        if ($id == null) {
14404fd306cSNickeau            /**
14504fd306cSNickeau             * Happens in test when rendering
14604fd306cSNickeau             * with instructions only
14704fd306cSNickeau             */
14804fd306cSNickeau            return;
14904fd306cSNickeau        }
15032b85071SNickeau
15104fd306cSNickeau        $dokuPath = WikiPath::createFromUnknownRoot($id);
15221913ab3SNickeau        if ($dokuPath->isPage()) {
15385e82846SNickeau
15421913ab3SNickeau            /**
15521913ab3SNickeau             * It should be only a page
15621913ab3SNickeau             * https://www.dokuwiki.org/devel:event:auth_acl_check
15721913ab3SNickeau             */
15804fd306cSNickeau            $page = MarkupPath::createMarkupFromId($id);
15985e82846SNickeau
16085e82846SNickeau            if ($page->isLowQualityPage()) {
16185e82846SNickeau                if ($this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_ENABLE, true)) {
16285e82846SNickeau                    $securityConf = $this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_MODE, PageProtection::CONF_VALUE_ACL);
16385e82846SNickeau                    if ($securityConf == PageProtection::CONF_VALUE_ACL) {
1645f891b7eSNickeau                        $event->result = AUTH_NONE;
16585e82846SNickeau                        return;
16685e82846SNickeau                    }
16785e82846SNickeau                }
16885e82846SNickeau            }
16985e82846SNickeau            if ($page->isLatePublication()) {
170c3437056SNickeau                if ($this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_ENABLE, true)) {
171c3437056SNickeau                    $securityConf = $this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_MODE, PageProtection::CONF_VALUE_ACL);
17285e82846SNickeau                    if ($securityConf == PageProtection::CONF_VALUE_ACL) {
17385e82846SNickeau                        $event->result = AUTH_NONE;
17485e82846SNickeau                        return;
17585e82846SNickeau                    }
17685e82846SNickeau                }
17785e82846SNickeau            }
17885e82846SNickeau
17985e82846SNickeau        }
18085e82846SNickeau
18185e82846SNickeau    }
18285e82846SNickeau
18385e82846SNickeau    function handleSiteMapGenerate(&$event, $param)
18485e82846SNickeau    {
18585e82846SNickeau        $pageItems = $event->data["items"];
18685e82846SNickeau        foreach ($pageItems as $key => $pageItem) {
18765e00826Sgerardnico
18865e00826Sgerardnico            try {
18965e00826Sgerardnico                $url = Url::createFromString($pageItem->url);
19065e00826Sgerardnico                $fetcherPage = FetcherPage::createPageFragmentFetcherFromUrl($url);
19165e00826Sgerardnico            } catch (ExceptionBadArgument|ExceptionBadSyntax  $e) {
19265e00826Sgerardnico                LogUtility::internalError("We were unable to build the page fetcher. Error: " . $e->getMessage(), "sitemap", $e);
19365e00826Sgerardnico                continue;
19465e00826Sgerardnico            }
19565e00826Sgerardnico
19665e00826Sgerardnico            $page = MarkupPath::createPageFromPathObject($fetcherPage->getSourcePath());
19785e82846SNickeau            if ($page->isLowQualityPage() && LowQualityPage::isProtectionEnabled()) {
19885e82846SNickeau
19985e82846SNickeau                unset($event->data["items"][$key]);
20085e82846SNickeau                continue;
20185e82846SNickeau
20285e82846SNickeau            }
203c3437056SNickeau            if ($page->isLatePublication() && PagePublicationDate::isLatePublicationProtectionEnabled()) {
20485e82846SNickeau                unset($event->data["items"][$key]);
2055f891b7eSNickeau            }
20665e00826Sgerardnico            /**
20765e00826Sgerardnico             * Url rewrite
20865e00826Sgerardnico             */
209*f9161b9dSNico            $urlAfterRewrite = $page->getCanonicalUrl()->toAbsoluteUrlString();
21065e00826Sgerardnico            $event->data["items"][$key]->url = $urlAfterRewrite;
2115f891b7eSNickeau        }
2125f891b7eSNickeau
2135f891b7eSNickeau    }
2145f891b7eSNickeau
2155f891b7eSNickeau    /**
2165f891b7eSNickeau     * @param $event
2175f891b7eSNickeau     * @param $param
2185f891b7eSNickeau     * The autocomplete do a search on page name
2195f891b7eSNickeau     */
2205f891b7eSNickeau    function handleSearchPageLookup(&$event, $param)
2215f891b7eSNickeau    {
2225f891b7eSNickeau        $this->excludePageFromSearch($event);
2235f891b7eSNickeau    }
2245f891b7eSNickeau
2255f891b7eSNickeau    /**
2265f891b7eSNickeau     * @param $event
2275f891b7eSNickeau     * @param $param
2285f891b7eSNickeau     * The search page do a search on page name
2295f891b7eSNickeau     */
2305f891b7eSNickeau    function handleSearchFullPage(&$event, $param)
2315f891b7eSNickeau    {
2325f891b7eSNickeau
2335f891b7eSNickeau        $this->excludePageFromSearch($event);
2345f891b7eSNickeau    }
2355f891b7eSNickeau
2365f891b7eSNickeau    /**
2375f891b7eSNickeau     *
2385f891b7eSNickeau     * @param $event
2395f891b7eSNickeau     * @param $param
2405f891b7eSNickeau     * The Rss
2415f891b7eSNickeau     * https://www.dokuwiki.org/syndication
2425f891b7eSNickeau     * Example
2435f891b7eSNickeau     * https://example.com/feed.php?type=rss2&num=5
2445f891b7eSNickeau     */
2455f891b7eSNickeau    function handleRssFeed(&$event, $param)
2465f891b7eSNickeau    {
24785e82846SNickeau        $isLowQualityProtectionEnabled = LowQualityPage::isProtectionEnabled();
248c3437056SNickeau        $isLatePublicationProtectionEnabled = PagePublicationDate::isLatePublicationProtectionEnabled();
24985e82846SNickeau        if (!$isLatePublicationProtectionEnabled && !$isLowQualityProtectionEnabled) {
25085e82846SNickeau            return;
25185e82846SNickeau        }
25285e82846SNickeau
25385e82846SNickeau        $pagesToBeAdded = &$event->data["data"];
25485e82846SNickeau        foreach ($pagesToBeAdded as $key => $data) {
25585e82846SNickeau
256e8b2ff59SNickeau            // To prevent an Illegal string offset 'id'
257e8b2ff59SNickeau            if (isset($data["id"])) {
258e8b2ff59SNickeau
25904fd306cSNickeau                $page = MarkupPath::createMarkupFromId($data["id"]);
26085e82846SNickeau
26185e82846SNickeau                if ($page->isLowQualityPage() && $isLowQualityProtectionEnabled) {
26285e82846SNickeau                    $protectionMode = LowQualityPage::getLowQualityProtectionMode();
26385e82846SNickeau                    if ($protectionMode != PageProtection::CONF_VALUE_ROBOT) {
26485e82846SNickeau                        unset($pagesToBeAdded[$key]);
26585e82846SNickeau                    }
26685e82846SNickeau                }
26785e82846SNickeau
26885e82846SNickeau                if ($page->isLatePublication() && $isLatePublicationProtectionEnabled) {
269c3437056SNickeau                    $protectionMode = PagePublicationDate::getLatePublicationProtectionMode();
27085e82846SNickeau                    if ($protectionMode != PageProtection::CONF_VALUE_ROBOT) {
27185e82846SNickeau                        unset($pagesToBeAdded[$key]);
27285e82846SNickeau                    }
27385e82846SNickeau                }
274e8b2ff59SNickeau
275e8b2ff59SNickeau            }
27685e82846SNickeau        }
27785e82846SNickeau
2785f891b7eSNickeau    }
2795f891b7eSNickeau
2805f891b7eSNickeau    /**
2815f891b7eSNickeau     * @param $event
28285e82846SNickeau     * @param array $protectionModes
2835f891b7eSNickeau     */
2845f891b7eSNickeau    private
28585e82846SNickeau    function excludePageFromSearch(&$event, $protectionModes = [PageProtection::CONF_VALUE_ACL, PageProtection::CONF_VALUE_HIDDEN])
2865f891b7eSNickeau    {
2875f891b7eSNickeau
2885f891b7eSNickeau        /**
2895f891b7eSNickeau         * The value is always an array
2905f891b7eSNickeau         * but as we got this error:
2915f891b7eSNickeau         * ```
2925f891b7eSNickeau         * array_keys() expects parameter 1 to be array
2935f891b7eSNickeau         * ```
294e8b2ff59SNickeau         * The result is a list of page id
2955f891b7eSNickeau         */
296e8b2ff59SNickeau        if (is_array($event->result)) {
297e8b2ff59SNickeau            foreach (array_keys($event->result) as $idx) {
29804fd306cSNickeau                $page = MarkupPath::createMarkupFromId($idx);
29985e82846SNickeau                if ($page->isLowQualityPage()) {
30085e82846SNickeau                    $securityConf = $this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_MODE);
30185e82846SNickeau                    if (in_array($securityConf, $protectionModes)) {
302e8b2ff59SNickeau                        unset($event->result[$idx]);
30385e82846SNickeau                        return;
30485e82846SNickeau                    }
30585e82846SNickeau                }
30685e82846SNickeau                if ($page->isLatePublication()) {
307c3437056SNickeau                    $securityConf = $this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_MODE);
30885e82846SNickeau                    if (in_array($securityConf, [PageProtection::CONF_VALUE_ACL, PageProtection::CONF_VALUE_HIDDEN])) {
309e8b2ff59SNickeau                        unset($event->result[$idx]);
31085e82846SNickeau                        return;
31185e82846SNickeau                    }
3125f891b7eSNickeau                }
3135f891b7eSNickeau            }
3145f891b7eSNickeau        }
3155f891b7eSNickeau
3165f891b7eSNickeau    }
3175f891b7eSNickeau
3185f891b7eSNickeau
31985e82846SNickeau    /**
32085e82846SNickeau     * Handle the meta robots
32185e82846SNickeau     * https://www.dokuwiki.org/devel:event:tpl_metaheader_output
32285e82846SNickeau     * @param $event
32385e82846SNickeau     * @param $param
32485e82846SNickeau     */
32585e82846SNickeau    function handleRobotsMeta(&$event, $param)
32685e82846SNickeau    {
32785e82846SNickeau
3285b0932efSgerardnico        $executionContext = ExecutionContext::getActualOrCreateFromEnv();
3295b0932efSgerardnico        $requestedPath = $executionContext->getRequestedPath();
33004fd306cSNickeau
33104fd306cSNickeau        if (!FileSystems::exists($requestedPath)) {
33285e82846SNickeau            return;
33385e82846SNickeau        }
33485e82846SNickeau
33504fd306cSNickeau        $page = MarkupPath::createPageFromPathObject($requestedPath);
3365b0932efSgerardnico        try {
3375b0932efSgerardnico            $follow = Robots::canBeIndexedAndGetFollowValue($page, $executionContext);
3385b0932efSgerardnico        } catch (ExceptionNotEnabled $e) {
3395b0932efSgerardnico            // Robots Protection is not Enabled
34085e82846SNickeau            return;
34185e82846SNickeau        }
34285e82846SNickeau
343cc610584Sgerardnico        // header ['X-Robots-Tag'] = 'noindex'; ???
344cc610584Sgerardnico
34585e82846SNickeau        foreach ($event->data['meta'] as $key => $meta) {
34685e82846SNickeau            if (array_key_exists("name", $meta)) {
34785e82846SNickeau                /**
34885e82846SNickeau                 * We may have several properties
34985e82846SNickeau                 */
35085e82846SNickeau                if ($meta["name"] == "robots") {
35185e82846SNickeau                    $event->data['meta'][$key]["content"] = "noindex,$follow";
35285e82846SNickeau                }
35385e82846SNickeau            }
35485e82846SNickeau        }
3555b0932efSgerardnico
35685e82846SNickeau    }
35785e82846SNickeau
3585f891b7eSNickeau}
359