diff -r 13532b0a223f -r c15fbf197a54 includes/pageutils.php --- a/includes/pageutils.php Thu Mar 27 16:41:07 2008 -0400 +++ b/includes/pageutils.php Sat Mar 29 15:58:59 2008 -0700 @@ -1672,11 +1672,15 @@ // regenerate page selection $parms['page_id'] = ( isset($parms['page_id']) ) ? $parms['page_id'] : false; $parms['namespace'] = ( isset($parms['namespace']) ) ? $parms['namespace'] : false; + $parms['mode'] = 'seltarget_id'; $page_id =& $parms['page_id']; $namespace =& $parms['namespace']; $page_where_clause = ( empty($page_id) || empty($namespace) ) ? 'AND a.page_id IS NULL AND a.namespace IS NULL' : 'AND a.page_id=\'' . $db->escape($page_id) . '\' AND a.namespace=\'' . $db->escape($namespace) . '\''; $page_where_clause_lite = ( empty($page_id) || empty($namespace) ) ? 'AND page_id IS NULL AND namespace IS NULL' : 'AND page_id=\'' . $db->escape($page_id) . '\' AND namespace=\'' . $db->escape($namespace) . '\''; + $return['page_id'] = $parms['page_id']; + $return['namespace'] = $parms['namespace']; + // From here, let the seltarget handler take over case 'seltarget': $return['mode'] = 'seltarget'; @@ -1688,24 +1692,25 @@ switch($parms['target_type']) { case ACL_TYPE_USER: - $q = $db->sql_query('SELECT a.rules,u.user_id FROM ' . table_prefix.'users AS u + $user_col = ( $parms['mode'] == 'seltarget_id' ) ? 'user_id' : 'username'; + $q = $db->sql_query('SELECT a.rules,u.user_id,u.username FROM ' . table_prefix.'users AS u LEFT JOIN ' . table_prefix.'acl AS a ON a.target_id=u.user_id WHERE a.target_type='.ACL_TYPE_USER.' - AND u.username=\'' . $db->escape($parms['target_id']) . '\' + AND u.' . $user_col . ' = \'' . $db->escape($parms['target_id']) . '\' ' . $page_where_clause . ';'); if(!$q) return(Array('mode'=>'error','error'=>$db->get_error())); if($db->numrows() < 1) { $return['type'] = 'new'; - $q = $db->sql_query('SELECT user_id FROM ' . table_prefix.'users WHERE username=\'' . $db->escape($parms['target_id']) . '\';'); + $q = $db->sql_query('SELECT user_id,username FROM ' . table_prefix.'users WHERE username=\'' . $db->escape($parms['target_id']) . '\';'); if(!$q) return(Array('mode'=>'error','error'=>$db->get_error())); if($db->numrows() < 1) - return Array('mode'=>'error','error'=>$lang->get('acl_err_user_not_found')); + return Array('mode'=>'error','error'=>$lang->get('acl_err_user_not_found'),'debug' => $db->sql_backtrace()); $row = $db->fetchrow(); - $return['target_name'] = $return['target_id']; + $return['target_name'] = $row['username']; $return['target_id'] = intval($row['user_id']); $return['current_perms'] = array(); } @@ -1713,7 +1718,7 @@ { $return['type'] = 'edit'; $row = $db->fetchrow(); - $return['target_name'] = $return['target_id']; + $return['target_name'] = $row['username']; $return['target_id'] = intval($row['user_id']); $return['current_perms'] = $session->string_to_perm($row['rules']); } @@ -1830,8 +1835,9 @@ { return Array('mode'=>'error','error'=>$lang->get('acl_err_demo')); } - $q = $db->sql_query('DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).' - ' . $page_where_clause_lite . ';'); + $sql = 'DELETE FROM ' . table_prefix.'acl WHERE target_type='.intval($parms['target_type']).' AND target_id='.intval($parms['target_id']).' + ' . $page_where_clause_lite . ';'; + $q = $db->sql_query($sql); if(!$q) return Array('mode'=>'error','error'=>$db->get_error()); return Array( @@ -1843,6 +1849,117 @@ 'namespace' => $namespace, ); break; + case 'list_existing': + + $return = array( + 'mode' => 'list_existing', + 'key' => acl_list_draw_key(), + 'rules' => array() + ); + + $q = $db->sql_query("SELECT a.rule_id, u.username, g.group_name, a.target_type, a.target_id, a.page_id, a.namespace, a.rules, p.pg_name\n" + . " FROM " . table_prefix . "acl AS a\n" + . " LEFT JOIN " . table_prefix . "users AS u\n" + . " ON ( (a.target_type = " . ACL_TYPE_USER . " AND a.target_id = u.user_id) OR (u.user_id IS NULL) )\n" + . " LEFT JOIN " . table_prefix . "groups AS g\n" + . " ON ( (a.target_type = " . ACL_TYPE_GROUP . " AND a.target_id = g.group_id) OR (g.group_id IS NULL) )\n" + . " LEFT JOIN " . table_prefix . "page_groups as p\n" + . " ON ( (a.namespace = '__PageGroup' AND a.page_id = p.pg_id) OR (p.pg_id IS NULL) )\n" + . " GROUP BY a.rule_id\n" + . " ORDER BY a.target_type ASC, a.rule_id ASC;" + ); + + if ( !$q ) + $db->_die(); + + while ( $row = $db->fetchrow($q) ) + { + if ( $row['target_type'] == ACL_TYPE_USER && empty($row['username']) ) + { + // This is only done if we have an ACL affecting a user that doesn't exist. + // Nice little bit of maintenance to have. + if ( !$db->sql_query("DELETE FROM " . table_prefix . "acl WHERE rule_id = {$row['rule_id']};") ) + $db->_die(); + continue; + } + $score = get_acl_rule_score($row['rules']); + $deep_limit = ACL_SCALE_MINIMAL_SHADE; + // Determine background color of cell by score + if ( $score > 5 ) + { + // high score, show in green + $color = 2.5 * $score; + if ( $color > 255 ) + $color = 255; + $color = round($color); + // blend with the colordepth limit + $color = $deep_limit + ( ( 0xFF - $deep_limit ) - ( ( $color / 0xFF ) * ( 0xFF - $deep_limit ) ) ); + $color = dechex($color); + $color = "{$color}ff{$color}"; + } + else if ( $score < -5 ) + { + // low score, show in red + $color = 0 - $score; + $color = 2.5 * $color; + if ( $color > 255 ) + $color = 255; + $color = round($color); + // blend with the colordepth limit + $color = $deep_limit + ( ( 0xFF - $deep_limit ) - ( ( $color / 0xFF ) * ( 0xFF - $deep_limit ) ) ); + $color = dechex($color); + $color = "ff{$color}{$color}"; + } + else + { + $color = 'efefef'; + } + + // Rate rule textually based on its score + if ( $score >= 70 ) + $desc = $lang->get('acl_msg_scale_allow'); + else if ( $score >= 50 ) + $desc = $lang->get('acl_msg_scale_mostly_allow'); + else if ( $score >= 25 ) + $desc = $lang->get('acl_msg_scale_some_allow'); + else if ( $score >= -25 ) + $desc = $lang->get('acl_msg_scale_mixed'); + else if ( $score <= -70 ) + $desc = $lang->get('acl_msg_scale_deny'); + else if ( $score <= -50 ) + $desc = $lang->get('acl_msg_scale_mostly_deny'); + else if ( $score <= -25 ) + $desc = $lang->get('acl_msg_scale_some_deny'); + + // group and user target info + $info = ''; + if ( $row['target_type'] == ACL_TYPE_USER ) + $info = $lang->get('acl_msg_list_user', array( 'username' => $row['username'] )); // "(User: {$row['username']})"; + else if ( $row['target_type'] == ACL_TYPE_GROUP ) + $info = $lang->get('acl_msg_list_group', array( 'group' => $row['group_name'] )); + + // affected pages info + if ( $row['page_id'] && $row['namespace'] && $row['namespace'] != '__PageGroup' ) + $info .= $lang->get('acl_msg_list_on_page', array( 'page_name' => "{$row['namespace']}:{$row['page_id']}" )); + else if ( $row['page_id'] && $row['namespace'] && $row['namespace'] == '__PageGroup' ) + $info .= $lang->get('acl_msg_list_on_page_group', array( 'page_group' => $row['pg_name'] )); + else + $info .= $lang->get('acl_msg_list_entire_site'); + + $score_string = $lang->get('acl_msg_list_score', array + ( + 'score' => $score, + 'desc' => $desc, + 'info' => $info + )); + $return['rules'][] = array( + 'score_string' => $score_string, + 'rule_id' => $row['rule_id'], + 'color' => $color + ); + } + + break; default: return Array('mode'=>'error','error'=>'Hacking attempt'); break; @@ -2125,4 +2242,84 @@ } +/** + * Generates a graphical key showing how the ACL rule list works. + * @return string + */ + +function acl_list_draw_key() +{ + $out = '
'; + $out .= '
← Deny
'; + $out .= '
Allow →
'; + $out .= 'Neutral'; + $out .= '
'; + // 11 boxes on each side of the center + $inc = ceil ( ( 0xFF - ACL_SCALE_MINIMAL_SHADE ) / 11 ); + for ( $i = ACL_SCALE_MINIMAL_SHADE; $i <= 0xFF; $i+= $inc ) + { + $octet = dechex($i); + $color = "ff$octet$octet"; + $out .= '
 
