1<?php
2
3use dokuwiki\Extension\Plugin;
4
5/**
6 * DokuWiki Plugin elasticsearch (Helper Component)
7 *
8 * User-independent ACL methods
9 *
10 * @license GPL 2 http://www.gnu.org/licenses/gpl-2.0.html
11 * @author  Andreas Gohr <gohr@cosmocode.de>
12 * @author  Anna Dabrowska <dabrowska@cosmocode.de>
13 */
14class helper_plugin_elasticsearch_acl extends Plugin
15{
16    /**
17     * Returns a full list of (read) permissions for users and groups whose access to a given page
18     * is defined in the ACLs.
19     * Traverses the whole rule set and resolves overrides and exclusions.
20     *
21     * @param string $id Page id
22     * @return array
23     */
24    public function getPageACL($id)
25    {
26        $id    = cleanID($id);
27        $rules = [];
28
29        /** @var admin_plugin_acl $hlpACL */
30        $hlpACL = plugin_load('admin', 'acl');
31        if (method_exists($hlpACL, 'initAclConfig')) {
32            $hlpACL->initAclConfig();
33        } else {
34            /** @deprecated Call for current stable release */
35            $hlpACL->_init_acl_config();
36        }
37
38        // ACL lines as array
39        $acl = $hlpACL->acl;
40        ksort($acl);
41
42        // check for exact id
43        if (isset($acl[$id])) {
44            // process matched rule
45            $this->addRule($acl[$id], $rules);
46            // stop traversing if we reached a total access block for @ALL
47            if (isset($acl[$id]['@ALL'])) return $rules;
48        }
49
50        // walk namespace segments up
51        $ns = $id;
52        do {
53            $ns = getNS($ns);
54            // no namespace, check permissions for root
55            if (!$ns && isset($acl['*'])) {
56                $this->addRule($acl['*'], $rules);
57                // stop traversing if we reached a total access block for @ALL
58                if (isset($acl['*']['@ALL'])) {
59                    $ns = false;
60                    continue;
61                }
62            }
63            // check namespace
64            if (isset($acl[$ns . ':*'])) {
65                $this->addRule($acl[$ns . ':*'], $rules);
66                // stop traversing if we reached a total access block for @ALL
67                if (isset($acl[$ns . ':*']['@ALL'])) $ns = false;
68            }
69        } while ($ns);
70
71        return $rules;
72    }
73
74    /**
75     * Splits a rule set into query-digestible chunks
76     *
77     * @param array $rules
78     * @return array
79     */
80    public function splitRules($rules)
81    {
82        $splitACL = [
83            'groups_include' => [],
84            'groups_exclude' => [],
85            'users_include' => [],
86            'users_exclude' => [],
87        ];
88
89        foreach ($rules as $key => $perm) {
90            if (strpos($key, '@') === 0) {
91                $type = $perm ? 'groups_include' : 'groups_exclude';
92            } else {
93                $type = $perm ? 'users_include' : 'users_exclude';
94            }
95            $splitACL[$type][] = ltrim($key, '@');
96        }
97
98        return $splitACL;
99    }
100
101    /**
102     * Adds specific access rules to a rule set covering a full namespace path.
103     * Omit access block for @ALL since it is assumed.
104     *
105     * @param array $rule Collection of access permissions for a certain location
106     * @param array $rules Set of rules already
107     */
108    protected function addRule($rule, &$rules)
109    {
110        $localrules = [];
111
112        foreach ($rule as $key => $perm) {
113            // set read permissions for a given group or user
114            // but skip if already defined for a more specific path
115            if ($key !== '@ALL' && !array_key_exists($key, $rules)) {
116                $localrules[$key] = $perm > AUTH_NONE;
117            } elseif ($key === '@ALL' && $perm > AUTH_NONE) {
118                $localrules[$key] = true;
119            }
120        }
121
122        $rules = array_merge($rules, $localrules);
123    }
124}
125