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