'; + } + $out .= '
 
'; + for ( $i = 0xFF; $i >= ACL_SCALE_MINIMAL_SHADE; $i-= $inc ) + { + $octet = dechex($i); + $color = "{$octet}ff{$octet}"; + $out .= '
 
'; + } + $out .= '
'; + $out .= '
-100
'; + $out .= '
+100
'; + $out .= '0'; + $out .= '
'; + return $out; +} + +/** + * Gets the numerical score for the serialized form of an ACL rule + */ + +function get_acl_rule_score($perms) +{ + global $db, $session, $paths, $template, $plugins; // Common objects + if ( is_string($perms) ) + $perms = $session->string_to_perm($perms); + else if ( !is_array($perms) ) + return false; + $score = 0; + foreach ( $perms as $item ) + { + switch ( $item ) + { + case AUTH_ALLOW : + $inc = 2; + break; + case AUTH_WIKIMODE: + $inc = 1; + break; + case AUTH_DISALLOW: + $inc = -1; + break; + case AUTH_DENY: + $inc = -2; + break; + default: + $inc = 0; + break; + } + $score += $inc; + } + // this is different from the beta; calculate highest score and + // get percentage to be fairer to smaller/less broad rules + $divisor = count($perms) * 2; + if ( $divisor == 0 ) + { + return 0; + } + $score = 100 * ( $score / $divisor ); + return round($score); +} + ?>