1 | <?php
|
---|
2 | /**
|
---|
3 | * ACL administration functions
|
---|
4 | *
|
---|
5 | * @license GPL 2 (http://www.gnu.org/licenses/gpl.html)
|
---|
6 | * @author Andreas Gohr <[email protected]>
|
---|
7 | * @author Anika Henke <[email protected]> (concepts)
|
---|
8 | * @author Frank Schubert <[email protected]> (old version)
|
---|
9 | */
|
---|
10 | // must be run within Dokuwiki
|
---|
11 | if(!defined('DOKU_INC')) die();
|
---|
12 |
|
---|
13 | /**
|
---|
14 | * All DokuWiki plugins to extend the admin function
|
---|
15 | * need to inherit from this class
|
---|
16 | */
|
---|
17 | class admin_plugin_acl extends DokuWiki_Admin_Plugin {
|
---|
18 | var $acl = null;
|
---|
19 | var $ns = null;
|
---|
20 | /**
|
---|
21 | * The currently selected item, associative array with id and type.
|
---|
22 | * Populated from (in this order):
|
---|
23 | * $_REQUEST['current_ns']
|
---|
24 | * $_REQUEST['current_id']
|
---|
25 | * $ns
|
---|
26 | * $ID
|
---|
27 | */
|
---|
28 | var $current_item = null;
|
---|
29 | var $who = '';
|
---|
30 | var $usersgroups = array();
|
---|
31 | var $specials = array();
|
---|
32 |
|
---|
33 | /**
|
---|
34 | * return some info
|
---|
35 | */
|
---|
36 | function getInfo(){
|
---|
37 | return array(
|
---|
38 | 'author' => 'Andreas Gohr',
|
---|
39 | 'email' => '[email protected]',
|
---|
40 | 'date' => '2011-04-16',
|
---|
41 | 'name' => 'ACL Manager',
|
---|
42 | 'desc' => 'Manage Page Access Control Lists',
|
---|
43 | 'url' => 'http://dokuwiki.org/plugin:acl',
|
---|
44 | );
|
---|
45 | }
|
---|
46 |
|
---|
47 | /**
|
---|
48 | * return prompt for admin menu
|
---|
49 | */
|
---|
50 | function getMenuText($language) {
|
---|
51 | return $this->getLang('admin_acl');
|
---|
52 | }
|
---|
53 |
|
---|
54 | /**
|
---|
55 | * return sort order for position in admin menu
|
---|
56 | */
|
---|
57 | function getMenuSort() {
|
---|
58 | return 1;
|
---|
59 | }
|
---|
60 |
|
---|
61 | /**
|
---|
62 | * handle user request
|
---|
63 | *
|
---|
64 | * Initializes internal vars and handles modifications
|
---|
65 | *
|
---|
66 | * @author Andreas Gohr <[email protected]>
|
---|
67 | */
|
---|
68 | function handle() {
|
---|
69 | global $AUTH_ACL;
|
---|
70 | global $ID;
|
---|
71 | global $auth;
|
---|
72 | global $config_cascade;
|
---|
73 |
|
---|
74 | // fresh 1:1 copy without replacements
|
---|
75 | $AUTH_ACL = file($config_cascade['acl']['default']);
|
---|
76 |
|
---|
77 |
|
---|
78 | // namespace given?
|
---|
79 | if($_REQUEST['ns'] == '*'){
|
---|
80 | $this->ns = '*';
|
---|
81 | }else{
|
---|
82 | $this->ns = cleanID($_REQUEST['ns']);
|
---|
83 | }
|
---|
84 |
|
---|
85 | if ($_REQUEST['current_ns']) {
|
---|
86 | $this->current_item = array('id' => cleanID($_REQUEST['current_ns']), 'type' => 'd');
|
---|
87 | } elseif ($_REQUEST['current_id']) {
|
---|
88 | $this->current_item = array('id' => cleanID($_REQUEST['current_id']), 'type' => 'f');
|
---|
89 | } elseif ($this->ns) {
|
---|
90 | $this->current_item = array('id' => $this->ns, 'type' => 'd');
|
---|
91 | } else {
|
---|
92 | $this->current_item = array('id' => $ID, 'type' => 'f');
|
---|
93 | }
|
---|
94 |
|
---|
95 | // user or group choosen?
|
---|
96 | $who = trim($_REQUEST['acl_w']);
|
---|
97 | if($_REQUEST['acl_t'] == '__g__' && $who){
|
---|
98 | $this->who = '@'.ltrim($auth->cleanGroup($who),'@');
|
---|
99 | }elseif($_REQUEST['acl_t'] == '__u__' && $who){
|
---|
100 | $this->who = ltrim($who,'@');
|
---|
101 | if($this->who != '%USER%'){ #keep wildcard as is
|
---|
102 | $this->who = $auth->cleanUser($this->who);
|
---|
103 | }
|
---|
104 | }elseif($_REQUEST['acl_t'] &&
|
---|
105 | $_REQUEST['acl_t'] != '__u__' &&
|
---|
106 | $_REQUEST['acl_t'] != '__g__'){
|
---|
107 | $this->who = $_REQUEST['acl_t'];
|
---|
108 | }elseif($who){
|
---|
109 | $this->who = $who;
|
---|
110 | }
|
---|
111 |
|
---|
112 | // handle modifications
|
---|
113 | if(isset($_REQUEST['cmd']) && checkSecurityToken()){
|
---|
114 |
|
---|
115 | // scope for modifications
|
---|
116 | if($this->ns){
|
---|
117 | if($this->ns == '*'){
|
---|
118 | $scope = '*';
|
---|
119 | }else{
|
---|
120 | $scope = $this->ns.':*';
|
---|
121 | }
|
---|
122 | }else{
|
---|
123 | $scope = $ID;
|
---|
124 | }
|
---|
125 |
|
---|
126 | if(isset($_REQUEST['cmd']['save']) && $scope && $this->who && isset($_REQUEST['acl'])){
|
---|
127 | // handle additions or single modifications
|
---|
128 | $this->_acl_del($scope, $this->who);
|
---|
129 | $this->_acl_add($scope, $this->who, (int) $_REQUEST['acl']);
|
---|
130 | }elseif(isset($_REQUEST['cmd']['del']) && $scope && $this->who){
|
---|
131 | // handle single deletions
|
---|
132 | $this->_acl_del($scope, $this->who);
|
---|
133 | }elseif(isset($_REQUEST['cmd']['update'])){
|
---|
134 | // handle update of the whole file
|
---|
135 | foreach((array) $_REQUEST['del'] as $where => $names){
|
---|
136 | // remove all rules marked for deletion
|
---|
137 | foreach($names as $who)
|
---|
138 | unset($_REQUEST['acl'][$where][$who]);
|
---|
139 | }
|
---|
140 | // prepare lines
|
---|
141 | $lines = array();
|
---|
142 | // keep header
|
---|
143 | foreach($AUTH_ACL as $line){
|
---|
144 | if($line{0} == '#'){
|
---|
145 | $lines[] = $line;
|
---|
146 | }else{
|
---|
147 | break;
|
---|
148 | }
|
---|
149 | }
|
---|
150 | // re-add all rules
|
---|
151 | foreach((array) $_REQUEST['acl'] as $where => $opt){
|
---|
152 | foreach($opt as $who => $perm){
|
---|
153 | if ($who[0]=='@') {
|
---|
154 | if ($who!='@ALL') {
|
---|
155 | $who = '@'.ltrim($auth->cleanGroup($who),'@');
|
---|
156 | }
|
---|
157 | } elseif ($who != '%USER%'){ #keep wildcard as is
|
---|
158 | $who = $auth->cleanUser($who);
|
---|
159 | }
|
---|
160 | $who = auth_nameencode($who,true);
|
---|
161 | $lines[] = "$where\t$who\t$perm\n";
|
---|
162 | }
|
---|
163 | }
|
---|
164 | // save it
|
---|
165 | io_saveFile($config_cascade['acl']['default'], join('',$lines));
|
---|
166 | }
|
---|
167 |
|
---|
168 | // reload ACL config
|
---|
169 | $AUTH_ACL = file($config_cascade['acl']['default']);
|
---|
170 | }
|
---|
171 |
|
---|
172 | // initialize ACL array
|
---|
173 | $this->_init_acl_config();
|
---|
174 | }
|
---|
175 |
|
---|
176 | /**
|
---|
177 | * ACL Output function
|
---|
178 | *
|
---|
179 | * print a table with all significant permissions for the
|
---|
180 | * current id
|
---|
181 | *
|
---|
182 | * @author Frank Schubert <[email protected]>
|
---|
183 | * @author Andreas Gohr <[email protected]>
|
---|
184 | */
|
---|
185 | function html() {
|
---|
186 | global $ID;
|
---|
187 |
|
---|
188 | echo '<div id="acl_manager">'.NL;
|
---|
189 | echo '<h1>'.$this->getLang('admin_acl').'</h1>'.NL;
|
---|
190 | echo '<div class="level1">'.NL;
|
---|
191 |
|
---|
192 | echo '<div id="acl__tree">'.NL;
|
---|
193 | $this->_html_explorer();
|
---|
194 | echo '</div>'.NL;
|
---|
195 |
|
---|
196 | echo '<div id="acl__detail">'.NL;
|
---|
197 | $this->_html_detail();
|
---|
198 | echo '</div>'.NL;
|
---|
199 | echo '</div>'.NL;
|
---|
200 |
|
---|
201 | echo '<div class="clearer"></div>';
|
---|
202 | echo '<h2>'.$this->getLang('current').'</h2>'.NL;
|
---|
203 | echo '<div class="level2">'.NL;
|
---|
204 | $this->_html_table();
|
---|
205 | echo '</div>'.NL;
|
---|
206 |
|
---|
207 | echo '<div class="footnotes"><div class="fn">'.NL;
|
---|
208 | echo '<sup><a id="fn__1" class="fn_bot" name="fn__1" href="#fnt__1">1)</a></sup>'.NL;
|
---|
209 | echo $this->getLang('p_include');
|
---|
210 | echo '</div></div>';
|
---|
211 |
|
---|
212 | echo '</div>'.NL;
|
---|
213 | }
|
---|
214 |
|
---|
215 | /**
|
---|
216 | * returns array with set options for building links
|
---|
217 | *
|
---|
218 | * @author Andreas Gohr <[email protected]>
|
---|
219 | */
|
---|
220 | function _get_opts($addopts=null){
|
---|
221 | global $ID;
|
---|
222 | $opts = array(
|
---|
223 | 'do'=>'admin',
|
---|
224 | 'page'=>'acl',
|
---|
225 | );
|
---|
226 | if($this->ns) $opts['ns'] = $this->ns;
|
---|
227 | if($this->who) $opts['acl_w'] = $this->who;
|
---|
228 |
|
---|
229 | if(is_null($addopts)) return $opts;
|
---|
230 | return array_merge($opts, $addopts);
|
---|
231 | }
|
---|
232 |
|
---|
233 | /**
|
---|
234 | * Display a tree menu to select a page or namespace
|
---|
235 | *
|
---|
236 | * @author Andreas Gohr <[email protected]>
|
---|
237 | */
|
---|
238 | function _html_explorer(){
|
---|
239 | global $conf;
|
---|
240 | global $ID;
|
---|
241 | global $lang;
|
---|
242 |
|
---|
243 | $dir = $conf['datadir'];
|
---|
244 | $ns = $this->ns;
|
---|
245 | if(empty($ns)){
|
---|
246 | $ns = dirname(str_replace(':','/',$ID));
|
---|
247 | if($ns == '.') $ns ='';
|
---|
248 | }elseif($ns == '*'){
|
---|
249 | $ns ='';
|
---|
250 | }
|
---|
251 | $ns = utf8_encodeFN(str_replace(':','/',$ns));
|
---|
252 |
|
---|
253 | $data = $this->_get_tree($ns);
|
---|
254 |
|
---|
255 | // wrap a list with the root level around the other namespaces
|
---|
256 | $item = array( 'level' => 0, 'id' => '*', 'type' => 'd',
|
---|
257 | 'open' =>'true', 'label' => '['.$lang['mediaroot'].']');
|
---|
258 |
|
---|
259 | echo '<ul class="acltree">';
|
---|
260 | echo $this->_html_li_acl($item);
|
---|
261 | echo '<div class="li">';
|
---|
262 | echo $this->_html_list_acl($item);
|
---|
263 | echo '</div>';
|
---|
264 | echo html_buildlist($data,'acl',
|
---|
265 | array($this,'_html_list_acl'),
|
---|
266 | array($this,'_html_li_acl'));
|
---|
267 | echo '</li>';
|
---|
268 | echo '</ul>';
|
---|
269 |
|
---|
270 | }
|
---|
271 |
|
---|
272 | /**
|
---|
273 | * get a combined list of media and page files
|
---|
274 | *
|
---|
275 | * @param string $folder an already converted filesystem folder of the current namespace
|
---|
276 | * @param string $limit limit the search to this folder
|
---|
277 | */
|
---|
278 | function _get_tree($folder,$limit=''){
|
---|
279 | global $conf;
|
---|
280 |
|
---|
281 | // read tree structure from pages and media
|
---|
282 | $data = array();
|
---|
283 | search($data,$conf['datadir'],'search_index',array('ns' => $folder),$limit);
|
---|
284 | $media = array();
|
---|
285 | search($media,$conf['mediadir'],'search_index',array('ns' => $folder, 'nofiles' => true),$limit);
|
---|
286 | $data = array_merge($data,$media);
|
---|
287 | unset($media);
|
---|
288 |
|
---|
289 | // combine by sorting and removing duplicates
|
---|
290 | usort($data,array($this,'_tree_sort'));
|
---|
291 | $count = count($data);
|
---|
292 | if($count>0) for($i=1; $i<$count; $i++){
|
---|
293 | if($data[$i-1]['id'] == $data[$i]['id'] && $data[$i-1]['type'] == $data[$i]['type']) unset($data[$i]);
|
---|
294 | }
|
---|
295 | return $data;
|
---|
296 | }
|
---|
297 |
|
---|
298 | /**
|
---|
299 | * usort callback
|
---|
300 | *
|
---|
301 | * Sorts the combined trees of media and page files
|
---|
302 | */
|
---|
303 | function _tree_sort($a,$b){
|
---|
304 | // handle the trivial cases first
|
---|
305 | if ($a['id'] == '') return -1;
|
---|
306 | if ($b['id'] == '') return 1;
|
---|
307 | // split up the id into parts
|
---|
308 | $a_ids = explode(':', $a['id']);
|
---|
309 | $b_ids = explode(':', $b['id']);
|
---|
310 | // now loop through the parts
|
---|
311 | while (count($a_ids) && count($b_ids)) {
|
---|
312 | // compare each level from upper to lower
|
---|
313 | // until a non-equal component is found
|
---|
314 | $cur_result = strcmp(array_shift($a_ids), array_shift($b_ids));
|
---|
315 | if ($cur_result) {
|
---|
316 | // if one of the components is the last component and is a file
|
---|
317 | // and the other one is either of a deeper level or a directory,
|
---|
318 | // the file has to come after the deeper level or directory
|
---|
319 | if (empty($a_ids) && $a['type'] == 'f' && (count($b_ids) || $b['type'] == 'd')) return 1;
|
---|
320 | if (empty($b_ids) && $b['type'] == 'f' && (count($a_ids) || $a['type'] == 'd')) return -1;
|
---|
321 | return $cur_result;
|
---|
322 | }
|
---|
323 | }
|
---|
324 | // The two ids seem to be equal. One of them might however refer
|
---|
325 | // to a page, one to a namespace, the namespace needs to be first.
|
---|
326 | if (empty($a_ids) && empty($b_ids)) {
|
---|
327 | if ($a['type'] == $b['type']) return 0;
|
---|
328 | if ($a['type'] == 'f') return 1;
|
---|
329 | return -1;
|
---|
330 | }
|
---|
331 | // Now the empty part is either a page in the parent namespace
|
---|
332 | // that obviously needs to be after the namespace
|
---|
333 | // Or it is the namespace that contains the other part and should be
|
---|
334 | // before that other part.
|
---|
335 | if (empty($a_ids)) return ($a['type'] == 'd') ? -1 : 1;
|
---|
336 | if (empty($b_ids)) return ($b['type'] == 'd') ? 1 : -1;
|
---|
337 | }
|
---|
338 |
|
---|
339 | /**
|
---|
340 | * Display the current ACL for selected where/who combination with
|
---|
341 | * selectors and modification form
|
---|
342 | *
|
---|
343 | * @author Andreas Gohr <[email protected]>
|
---|
344 | */
|
---|
345 | function _html_detail(){
|
---|
346 | global $conf;
|
---|
347 | global $ID;
|
---|
348 |
|
---|
349 | echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
|
---|
350 |
|
---|
351 | echo '<div id="acl__user">';
|
---|
352 | echo $this->getLang('acl_perms').' ';
|
---|
353 | $inl = $this->_html_select();
|
---|
354 | echo '<input type="text" name="acl_w" class="edit" value="'.(($inl)?'':hsc(ltrim($this->who,'@'))).'" />'.NL;
|
---|
355 | echo '<input type="submit" value="'.$this->getLang('btn_select').'" class="button" />'.NL;
|
---|
356 | echo '</div>'.NL;
|
---|
357 |
|
---|
358 | echo '<div id="acl__info">';
|
---|
359 | $this->_html_info();
|
---|
360 | echo '</div>';
|
---|
361 |
|
---|
362 | echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
|
---|
363 | echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
|
---|
364 | echo '<input type="hidden" name="do" value="admin" />'.NL;
|
---|
365 | echo '<input type="hidden" name="page" value="acl" />'.NL;
|
---|
366 | echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL;
|
---|
367 | echo '</div></form>'.NL;
|
---|
368 | }
|
---|
369 |
|
---|
370 | /**
|
---|
371 | * Print infos and editor
|
---|
372 | */
|
---|
373 | function _html_info(){
|
---|
374 | global $ID;
|
---|
375 |
|
---|
376 | if($this->who){
|
---|
377 | $current = $this->_get_exact_perm();
|
---|
378 |
|
---|
379 | // explain current permissions
|
---|
380 | $this->_html_explain($current);
|
---|
381 | // load editor
|
---|
382 | $this->_html_acleditor($current);
|
---|
383 | }else{
|
---|
384 | echo '<p>';
|
---|
385 | if($this->ns){
|
---|
386 | printf($this->getLang('p_choose_ns'),hsc($this->ns));
|
---|
387 | }else{
|
---|
388 | printf($this->getLang('p_choose_id'),hsc($ID));
|
---|
389 | }
|
---|
390 | echo '</p>';
|
---|
391 |
|
---|
392 | echo $this->locale_xhtml('help');
|
---|
393 | }
|
---|
394 | }
|
---|
395 |
|
---|
396 | /**
|
---|
397 | * Display the ACL editor
|
---|
398 | *
|
---|
399 | * @author Andreas Gohr <[email protected]>
|
---|
400 | */
|
---|
401 | function _html_acleditor($current){
|
---|
402 | global $lang;
|
---|
403 |
|
---|
404 | echo '<fieldset>';
|
---|
405 | if(is_null($current)){
|
---|
406 | echo '<legend>'.$this->getLang('acl_new').'</legend>';
|
---|
407 | }else{
|
---|
408 | echo '<legend>'.$this->getLang('acl_mod').'</legend>';
|
---|
409 | }
|
---|
410 |
|
---|
411 |
|
---|
412 | echo $this->_html_checkboxes($current,empty($this->ns),'acl');
|
---|
413 |
|
---|
414 | if(is_null($current)){
|
---|
415 | echo '<input type="submit" name="cmd[save]" class="button" value="'.$lang['btn_save'].'" />'.NL;
|
---|
416 | }else{
|
---|
417 | echo '<input type="submit" name="cmd[save]" class="button" value="'.$lang['btn_update'].'" />'.NL;
|
---|
418 | echo '<input type="submit" name="cmd[del]" class="button" value="'.$lang['btn_delete'].'" />'.NL;
|
---|
419 | }
|
---|
420 |
|
---|
421 | echo '</fieldset>';
|
---|
422 | }
|
---|
423 |
|
---|
424 | /**
|
---|
425 | * Explain the currently set permissions in plain english/$lang
|
---|
426 | *
|
---|
427 | * @author Andreas Gohr <[email protected]>
|
---|
428 | */
|
---|
429 | function _html_explain($current){
|
---|
430 | global $ID;
|
---|
431 | global $auth;
|
---|
432 |
|
---|
433 | $who = $this->who;
|
---|
434 | $ns = $this->ns;
|
---|
435 |
|
---|
436 | // prepare where to check
|
---|
437 | if($ns){
|
---|
438 | if($ns == '*'){
|
---|
439 | $check='*';
|
---|
440 | }else{
|
---|
441 | $check=$ns.':*';
|
---|
442 | }
|
---|
443 | }else{
|
---|
444 | $check = $ID;
|
---|
445 | }
|
---|
446 |
|
---|
447 | // prepare who to check
|
---|
448 | if($who{0} == '@'){
|
---|
449 | $user = '';
|
---|
450 | $groups = array(ltrim($who,'@'));
|
---|
451 | }else{
|
---|
452 | $user = $who;
|
---|
453 | $info = $auth->getUserData($user);
|
---|
454 | if($info === false){
|
---|
455 | $groups = array();
|
---|
456 | }else{
|
---|
457 | $groups = $info['grps'];
|
---|
458 | }
|
---|
459 | }
|
---|
460 |
|
---|
461 | // check the permissions
|
---|
462 | $perm = auth_aclcheck($check,$user,$groups);
|
---|
463 |
|
---|
464 | // build array of named permissions
|
---|
465 | $names = array();
|
---|
466 | if($perm){
|
---|
467 | if($ns){
|
---|
468 | if($perm >= AUTH_DELETE) $names[] = $this->getLang('acl_perm16');
|
---|
469 | if($perm >= AUTH_UPLOAD) $names[] = $this->getLang('acl_perm8');
|
---|
470 | if($perm >= AUTH_CREATE) $names[] = $this->getLang('acl_perm4');
|
---|
471 | }
|
---|
472 | if($perm >= AUTH_EDIT) $names[] = $this->getLang('acl_perm2');
|
---|
473 | if($perm >= AUTH_READ) $names[] = $this->getLang('acl_perm1');
|
---|
474 | $names = array_reverse($names);
|
---|
475 | }else{
|
---|
476 | $names[] = $this->getLang('acl_perm0');
|
---|
477 | }
|
---|
478 |
|
---|
479 | // print permission explanation
|
---|
480 | echo '<p>';
|
---|
481 | if($user){
|
---|
482 | if($ns){
|
---|
483 | printf($this->getLang('p_user_ns'),hsc($who),hsc($ns),join(', ',$names));
|
---|
484 | }else{
|
---|
485 | printf($this->getLang('p_user_id'),hsc($who),hsc($ID),join(', ',$names));
|
---|
486 | }
|
---|
487 | }else{
|
---|
488 | if($ns){
|
---|
489 | printf($this->getLang('p_group_ns'),hsc(ltrim($who,'@')),hsc($ns),join(', ',$names));
|
---|
490 | }else{
|
---|
491 | printf($this->getLang('p_group_id'),hsc(ltrim($who,'@')),hsc($ID),join(', ',$names));
|
---|
492 | }
|
---|
493 | }
|
---|
494 | echo '</p>';
|
---|
495 |
|
---|
496 | // add note if admin
|
---|
497 | if($perm == AUTH_ADMIN){
|
---|
498 | echo '<p>'.$this->getLang('p_isadmin').'</p>';
|
---|
499 | }elseif(is_null($current)){
|
---|
500 | echo '<p>'.$this->getLang('p_inherited').'</p>';
|
---|
501 | }
|
---|
502 | }
|
---|
503 |
|
---|
504 |
|
---|
505 | /**
|
---|
506 | * Item formatter for the tree view
|
---|
507 | *
|
---|
508 | * User function for html_buildlist()
|
---|
509 | *
|
---|
510 | * @author Andreas Gohr <[email protected]>
|
---|
511 | */
|
---|
512 | function _html_list_acl($item){
|
---|
513 | global $ID;
|
---|
514 | $ret = '';
|
---|
515 | // what to display
|
---|
516 | if($item['label']){
|
---|
517 | $base = $item['label'];
|
---|
518 | }else{
|
---|
519 | $base = ':'.$item['id'];
|
---|
520 | $base = substr($base,strrpos($base,':')+1);
|
---|
521 | }
|
---|
522 |
|
---|
523 | // highlight?
|
---|
524 | if( ($item['type']== $this->current_item['type'] && $item['id'] == $this->current_item['id']))
|
---|
525 | $cl = ' cur';
|
---|
526 |
|
---|
527 | // namespace or page?
|
---|
528 | if($item['type']=='d'){
|
---|
529 | if($item['open']){
|
---|
530 | $img = DOKU_BASE.'lib/images/minus.gif';
|
---|
531 | $alt = '−';
|
---|
532 | }else{
|
---|
533 | $img = DOKU_BASE.'lib/images/plus.gif';
|
---|
534 | $alt = '+';
|
---|
535 | }
|
---|
536 | $ret .= '<img src="'.$img.'" alt="'.$alt.'" />';
|
---|
537 | $ret .= '<a href="'.wl('',$this->_get_opts(array('ns'=>$item['id'],'sectok'=>getSecurityToken()))).'" class="idx_dir'.$cl.'">';
|
---|
538 | $ret .= $base;
|
---|
539 | $ret .= '</a>';
|
---|
540 | }else{
|
---|
541 | $ret .= '<a href="'.wl('',$this->_get_opts(array('id'=>$item['id'],'ns'=>'','sectok'=>getSecurityToken()))).'" class="wikilink1'.$cl.'">';
|
---|
542 | $ret .= noNS($item['id']);
|
---|
543 | $ret .= '</a>';
|
---|
544 | }
|
---|
545 | return $ret;
|
---|
546 | }
|
---|
547 |
|
---|
548 |
|
---|
549 | function _html_li_acl($item){
|
---|
550 | return '<li class="level'.$item['level'].'">';
|
---|
551 | }
|
---|
552 |
|
---|
553 |
|
---|
554 | /**
|
---|
555 | * Get current ACL settings as multidim array
|
---|
556 | *
|
---|
557 | * @author Andreas Gohr <[email protected]>
|
---|
558 | */
|
---|
559 | function _init_acl_config(){
|
---|
560 | global $AUTH_ACL;
|
---|
561 | global $conf;
|
---|
562 | $acl_config=array();
|
---|
563 | $usersgroups = array();
|
---|
564 |
|
---|
565 | // get special users and groups
|
---|
566 | $this->specials[] = '@ALL';
|
---|
567 | $this->specials[] = '@'.$conf['defaultgroup'];
|
---|
568 | if($conf['manager'] != '!!not set!!'){
|
---|
569 | $this->specials = array_merge($this->specials,
|
---|
570 | array_map('trim',
|
---|
571 | explode(',',$conf['manager'])));
|
---|
572 | }
|
---|
573 | $this->specials = array_filter($this->specials);
|
---|
574 | $this->specials = array_unique($this->specials);
|
---|
575 | sort($this->specials);
|
---|
576 |
|
---|
577 | foreach($AUTH_ACL as $line){
|
---|
578 | $line = trim(preg_replace('/#.*$/','',$line)); //ignore comments
|
---|
579 | if(!$line) continue;
|
---|
580 |
|
---|
581 | $acl = preg_split('/\s+/',$line);
|
---|
582 | //0 is pagename, 1 is user, 2 is acl
|
---|
583 |
|
---|
584 | $acl[1] = rawurldecode($acl[1]);
|
---|
585 | $acl_config[$acl[0]][$acl[1]] = $acl[2];
|
---|
586 |
|
---|
587 | // store non-special users and groups for later selection dialog
|
---|
588 | $ug = $acl[1];
|
---|
589 | if(in_array($ug,$this->specials)) continue;
|
---|
590 | $usersgroups[] = $ug;
|
---|
591 | }
|
---|
592 |
|
---|
593 | $usersgroups = array_unique($usersgroups);
|
---|
594 | sort($usersgroups);
|
---|
595 | ksort($acl_config);
|
---|
596 |
|
---|
597 | $this->acl = $acl_config;
|
---|
598 | $this->usersgroups = $usersgroups;
|
---|
599 | }
|
---|
600 |
|
---|
601 | /**
|
---|
602 | * Display all currently set permissions in a table
|
---|
603 | *
|
---|
604 | * @author Andreas Gohr <[email protected]>
|
---|
605 | */
|
---|
606 | function _html_table(){
|
---|
607 | global $lang;
|
---|
608 | global $ID;
|
---|
609 |
|
---|
610 | echo '<form action="'.wl().'" method="post" accept-charset="utf-8"><div class="no">'.NL;
|
---|
611 | if($this->ns){
|
---|
612 | echo '<input type="hidden" name="ns" value="'.hsc($this->ns).'" />'.NL;
|
---|
613 | }else{
|
---|
614 | echo '<input type="hidden" name="id" value="'.hsc($ID).'" />'.NL;
|
---|
615 | }
|
---|
616 | echo '<input type="hidden" name="acl_w" value="'.hsc($this->who).'" />'.NL;
|
---|
617 | echo '<input type="hidden" name="do" value="admin" />'.NL;
|
---|
618 | echo '<input type="hidden" name="page" value="acl" />'.NL;
|
---|
619 | echo '<input type="hidden" name="sectok" value="'.getSecurityToken().'" />'.NL;
|
---|
620 | echo '<table class="inline">';
|
---|
621 | echo '<tr>';
|
---|
622 | echo '<th>'.$this->getLang('where').'</th>';
|
---|
623 | echo '<th>'.$this->getLang('who').'</th>';
|
---|
624 | echo '<th>'.$this->getLang('perm').'<sup><a id="fnt__1" class="fn_top" name="fnt__1" href="#fn__1">1)</a></sup></th>';
|
---|
625 | echo '<th>'.$lang['btn_delete'].'</th>';
|
---|
626 | echo '</tr>';
|
---|
627 | foreach($this->acl as $where => $set){
|
---|
628 | foreach($set as $who => $perm){
|
---|
629 | echo '<tr>';
|
---|
630 | echo '<td>';
|
---|
631 | if(substr($where,-1) == '*'){
|
---|
632 | echo '<span class="aclns">'.hsc($where).'</span>';
|
---|
633 | $ispage = false;
|
---|
634 | }else{
|
---|
635 | echo '<span class="aclpage">'.hsc($where).'</span>';
|
---|
636 | $ispage = true;
|
---|
637 | }
|
---|
638 | echo '</td>';
|
---|
639 |
|
---|
640 | echo '<td>';
|
---|
641 | if($who{0} == '@'){
|
---|
642 | echo '<span class="aclgroup">'.hsc($who).'</span>';
|
---|
643 | }else{
|
---|
644 | echo '<span class="acluser">'.hsc($who).'</span>';
|
---|
645 | }
|
---|
646 | echo '</td>';
|
---|
647 |
|
---|
648 | echo '<td>';
|
---|
649 | echo $this->_html_checkboxes($perm,$ispage,'acl['.$where.']['.$who.']');
|
---|
650 | echo '</td>';
|
---|
651 |
|
---|
652 | echo '<td align="center">';
|
---|
653 | echo '<input type="checkbox" name="del['.hsc($where).'][]" value="'.hsc($who).'" />';
|
---|
654 | echo '</td>';
|
---|
655 | echo '</tr>';
|
---|
656 | }
|
---|
657 | }
|
---|
658 |
|
---|
659 | echo '<tr>';
|
---|
660 | echo '<th align="right" colspan="4">';
|
---|
661 | echo '<input type="submit" value="'.$lang['btn_update'].'" name="cmd[update]" class="button" />';
|
---|
662 | echo '</th>';
|
---|
663 | echo '</tr>';
|
---|
664 | echo '</table>';
|
---|
665 | echo '</div></form>'.NL;
|
---|
666 | }
|
---|
667 |
|
---|
668 |
|
---|
669 | /**
|
---|
670 | * Returns the permission which were set for exactly the given user/group
|
---|
671 | * and page/namespace. Returns null if no exact match is available
|
---|
672 | *
|
---|
673 | * @author Andreas Gohr <[email protected]>
|
---|
674 | */
|
---|
675 | function _get_exact_perm(){
|
---|
676 | global $ID;
|
---|
677 | if($this->ns){
|
---|
678 | if($this->ns == '*'){
|
---|
679 | $check = '*';
|
---|
680 | }else{
|
---|
681 | $check = $this->ns.':*';
|
---|
682 | }
|
---|
683 | }else{
|
---|
684 | $check = $ID;
|
---|
685 | }
|
---|
686 |
|
---|
687 | if(isset($this->acl[$check][$this->who])){
|
---|
688 | return $this->acl[$check][$this->who];
|
---|
689 | }else{
|
---|
690 | return null;
|
---|
691 | }
|
---|
692 | }
|
---|
693 |
|
---|
694 | /**
|
---|
695 | * adds new acl-entry to conf/acl.auth.php
|
---|
696 | *
|
---|
697 | * @author Frank Schubert <[email protected]>
|
---|
698 | */
|
---|
699 | function _acl_add($acl_scope, $acl_user, $acl_level){
|
---|
700 | global $config_cascade;
|
---|
701 | $acl_config = file_get_contents($config_cascade['acl']['default']);
|
---|
702 | $acl_user = auth_nameencode($acl_user,true);
|
---|
703 |
|
---|
704 | // max level for pagenames is edit
|
---|
705 | if(strpos($acl_scope,'*') === false) {
|
---|
706 | if($acl_level > AUTH_EDIT) $acl_level = AUTH_EDIT;
|
---|
707 | }
|
---|
708 |
|
---|
709 |
|
---|
710 | $new_acl = "$acl_scope\t$acl_user\t$acl_level\n";
|
---|
711 |
|
---|
712 | $new_config = $acl_config.$new_acl;
|
---|
713 |
|
---|
714 | return io_saveFile($config_cascade['acl']['default'], $new_config);
|
---|
715 | }
|
---|
716 |
|
---|
717 | /**
|
---|
718 | * remove acl-entry from conf/acl.auth.php
|
---|
719 | *
|
---|
720 | * @author Frank Schubert <[email protected]>
|
---|
721 | */
|
---|
722 | function _acl_del($acl_scope, $acl_user){
|
---|
723 | global $config_cascade;
|
---|
724 | $acl_config = file($config_cascade['acl']['default']);
|
---|
725 | $acl_user = auth_nameencode($acl_user,true);
|
---|
726 |
|
---|
727 | $acl_pattern = '^'.preg_quote($acl_scope,'/').'\s+'.$acl_user.'\s+[0-8].*$';
|
---|
728 |
|
---|
729 | // save all non!-matching
|
---|
730 | $new_config = preg_grep("/$acl_pattern/", $acl_config, PREG_GREP_INVERT);
|
---|
731 |
|
---|
732 | return io_saveFile($config_cascade['acl']['default'], join('',$new_config));
|
---|
733 | }
|
---|
734 |
|
---|
735 | /**
|
---|
736 | * print the permission radio boxes
|
---|
737 | *
|
---|
738 | * @author Frank Schubert <[email protected]>
|
---|
739 | * @author Andreas Gohr <[email protected]>
|
---|
740 | */
|
---|
741 | function _html_checkboxes($setperm,$ispage,$name){
|
---|
742 | global $lang;
|
---|
743 |
|
---|
744 | static $label = 0; //number labels
|
---|
745 | $ret = '';
|
---|
746 |
|
---|
747 | if($ispage && $setperm > AUTH_EDIT) $perm = AUTH_EDIT;
|
---|
748 |
|
---|
749 | foreach(array(AUTH_NONE,AUTH_READ,AUTH_EDIT,AUTH_CREATE,AUTH_UPLOAD,AUTH_DELETE) as $perm){
|
---|
750 | $label += 1;
|
---|
751 |
|
---|
752 | //general checkbox attributes
|
---|
753 | $atts = array( 'type' => 'radio',
|
---|
754 | 'id' => 'pbox'.$label,
|
---|
755 | 'name' => $name,
|
---|
756 | 'value' => $perm );
|
---|
757 | //dynamic attributes
|
---|
758 | if(!is_null($setperm) && $setperm == $perm) $atts['checked'] = 'checked';
|
---|
759 | if($ispage && $perm > AUTH_EDIT){
|
---|
760 | $atts['disabled'] = 'disabled';
|
---|
761 | $class = ' class="disabled"';
|
---|
762 | }else{
|
---|
763 | $class = '';
|
---|
764 | }
|
---|
765 |
|
---|
766 | //build code
|
---|
767 | $ret .= '<label for="pbox'.$label.'" title="'.$this->getLang('acl_perm'.$perm).'"'.$class.'>';
|
---|
768 | $ret .= '<input '.buildAttributes($atts).' /> ';
|
---|
769 | $ret .= $this->getLang('acl_perm'.$perm);
|
---|
770 | $ret .= '</label>'.NL;
|
---|
771 | }
|
---|
772 | return $ret;
|
---|
773 | }
|
---|
774 |
|
---|
775 | /**
|
---|
776 | * Print a user/group selector (reusing already used users and groups)
|
---|
777 | *
|
---|
778 | * @author Andreas Gohr <[email protected]>
|
---|
779 | */
|
---|
780 | function _html_select(){
|
---|
781 | global $conf;
|
---|
782 | $inlist = false;
|
---|
783 |
|
---|
784 | if($this->who &&
|
---|
785 | !in_array($this->who,$this->usersgroups) &&
|
---|
786 | !in_array($this->who,$this->specials)){
|
---|
787 |
|
---|
788 | if($this->who{0} == '@'){
|
---|
789 | $gsel = ' selected="selected"';
|
---|
790 | }else{
|
---|
791 | $usel = ' selected="selected"';
|
---|
792 | }
|
---|
793 | }else{
|
---|
794 | $usel = '';
|
---|
795 | $gsel = '';
|
---|
796 | $inlist = true;
|
---|
797 | }
|
---|
798 |
|
---|
799 |
|
---|
800 | echo '<select name="acl_t" class="edit">'.NL;
|
---|
801 | echo ' <option value="__g__" class="aclgroup"'.$gsel.'>'.$this->getLang('acl_group').':</option>'.NL;
|
---|
802 | echo ' <option value="__u__" class="acluser"'.$usel.'>'.$this->getLang('acl_user').':</option>'.NL;
|
---|
803 | if (!empty($this->specials)) {
|
---|
804 | echo ' <optgroup label=" ">'.NL;
|
---|
805 | foreach($this->specials as $ug){
|
---|
806 | if($ug == $this->who){
|
---|
807 | $sel = ' selected="selected"';
|
---|
808 | $inlist = true;
|
---|
809 | }else{
|
---|
810 | $sel = '';
|
---|
811 | }
|
---|
812 |
|
---|
813 | if($ug{0} == '@'){
|
---|
814 | echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
|
---|
815 | }else{
|
---|
816 | echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
|
---|
817 | }
|
---|
818 | }
|
---|
819 | echo ' </optgroup>'.NL;
|
---|
820 | }
|
---|
821 | if (!empty($this->usersgroups)) {
|
---|
822 | echo ' <optgroup label=" ">'.NL;
|
---|
823 | foreach($this->usersgroups as $ug){
|
---|
824 | if($ug == $this->who){
|
---|
825 | $sel = ' selected="selected"';
|
---|
826 | $inlist = true;
|
---|
827 | }else{
|
---|
828 | $sel = '';
|
---|
829 | }
|
---|
830 |
|
---|
831 | if($ug{0} == '@'){
|
---|
832 | echo ' <option value="'.hsc($ug).'" class="aclgroup"'.$sel.'>'.hsc($ug).'</option>'.NL;
|
---|
833 | }else{
|
---|
834 | echo ' <option value="'.hsc($ug).'" class="acluser"'.$sel.'>'.hsc($ug).'</option>'.NL;
|
---|
835 | }
|
---|
836 | }
|
---|
837 | echo ' </optgroup>'.NL;
|
---|
838 | }
|
---|
839 | echo '</select>'.NL;
|
---|
840 | return $inlist;
|
---|
841 | }
|
---|
842 | }
|
---|