1<?php
2/**
3 * @license    GPL 2 (http://www.gnu.org/licenses/gpl.html)
4 * @author     Myron Turner <turnermm02@shaw.ca>
5 */
6
7// must be run within Dokuwiki
8if (!defined('DOKU_INC')) die();
9if (!defined('HTMLOK_ACCESS_DIR')) define('HTMLOK_ACCESS_DIR', realpath(dirname(__FILE__)) . '/conf/access');
10
11class helper_plugin_htmlOKay extends DokuWiki_Plugin {
12
13  var $access_level = 0;
14  var $saved_inf;
15  var $current_file;
16   var $files;
17   var $users;
18   var $groups;
19   var $display;
20   var $namespace;
21   var $db_msg;
22
23  function getMethods(){
24    $result = array();
25    $result[] = array(
26      'name'   => 'set_permissions',
27      'desc'   => "initialize current user's access permissions",
28       'params' =>array()
29    );
30    $result[] = array(
31       'name'   => 'get_namespace',
32      'desc'   => 'returns current access namespace',
33      'params' =>array(),
34      'return' => array('namespace' => 'string')
35    );
36    $result[] = array(
37       'name'   => 'get_access_scope',
38      'desc'   => 'returns current access scope with namespace colons replaced with hashes: ns#ns2#page',
39       'params' =>array('path' => 'string') ,
40      'return' => array('access_scope' => 'string')
41    );
42   $result[] = array(
43       'name'   => 'set_DokuWikiDefault_perm',
44       'desc'   => 'sets htmlok=0,$INFO[htmlOK_client] = false',
45       'params' =>array()
46    );
47   $result[] = array(
48       'name'   => 'get_access_file',
49       'desc'   => 'returns system path to file holding access data',
50       'params' =>array('access_dir' => 'string', 'namespace' => 'string') ,
51      'return' => array('acces_file' => 'string')
52    );
53   $result[] = array(
54       'name'   => 'in_groups',
55       'desc'   => 'checks htmlOKay user groups against INFO[userinfo][groups] to see if this is htmlOKay user',
56       'params' =>array('INF0_groups' => 'string', 'groups' => 'string'),
57      'return' => array('in_group' => 'bool')
58    );
59   $result[] = array(
60       'name'   => 'get_permission_level',
61       'desc'   => 'checks htmlOKay user groups against INFO[userinfo][groups] to see if this is htmlOKay user',
62       'params' =>array('info' => 'mixed', 'htmlok' => 'mixed'),
63      'return' => array('level' => 'integer')
64    );
65   $result[] = array(
66       'name'   => 'get_access ',
67       'desc'   => 'gets current access level',
68       'params' =>array(),
69      'return' => array('level' => 'integer')
70    );
71    return $result;
72  }
73
74
75      function get_info()
76    {
77        global $conf;
78        global $INFO, $ID;
79
80   if (empty($INFO['namespace'])) {
81     $INFO['namespace'] = getNS($ID);
82  }
83
84        if (!empty($INFO['namespace']))
85        {
86            $namespace = $INFO['namespace'];
87        }
88
89        else
90        {
91            $namespace = '_ROOT_';
92        }
93
94        $this->namespace = $namespace;
95        $namespace = str_replace(':', '#', $namespace);
96
97        $access_file = $this->get_access_file(HTMLOK_ACCESS_DIR, $namespace);
98         if (!defined('ACCESS_FILE')) define('ACCESS_FILE', $access_file);
99        $access_file = ACCESS_FILE;
100        if (file_exists($access_file))
101        {
102            $INFO['htmlOK_access_scope'] = $this->get_access_scope($access_file);
103           $this->saved_inf =file_get_contents ($access_file);
104
105            if (!$this->saved_inf)
106            {
107                return;
108            }
109            $this->saved_inf = unserialize($this->saved_inf);
110            $this->files = $this->saved_inf['filespecs'];
111            $this->users = $this->saved_inf['user'];
112            $this->groups = $this->saved_inf['group'];
113            if(!empty($INFO['filepath']))  {
114               $this->curent_file = basename($INFO['filepath']);
115            }
116            else {
117               $this->curent_file = noNS($ID) . '.txt';
118            }
119
120            $this->access_file = $access_file;
121        }
122    }
123
124    function get_saved_inf() {
125         return $this->saved_inf;
126    }
127
128    function get_namespace() {
129         return $this->namespace;
130    }
131
132     function set_permissions()
133    {
134        global $INFO;
135        global $ID;
136        global $conf;
137
138        $this->get_info();
139        $in_group = false;
140        $in_users = false;
141        $file_found = false;
142        // set up defaults
143        $INFO['htmlOK_client'] = $INFO['client']; // set as a flag for use in syntax.php
144        $INFO['htmlOK_displayOnly'] = $this->saved_inf['display'];
145        $INFO['hmtlOK_access_level'] = 0;
146        // have HTML permissions been set for this namespace?
147
148        if (!$this->saved_inf)
149        {
150            $this->set_DokuWikiDefault_perm(); // Not HTML
151            return;
152        }
153
154        // have HTML permissions been set for this file in current namespace?
155        $this->set_dbg_msg("permissions exist");
156        foreach($this->files as $file)
157        {
158            if ($file == $this->curent_file || $file == 'all')
159            {
160                $file_found = true;
161                break;
162            }
163        }
164
165        if (!$file_found)
166        {
167            $this->set_DokuWikiDefault_perm(); // Not HTML
168            return;
169        }
170        // The current file has access to embedded HTML
171        // Does user belong to a group which has HTML access?
172        if(isset($INFO['userinfo']))  {
173            $INF0_groups = $INFO['userinfo']['grps'];
174        }
175        else {
176            $INF0_groups = "";
177        }
178
179        if (isset($this->groups) && !empty($this->groups))
180        {
181            $groups = array_keys($this->groups);
182            // $groups_found will be groups common to user and current page
183            $groups_found = $this->in_groups($INF0_groups, $groups);
184            if ($groups_found !== false)
185            {
186                $in_group = true;
187            }
188        }
189
190        // Does user have individual HTML access?
191        if (isset($this->users) && !empty($this->users))
192        {
193            $users = array_keys($this->users);
194            if (array_search ($INFO['client'], $users) !== false)
195            {
196                $in_users = true;
197            }
198        }
199
200        if ($in_users) $this->set_dbg_msg("User found: " . $INFO['client']);
201        else $this->set_dbg_msg("User " . $INFO['client'] . '  not found');
202
203        if ($in_group)
204        {
205            $str = print_r($groups_found, true);
206            $this->set_dbg_msg("Group(s) found: $str");
207        }
208        // If the user is not among groups or users with access then permissions are according to ACL
209        // check to see if the page uses HTML and has a default HTML access level
210        if (!$in_users && !$in_group)
211        {
212            $INFO['htmlOK_client'] = false;
213            if (isset($this->saved_inf['display']))
214            {
215                $INFO['hmtlOK_access_level'] = $this->get_permission_level('display', $this->saved_inf);
216                $this->set_dbg_msg("Display: " . $INFO['hmtlOK_access_level']);
217                $conf['htmlok'] = 1;
218                $INFO['htmlOK_visitor'] = true;
219
220                $cache = new cache($ID, ".xhtml");
221                trigger_event('PARSER_CACHE_USE', $cache);
222
223                return;
224            }
225            $this->set_dbg_msg("Permission denied");
226            return;
227        }
228
229        // Now we have to check the level of access
230        // and grant the user the highest level of his/her permissions
231        $group_level = 0;
232        $user_level = 0;
233        if ($in_group)
234        {
235            $group_level = $this->get_permission_level($groups_found, $this->groups);
236        }
237        if ($in_users)
238        {
239            $user_level = $this->get_permission_level($INFO['client'], $this->users);
240        }
241        $INFO['hmtlOK_access_level'] = ($group_level > $user_level) ? $group_level : $user_level;
242
243        if ($INFO['hmtlOK_access_level'] == 0)
244        {
245            $this->set_DokuWikiDefault_perm();
246            return;
247        }
248        $conf['htmlok'] = 1;
249    }
250
251       function get_access_scope($path) {
252         $access_dir = preg_quote(HTMLOK_ACCESS_DIR, '/');
253         $access_scope = preg_replace('/' . $access_dir . '/', "", $path);
254         $access_scope = trim($access_scope,'/' );
255         $access_scope = preg_replace('/#/', ':',$access_scope);
256         return $access_scope;
257    }
258
259       function set_DokuWikiDefault_perm()
260    {
261        global $INFO;
262        global $conf;
263        $INFO['htmlOK_client'] = false; // deactivate PARSER_CACHE_USE event, which
264        // disables caching while page is being edited
265        $conf['htmlok'] = 0; // Stop syntax.php from applying rules, this is not HTML
266
267        // So we will let ACL determine write permissions
268    }
269
270      function get_access_file($access_dir, $namespace)
271    {
272        $file = $access_dir . '/' . $namespace;
273        $this->set_dbg_msg("Original access file: $file");
274        if (file_exists($file))
275        {
276            $this->set_dbg_msg("Tried Original access file: $file");
277            return $file;
278        }
279
280        $dirs = explode('#', $namespace);
281        foreach($dirs as $dir)
282        {
283            array_pop($dirs);
284            $new_dir = implode('#', $dirs);
285            $file = $access_dir . '/' . $new_dir;
286            $this->set_dbg_msg("Tried access file: $file");
287
288            if (file_exists($file))
289            {
290                $this->set_dbg_msg("File exists: $file");
291                return $file;
292            }
293        }
294        return $access_dir . '/' . $namespace;
295    }
296
297    function in_groups($INF0_groups, $groups)
298    {
299        $groups_found = array();
300        $in_group = false;
301
302        if (!isset($INF0_groups)) return false; // no groups assigned to non-registered user
303        if(!is_array($INF0_groups)) return false;
304        foreach($INF0_groups as $grp)
305        {
306            if (array_search ($grp, $groups) !== false)
307            {
308                $in_group = true;
309                $groups_found[] = $grp;
310            }
311        }
312        if ($in_group) return $groups_found;
313        return false;
314    }
315
316    /**
317    *
318    * @param mixed $info either string, which is $INFO['client'] or array of groups common to
319    *                   both $INFO['userinfo']['grps'] and htmlOK's $saved_inf
320    * @param array $htmlok either user or group array from htmlOK $saved_inf
321    * @return integer the level as an integer
322    */
323    function get_permission_level($info, $htmlok)
324    {
325        $levels = array('none' => 0, 'strict' => 1, 'medium' => 2, 'lax' => 3, 'su' => 4);
326
327        if (is_string($info))
328            {
329             if(array_key_exists ( $info , $levels)) {
330              $this->access_level = $levels[$htmlok[$info]];
331                return $levels[$htmlok[$info]];
332        }
333        }
334        if(!is_array($info)) return 0;
335        $level = 0;
336        foreach($info as $name)
337        {
338            $temp = $htmlok[$name];
339            if ($levels[$temp] > $level)
340            {
341                $level = $levels[$temp];
342            }
343        }
344
345       $this->access_level = $level;
346        return $level;
347    }
348
349  function get_access() {
350      global $INFO;
351
352      if($INFO['hmtlOK_access_level'] ) {
353         return $INFO['hmtlOK_access_level'];
354       }
355       return $this->get_permission_level('display', $this->saved_inf);
356  }
357
358   function set_dbg_msg($msg="") {
359      if(!$msg) return $this->db_msg;
360      $this->db_msg .= $msg . '<br />';
361    }
362
363}
364