1<?php
2
3use dokuwiki\Extension\ActionPlugin;
4use dokuwiki\Extension\EventHandler;
5use dokuwiki\Extension\Event;
6use dokuwiki\Utf8\PhpString;
7
8/**
9 * DokuWiki Plugin anonprotect (Action Component)
10 *
11 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
12 * @author Anna Dabrowska <dokuwiki@cosmocode.de>
13 */
14class action_plugin_anonprotect extends ActionPlugin
15{
16    /** @var bool True if ACLs have already been fixed */
17    public static $fixed = false;
18
19    /** @inheritDoc */
20    public function register(EventHandler $controller)
21    {
22        $controller->register_hook('AUTH_ACL_CHECK', 'BEFORE', $this, 'handleACL');
23    }
24
25    /**
26     * Event handler for AUTH_ACL_CHECK
27     *
28     * @param Event $event Event object
29     * @return void
30     */
31    public function handleACL(Event $event)
32    {
33        $user = $event->data['user'];
34        $id = $event->data['id'];
35        $ns = getNS($id);
36
37        $norestrictions = $this->getConf('norestrictions');
38        $skip = $this->skipNs($ns, $norestrictions);
39
40        if ($skip) {
41            return;
42        }
43
44        if (!$user) {
45            $event->preventDefault();
46            $event->result = AUTH_NONE;
47        }
48
49        // fix ACLs: downgrade every rule for @ALL to no access
50        if (self::$fixed) return;
51
52        global $AUTH_ACL;
53
54        foreach ($AUTH_ACL as $line => $rule) {
55            if (PhpString::strpos($rule, '@ALL') !== false) {
56                $rule = preg_replace('/(@ALL\\t)(\d)/', '${1}' . AUTH_NONE, $rule);
57                $AUTH_ACL[$line] = $rule;
58            }
59        }
60
61        self::$fixed = true;
62    }
63
64    /**
65     * Skip namespace if it matches the norestriction setting
66     *
67     * @param string $ns
68     * @param string $norestrictions
69     * @return bool
70     */
71    public function skipNs($ns, $norestrictions)
72    {
73        return !empty(array_filter(
74            explode(',', $norestrictions),
75            function ($skip) use ($ns) {
76                // add colons to make sure we match against full namespace names
77                $ns = $ns ? ':' . $ns . ':' : '';
78                $skip = trim($skip) . ':';
79
80                $pos = strpos($ns, $skip);
81
82                // if skip is absolute, current namespace must match from the beginning
83                $skipIsAbsolute = $skip[0] === ':';
84                $found = $skipIsAbsolute ? $pos === 0 : $pos !== false;
85                return $ns && $found;
86            }
87        ));
88    }
89}
90