xref: /plugin/combo/action/pageprotection.php (revision 65e00826e4eceefc13be6f404ba5dcc7c44f243c)
15f891b7eSNickeau<?php
25f891b7eSNickeau
3c3437056SNickeaurequire_once(__DIR__ . '/../ComboStrap/PluginUtility.php');
45f891b7eSNickeau
5*65e00826Sgerardnicouse ComboStrap\ExceptionBadArgument;
6*65e00826Sgerardnicouse ComboStrap\ExceptionBadSyntax;
704fd306cSNickeauuse ComboStrap\ExecutionContext;
8*65e00826Sgerardnicouse ComboStrap\FetcherPage;
904fd306cSNickeauuse ComboStrap\FileSystems;
10*65e00826Sgerardnicouse ComboStrap\LogUtility;
11*65e00826Sgerardnicouse ComboStrap\Web\Url;
1204fd306cSNickeauuse ComboStrap\WikiPath;
13c3437056SNickeauuse ComboStrap\Identity;
145f891b7eSNickeauuse ComboStrap\LowQualityPage;
1504fd306cSNickeauuse ComboStrap\MarkupPath;
165f891b7eSNickeauuse ComboStrap\PageProtection;
17c3437056SNickeauuse ComboStrap\PagePublicationDate;
185f891b7eSNickeau
19c3437056SNickeau
205f891b7eSNickeau/**
215f891b7eSNickeau *
225f891b7eSNickeau */
235f891b7eSNickeauclass action_plugin_combo_pageprotection extends DokuWiki_Action_Plugin
245f891b7eSNickeau{
255f891b7eSNickeau
265f891b7eSNickeau
275f891b7eSNickeau    public function register(Doku_Event_Handler $controller)
285f891b7eSNickeau    {
295f891b7eSNickeau
305f891b7eSNickeau
315f891b7eSNickeau        /**
325f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:pageutils_id_hidepage
335f891b7eSNickeau         */
345f891b7eSNickeau        $controller->register_hook('PAGEUTILS_ID_HIDEPAGE', 'BEFORE', $this, 'handleHiddenCheck', array());
3585e82846SNickeau
365f891b7eSNickeau        /**
375f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:auth_acl_check
385f891b7eSNickeau         */
395f891b7eSNickeau        $controller->register_hook('AUTH_ACL_CHECK', 'AFTER', $this, 'handleAclCheck', array());
4085e82846SNickeau
4185e82846SNickeau        /**
4285e82846SNickeau         * https://www.dokuwiki.org/devel:event:sitemap_generate
4385e82846SNickeau         */
4485e82846SNickeau        $controller->register_hook('SITEMAP_GENERATE', 'BEFORE', $this, 'handleSiteMapGenerate', array());
455f891b7eSNickeau
465f891b7eSNickeau        /**
475f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:search_query_pagelookup
485f891b7eSNickeau         */
495f891b7eSNickeau        $controller->register_hook('SEARCH_QUERY_PAGELOOKUP', 'AFTER', $this, 'handleSearchPageLookup', array());
505f891b7eSNickeau
515f891b7eSNickeau        /**
525f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:search_query_fullpage
535f891b7eSNickeau         */
545f891b7eSNickeau        $controller->register_hook('SEARCH_QUERY_FULLPAGE', 'AFTER', $this, 'handleSearchFullPage', array());
5585e82846SNickeau
565f891b7eSNickeau        /**
575f891b7eSNickeau         * https://www.dokuwiki.org/devel:event:feed_data_process
585f891b7eSNickeau         */
5985e82846SNickeau        $controller->register_hook('FEED_DATA_PROCESS', 'BEFORE', $this, 'handleRssFeed', array());
605f891b7eSNickeau
615f891b7eSNickeau
6285e82846SNickeau        /**
6385e82846SNickeau         * Robots meta
6485e82846SNickeau         * https://www.dokuwiki.org/devel:event:tpl_metaheader_output
6585e82846SNickeau         */
6685e82846SNickeau        $controller->register_hook('TPL_METAHEADER_OUTPUT', 'BEFORE', $this, 'handleRobotsMeta', array());
6785e82846SNickeau
685f891b7eSNickeau
695f891b7eSNickeau    }
705f891b7eSNickeau
715f891b7eSNickeau    /**
7285e82846SNickeau     * Set page has hidden
735f891b7eSNickeau     * @param $event
745f891b7eSNickeau     * @param $param
755f891b7eSNickeau     */
765f891b7eSNickeau    function handleHiddenCheck(&$event, $param)
775f891b7eSNickeau    {
785f891b7eSNickeau
7985e82846SNickeau        /**
8085e82846SNickeau         * Only for public
8185e82846SNickeau         */
8285e82846SNickeau        if (Identity::isLoggedIn()) {
8385e82846SNickeau            return;
8485e82846SNickeau        }
855f891b7eSNickeau
8685e82846SNickeau        $id = $event->data['id'];
8785e82846SNickeau        if ($id == null) {
8885e82846SNickeau            /**
8985e82846SNickeau             * Happens in test when rendering
9085e82846SNickeau             * with instructions only
9185e82846SNickeau             */
9285e82846SNickeau            return;
9385e82846SNickeau        }
9404fd306cSNickeau        $page = MarkupPath::createMarkupFromId($id);
9585e82846SNickeau
9685e82846SNickeau        if ($page->isLowQualityPage()) {
9785e82846SNickeau            if (LowQualityPage::getLowQualityProtectionMode() == PageProtection::CONF_VALUE_HIDDEN) {
9885e82846SNickeau                $event->data['hidden'] = true;
9985e82846SNickeau                return;
10085e82846SNickeau            }
10185e82846SNickeau        }
10285e82846SNickeau        if ($page->isLatePublication()) {
103c3437056SNickeau            if (PagePublicationDate::getLatePublicationProtectionMode() == PageProtection::CONF_VALUE_HIDDEN) {
1045f891b7eSNickeau                $event->data['hidden'] = true;
1055f891b7eSNickeau            }
1065f891b7eSNickeau
1075f891b7eSNickeau        }
1085f891b7eSNickeau
10985e82846SNickeau    }
11085e82846SNickeau
1115f891b7eSNickeau    /**
11285e82846SNickeau     *
11385e82846SNickeau     * https://www.dokuwiki.org/devel:event:auth_acl_check
1145f891b7eSNickeau     * @param $event
1155f891b7eSNickeau     * @param $param
1165f891b7eSNickeau     */
1175f891b7eSNickeau    function handleAclCheck(&$event, $param)
1185f891b7eSNickeau    {
11985e82846SNickeau        /**
12085e82846SNickeau         * Only for public
12185e82846SNickeau         *
12285e82846SNickeau         * Note: user is also
12385e82846SNickeau         * to be found at
12485e82846SNickeau         * $user = $event->data['user'];
12585e82846SNickeau         */
12685e82846SNickeau        if (Identity::isLoggedIn()) {
12785e82846SNickeau            return;
12885e82846SNickeau        }
1295f891b7eSNickeau
13032b85071SNickeau        /**
13121913ab3SNickeau         * Are we on a page script
13232b85071SNickeau         */
13321913ab3SNickeau        $imageScript = ["/lib/exe/mediamanager.php", "/lib/exe/detail.php"];
13421913ab3SNickeau        if (in_array($_SERVER['SCRIPT_NAME'], $imageScript)) {
13521913ab3SNickeau            // id may be null or end with a star
13621913ab3SNickeau            // this is not a image
1375f891b7eSNickeau            return;
13821913ab3SNickeau        }
13932b85071SNickeau
14021913ab3SNickeau        $id = $event->data['id'];
14104fd306cSNickeau        if ($id == null) {
14204fd306cSNickeau            /**
14304fd306cSNickeau             * Happens in test when rendering
14404fd306cSNickeau             * with instructions only
14504fd306cSNickeau             */
14604fd306cSNickeau            return;
14704fd306cSNickeau        }
14832b85071SNickeau
14904fd306cSNickeau        $dokuPath = WikiPath::createFromUnknownRoot($id);
15021913ab3SNickeau        if ($dokuPath->isPage()) {
15185e82846SNickeau
15221913ab3SNickeau            /**
15321913ab3SNickeau             * It should be only a page
15421913ab3SNickeau             * https://www.dokuwiki.org/devel:event:auth_acl_check
15521913ab3SNickeau             */
15604fd306cSNickeau            $page = MarkupPath::createMarkupFromId($id);
15785e82846SNickeau
15885e82846SNickeau            if ($page->isLowQualityPage()) {
15985e82846SNickeau                if ($this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_ENABLE, true)) {
16085e82846SNickeau                    $securityConf = $this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_MODE, PageProtection::CONF_VALUE_ACL);
16185e82846SNickeau                    if ($securityConf == PageProtection::CONF_VALUE_ACL) {
1625f891b7eSNickeau                        $event->result = AUTH_NONE;
16385e82846SNickeau                        return;
16485e82846SNickeau                    }
16585e82846SNickeau                }
16685e82846SNickeau            }
16785e82846SNickeau            if ($page->isLatePublication()) {
168c3437056SNickeau                if ($this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_ENABLE, true)) {
169c3437056SNickeau                    $securityConf = $this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_MODE, PageProtection::CONF_VALUE_ACL);
17085e82846SNickeau                    if ($securityConf == PageProtection::CONF_VALUE_ACL) {
17185e82846SNickeau                        $event->result = AUTH_NONE;
17285e82846SNickeau                        return;
17385e82846SNickeau                    }
17485e82846SNickeau                }
17585e82846SNickeau            }
17685e82846SNickeau
17785e82846SNickeau        }
17885e82846SNickeau
17985e82846SNickeau    }
18085e82846SNickeau
18185e82846SNickeau    function handleSiteMapGenerate(&$event, $param)
18285e82846SNickeau    {
18385e82846SNickeau        $pageItems = $event->data["items"];
18485e82846SNickeau        foreach ($pageItems as $key => $pageItem) {
185*65e00826Sgerardnico
186*65e00826Sgerardnico            try {
187*65e00826Sgerardnico                $url = Url::createFromString($pageItem->url);
188*65e00826Sgerardnico                $fetcherPage = FetcherPage::createPageFragmentFetcherFromUrl($url);
189*65e00826Sgerardnico            } catch (ExceptionBadArgument|ExceptionBadSyntax  $e) {
190*65e00826Sgerardnico                LogUtility::internalError("We were unable to build the page fetcher. Error: " . $e->getMessage(), "sitemap", $e);
191*65e00826Sgerardnico                continue;
192*65e00826Sgerardnico            }
193*65e00826Sgerardnico
194*65e00826Sgerardnico            $page = MarkupPath::createPageFromPathObject($fetcherPage->getSourcePath());
19585e82846SNickeau            if ($page->isLowQualityPage() && LowQualityPage::isProtectionEnabled()) {
19685e82846SNickeau
19785e82846SNickeau                unset($event->data["items"][$key]);
19885e82846SNickeau                continue;
19985e82846SNickeau
20085e82846SNickeau            }
201c3437056SNickeau            if ($page->isLatePublication() && PagePublicationDate::isLatePublicationProtectionEnabled()) {
20285e82846SNickeau                unset($event->data["items"][$key]);
2035f891b7eSNickeau            }
204*65e00826Sgerardnico            /**
205*65e00826Sgerardnico             * Url rewrite
206*65e00826Sgerardnico             */
207*65e00826Sgerardnico            $urlAfterRewrite = $page->getCanonicalUrl()->toString();
208*65e00826Sgerardnico            $event->data["items"][$key]->url = $urlAfterRewrite;
2095f891b7eSNickeau        }
2105f891b7eSNickeau
2115f891b7eSNickeau    }
2125f891b7eSNickeau
2135f891b7eSNickeau    /**
2145f891b7eSNickeau     * @param $event
2155f891b7eSNickeau     * @param $param
2165f891b7eSNickeau     * The autocomplete do a search on page name
2175f891b7eSNickeau     */
2185f891b7eSNickeau    function handleSearchPageLookup(&$event, $param)
2195f891b7eSNickeau    {
2205f891b7eSNickeau        $this->excludePageFromSearch($event);
2215f891b7eSNickeau    }
2225f891b7eSNickeau
2235f891b7eSNickeau    /**
2245f891b7eSNickeau     * @param $event
2255f891b7eSNickeau     * @param $param
2265f891b7eSNickeau     * The search page do a search on page name
2275f891b7eSNickeau     */
2285f891b7eSNickeau    function handleSearchFullPage(&$event, $param)
2295f891b7eSNickeau    {
2305f891b7eSNickeau
2315f891b7eSNickeau        $this->excludePageFromSearch($event);
2325f891b7eSNickeau    }
2335f891b7eSNickeau
2345f891b7eSNickeau    /**
2355f891b7eSNickeau     *
2365f891b7eSNickeau     * @param $event
2375f891b7eSNickeau     * @param $param
2385f891b7eSNickeau     * The Rss
2395f891b7eSNickeau     * https://www.dokuwiki.org/syndication
2405f891b7eSNickeau     * Example
2415f891b7eSNickeau     * https://example.com/feed.php?type=rss2&num=5
2425f891b7eSNickeau     */
2435f891b7eSNickeau    function handleRssFeed(&$event, $param)
2445f891b7eSNickeau    {
24585e82846SNickeau        $isLowQualityProtectionEnabled = LowQualityPage::isProtectionEnabled();
246c3437056SNickeau        $isLatePublicationProtectionEnabled = PagePublicationDate::isLatePublicationProtectionEnabled();
24785e82846SNickeau        if (!$isLatePublicationProtectionEnabled && !$isLowQualityProtectionEnabled) {
24885e82846SNickeau            return;
24985e82846SNickeau        }
25085e82846SNickeau
25185e82846SNickeau        $pagesToBeAdded = &$event->data["data"];
25285e82846SNickeau        foreach ($pagesToBeAdded as $key => $data) {
25385e82846SNickeau
254e8b2ff59SNickeau            // To prevent an Illegal string offset 'id'
255e8b2ff59SNickeau            if (isset($data["id"])) {
256e8b2ff59SNickeau
25704fd306cSNickeau                $page = MarkupPath::createMarkupFromId($data["id"]);
25885e82846SNickeau
25985e82846SNickeau                if ($page->isLowQualityPage() && $isLowQualityProtectionEnabled) {
26085e82846SNickeau                    $protectionMode = LowQualityPage::getLowQualityProtectionMode();
26185e82846SNickeau                    if ($protectionMode != PageProtection::CONF_VALUE_ROBOT) {
26285e82846SNickeau                        unset($pagesToBeAdded[$key]);
26385e82846SNickeau                    }
26485e82846SNickeau                }
26585e82846SNickeau
26685e82846SNickeau                if ($page->isLatePublication() && $isLatePublicationProtectionEnabled) {
267c3437056SNickeau                    $protectionMode = PagePublicationDate::getLatePublicationProtectionMode();
26885e82846SNickeau                    if ($protectionMode != PageProtection::CONF_VALUE_ROBOT) {
26985e82846SNickeau                        unset($pagesToBeAdded[$key]);
27085e82846SNickeau                    }
27185e82846SNickeau                }
272e8b2ff59SNickeau
273e8b2ff59SNickeau            }
27485e82846SNickeau        }
27585e82846SNickeau
2765f891b7eSNickeau    }
2775f891b7eSNickeau
2785f891b7eSNickeau    /**
2795f891b7eSNickeau     * @param $event
28085e82846SNickeau     * @param array $protectionModes
2815f891b7eSNickeau     */
2825f891b7eSNickeau    private
28385e82846SNickeau    function excludePageFromSearch(&$event, $protectionModes = [PageProtection::CONF_VALUE_ACL, PageProtection::CONF_VALUE_HIDDEN])
2845f891b7eSNickeau    {
2855f891b7eSNickeau
2865f891b7eSNickeau        /**
2875f891b7eSNickeau         * The value is always an array
2885f891b7eSNickeau         * but as we got this error:
2895f891b7eSNickeau         * ```
2905f891b7eSNickeau         * array_keys() expects parameter 1 to be array
2915f891b7eSNickeau         * ```
292e8b2ff59SNickeau         * The result is a list of page id
2935f891b7eSNickeau         */
294e8b2ff59SNickeau        if (is_array($event->result)) {
295e8b2ff59SNickeau            foreach (array_keys($event->result) as $idx) {
29604fd306cSNickeau                $page = MarkupPath::createMarkupFromId($idx);
29785e82846SNickeau                if ($page->isLowQualityPage()) {
29885e82846SNickeau                    $securityConf = $this->getConf(LowQualityPage::CONF_LOW_QUALITY_PAGE_PROTECTION_MODE);
29985e82846SNickeau                    if (in_array($securityConf, $protectionModes)) {
300e8b2ff59SNickeau                        unset($event->result[$idx]);
30185e82846SNickeau                        return;
30285e82846SNickeau                    }
30385e82846SNickeau                }
30485e82846SNickeau                if ($page->isLatePublication()) {
305c3437056SNickeau                    $securityConf = $this->getConf(PagePublicationDate::CONF_LATE_PUBLICATION_PROTECTION_MODE);
30685e82846SNickeau                    if (in_array($securityConf, [PageProtection::CONF_VALUE_ACL, PageProtection::CONF_VALUE_HIDDEN])) {
307e8b2ff59SNickeau                        unset($event->result[$idx]);
30885e82846SNickeau                        return;
30985e82846SNickeau                    }
3105f891b7eSNickeau                }
3115f891b7eSNickeau            }
3125f891b7eSNickeau        }
3135f891b7eSNickeau
3145f891b7eSNickeau    }
3155f891b7eSNickeau
3165f891b7eSNickeau
31785e82846SNickeau    /**
31885e82846SNickeau     * Handle the meta robots
31985e82846SNickeau     * https://www.dokuwiki.org/devel:event:tpl_metaheader_output
32085e82846SNickeau     * @param $event
32185e82846SNickeau     * @param $param
32285e82846SNickeau     */
32385e82846SNickeau    function handleRobotsMeta(&$event, $param)
32485e82846SNickeau    {
32585e82846SNickeau
32604fd306cSNickeau        $requestedPath = ExecutionContext::getActualOrCreateFromEnv()->getRequestedPath();
32704fd306cSNickeau
32804fd306cSNickeau        if (!FileSystems::exists($requestedPath)) {
32985e82846SNickeau            return;
33085e82846SNickeau        }
33185e82846SNickeau
33204fd306cSNickeau        $page = MarkupPath::createPageFromPathObject($requestedPath);
33385e82846SNickeau
33485e82846SNickeau        /**
33585e82846SNickeau         * No management for slot page
33685e82846SNickeau         */
33704fd306cSNickeau        if ($page->isSlot()) {
33885e82846SNickeau            return;
33985e82846SNickeau        }
34085e82846SNickeau
34185e82846SNickeau        $protected = false;
34285e82846SNickeau        $follow = "nofollow";
34385e82846SNickeau        if ($page->isLowQualityPage() && LowQualityPage::isProtectionEnabled()) {
34485e82846SNickeau            $protected = true;
34585e82846SNickeau            if (LowQualityPage::getLowQualityProtectionMode() == PageProtection::CONF_VALUE_ACL) {
34685e82846SNickeau                $follow = "nofollow";
34785e82846SNickeau            } else {
34885e82846SNickeau                $follow = "follow";
34985e82846SNickeau            }
35085e82846SNickeau        }
351c3437056SNickeau        if ($page->isLatePublication() && PagePublicationDate::isLatePublicationProtectionEnabled()) {
35285e82846SNickeau            $protected = true;
353c3437056SNickeau            if (PagePublicationDate::getLatePublicationProtectionMode() == PageProtection::CONF_VALUE_ACL) {
35485e82846SNickeau                $follow = "nofollow";
35585e82846SNickeau            } else {
35685e82846SNickeau                $follow = "follow";
35785e82846SNickeau            }
35885e82846SNickeau        }
35985e82846SNickeau        if ($protected) {
36085e82846SNickeau            foreach ($event->data['meta'] as $key => $meta) {
36185e82846SNickeau                if (array_key_exists("name", $meta)) {
36285e82846SNickeau                    /**
36385e82846SNickeau                     * We may have several properties
36485e82846SNickeau                     */
36585e82846SNickeau                    if ($meta["name"] == "robots") {
36685e82846SNickeau                        $event->data['meta'][$key]["content"] = "noindex,$follow";
36785e82846SNickeau                    }
36885e82846SNickeau                }
36985e82846SNickeau            }
37085e82846SNickeau        }
37185e82846SNickeau    }
37285e82846SNickeau
3735f891b7eSNickeau}
374