*/ // must be run within Dokuwiki if(!defined('DOKU_INC')) die(); class helper_plugin_aclauditor extends DokuWiki_Plugin { var $acls = null; var $usersgroups = null; function getInfo() { return array( 'author' => 'Etienne MELEARD', 'email' => 'etienne.meleard@free.fr', 'date' => @file_get_contents(DOKU_PLUGIN.'aclauditor/VERSION'), 'name' => 'ACL Auditor Plugin (helper class)', 'desc' => 'Functions to get info about user /group ACLs of a wiki page', 'url' => 'http://dokuwiki.org/plugin:aclauditor', ); } function getMethods() { return array( array( 'name' => 'resourceACLs', 'desc' => 'returns the list of ACLs that are applied on a resource (page/media)', 'params' => array( 'resource' => 'string' ), 'return' => array( 'list' => 'array' ) ), array( 'name' => 'getACL', 'desc' => 'returns the list of ACLs for a user/group', 'params' => array( 'of' => 'string' ), 'return' => array( 'list' => 'array' ) ), array( 'name' => 'getACLon', 'desc' => 'returns the list of ACLs that are applied on a resource (page/media) for a user or a group', 'params' => array( 'of' => 'string', 'resource' => 'string' ), 'return' => array( 'list' => 'array' ) ) ); } /** * Gets ACLs applied on a resource * @param $resource string or array of page id or media id to get acl list about * @retrun array */ function resourceACLs($resource, $locale = false) { $this->init(); $acls = array(); foreach($this->usersgroups as $u => $grps) if(auth_isadmin($u, $grps)) { $acls[$u] = array(); $acls[$u]['ADMIN'] = array('what' => '*', 'who' => $u, 'rule' => 'ADMIN', 'lvl' => AUTH_ADMIN); } $r = $this->IDPathTree($resource); foreach($this->acls as $w => $parts) { if(!in_array($parts['what'], $r)) continue; if(!isset($acls[$parts['who']])) $acls[$parts['who']] = array(); $acls[$parts['who']][$w] = array('what' => $parts['what'], 'who' => $parts['who'], 'rule' => $w, 'lvl' => $parts['lvl']); } uksort($acls, create_function('$a, $b', ' $agrp = preg_match("`^@.+`", $a); $bgrp = preg_match("`^@.+`", $b); if($agrp && !$bgrp) return -1; if(!$agrp && $bgrp) return 1; return strcmp($a, $b); ')); foreach($acls as $who => $list) { uasort($list, create_function('$a, $b', ' if($a["what"] == $b["what"]) return $a["lvl"] - $b["lvl"]; $a["what"] = str_replace("*", "", $a["what"]); $b["what"] = str_replace("*", "", $b["what"]); if(strpos($a["what"], $b["what"]) === 0) return 1; if(strpos($b["what"], $a["what"]) === 0) return -1; return 0; ')); $lvl = max(array_map(create_function('$p', 'return $p["lvl"];'), $list)); $slvl = -1; foreach($list as $l) if($l['what'] == $resource) $slvl = $l['lvl']; $list['_lvl'] = ($slvl >= 0) ? $slvl : $lvl; $acls[$who] = $list; } if($locale) foreach($acls as $who => $list) foreach($list as $rule => $d) if($d['what'] != $resource) unset($acls[$who][$rule]); return $acls; } /** * Get acls of a user/group for a resource * @param $of user or group to get acl list from * @param $resource page id or media id to get acl list about * @return array */ function getACLon($of, $resource) { $this->init(); $flt = array($of); if(!preg_match('`^@.+`', $of)) { $flt[] = '@ALL'; if(isset($this->usersgroups[$of])) $flt = array_merge($flt, $this->usersgroups[$of]); } $acls = array(); $glvl = 0; $gspecificlvl = -1; foreach($this->IDPathTree($resource) as $id) { $acls[$id] = $this->resourceACLs($id, true); $lvl = 0; $specificlvl = -1; foreach($acls[$id] as $who => $d) { if(!in_array($who, $flt)) { unset($acls[$id][$who]); continue; } foreach($d as $r => $rd) { if($rd['rule'] == 'ADMIN') { $lvl = AUTH_ADMIN; }elseif($rd['lvl'] > $lvl) $lvl = $rd['lvl']; if(($rd['what'] == $id) && ($rd['lvl'] > $specificlvl)) $specificlvl = $rd['lvl']; } } $acls[$id]['_lvl'] = $lvl; $acls[$id]['_specificlvl'] = $specificlvl; if($lvl > $glvl) $glvl = $lvl; if($specificlvl >= 0) $gspecificlvl = $specificlvl; } $acls['_lvl'] = $glvl; $acls['_specificlvl'] = $gspecificlvl; return $acls; } /** * Gets the acl list of an user/group * @param $of string what to get acls of * @return array */ function getACL($of) { $this->init(); $acls = array(); $of = array($of); if(!preg_match('`^@.+`', $of[0]) && isset($this->usersgroups[$of[0]])) { if(auth_isadmin($of[0], $this->usersgroups[$of[0]])) $acls['*'] = array('ADMIN' => array('what' => '*', 'who' => null, 'rule' => 'ADMIN', 'lvl' => AUTH_ADMIN)); $of = array_merge($of, $this->usersgroups[$of[0]]); } foreach($this->acls as $w => $parts) { if(!in_array($parts['who'], $of)) continue; if(!isset($acls[$parts['what']])) $acls[$parts['what']] = array(); $acls[$parts['what']][$w] = array('what' => $parts['what'], 'who' => $parts['who'], 'rule' => $w, 'lvl' => $parts['lvl']); } uksort($acls, create_function('$a, $b', ' if($a == $b) return 0; $a = str_replace("*", "", $a); $b = str_replace("*", "", $b); if(($b == "") || strpos($a, $b) === 0) return 1; if(($a == "") || strpos($b, $a) === 0) return -1; return 0; ')); foreach($acls as $what => $list) { uasort($list, create_function('$a, $b', 'return $a["lvl"] - $b["lvl"];')); $list['_lvl'] = max(array_map(create_function('$p', 'return $p["lvl"];'), $list)); $acls[$what] = $list; } return $acls; } /** * Parses the acl file into an array and loads users-groups hash */ function init() { if(is_null($this->acls)) { global $AUTH_ACL; foreach($AUTH_ACL as $l) { if(preg_match('`^\s*(#.*)$`', $l)) continue; list($what, $who, $lvl) = preg_split('`\s+`', $l); if(!$what || !$who || !$lvl) continue; $this->acls[$what.' '.$who.' '.$lvl] = array( 'what' => $what, 'who' => $who, 'lvl' => (int)$lvl ); } } if(is_null($this->usersgroups)) { global $auth; $this->usersgroups = array(); foreach($auth ? $auth->retrieveUsers() : array() as $u => $info) { $this->usersgroups[$u] = array_map(create_function('$g', 'return "@".$g;'), $info['grps']); $this->usersgroups[$u][] = '@ALL'; } } } /** * Decomposes an ID into ACLs compliant namespace tree * @param $id string id to decompose * @return array */ function IDPathTree($id) { $id = cleanID($id); if(!@file_exists(wikiFN($id)) && !@file_exists(mediaFN($id))) $id .= ':*'; $tree = $id ? array($id) : array(); while($id = getNS($id)) $tree[] = $id.':*'; $tree[] = '*'; return array_reverse(array_unique($tree)); } }