Major change to permissions backend - performs whois check (only supported blitzed and freenode right now) and advanced permissions supported.
authorDan
Tue, 20 Jan 2009 22:08:07 -0500
changeset 51 508400fc5282
parent 50 45164bc2567a
child 52 a8f0e99883d1
Major change to permissions backend - performs whois check (only supported blitzed and freenode right now) and advanced permissions supported.
config-sample.php
database.php
enanobot.php
libirc.php
modules/autoop.php
modules/ctcp.php
modules/echo.php
permissions.php
statsincludes/stats_frontend.php
--- a/config-sample.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/config-sample.php	Tue Jan 20 22:08:07 2009 -0500
@@ -7,7 +7,12 @@
 $pass = '';
 $name = 'Enano CMS logging/message bot';
 $user = 'enano';
-$privileged_list = array('your', 'nick', 'list', 'here');
+$permissions = array(
+    'your' => array('admin', 'alert'),
+    'nick' => array('admin', 'alert'),
+    'list' => array('echo', 'suspend', 'pm', 'channel' => array('#enano', '#ubuntu')),
+    'here' => array('echo', 'suspend', 'pm', 'shutdown', 'channel' => array('#enano')),
+  );
 $mysql_host = 'localhost';
 $mysql_user = '';
 $mysql_pass = '';
--- a/database.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/database.php	Tue Jan 20 22:08:07 2009 -0500
@@ -49,10 +49,11 @@
       // alert everyone on the bot's alert list
       if ( is_object($irc) )
       {
-        global $alert_list;
-        foreach ( $alert_list as $nick )
+        global $permissions;
+        foreach ( $permissions as $nick => $perms )
         {
-          $irc->privmsg($nick, "MySQL query error: $m_e");
+          if ( check_permissions($nick, array('context' => 'alert')) )
+            $irc->privmsg($nick, "MySQL query error: $m_e");
         }
       }
       else
--- a/enanobot.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/enanobot.php	Tue Jan 20 22:08:07 2009 -0500
@@ -75,6 +75,22 @@
 require('hooks.php');
 require('config.php');
 require('database.php');
+require('permissions.php');
+
+if ( !isset($permissions) )
+{
+  foreach ( $privileged_list as $user )
+  {
+    $permissions[$user] = array('admin');
+  }
+  if ( isset($alert_list) )
+  {
+    foreach ( $alert_list as $user )
+    {
+      $permissions[$user] = array('admin', 'alert');
+    }
+  }
+}
 
 $enanobot_version = '0.5-unstable';
 
@@ -141,7 +157,7 @@
 {
   global $irc, $nick, $mysql_conn, $privileged_list;
   
-  if ( strpos($message['message'], $nick) && !in_array($message['nick'], $privileged_list) && $message['nick'] != $nick )
+  if ( strpos($message['message'], $nick) && !check_permissions($message['nick'], array('context' => 'channel', 'channel' => $chan->get_channel_name())) && $message['nick'] != $nick )
   {
     $target_nick =& $message['nick'];
     // $chan->msg("{$target_nick}, I'm only a bot. :-) You should probably rely on the advice of humans if you need further assistance.", true);
@@ -156,40 +172,47 @@
 {
   global $privileged_list, $irc, $nick;
   static $part_cache = array();
-  if ( in_array($message['nick'], $privileged_list) && $message['message'] == 'Suspend' && $message['action'] == 'PRIVMSG' )
+  if ( $message['message'] == 'Suspend' && $message['action'] == 'PRIVMSG' && check_permissions($message['nick'], array('context' => 'suspend'), false) )
   {
     foreach ( $irc->channels as $channel )
     {
       $part_cache[] = array($channel->get_channel_name(), $channel->get_handler());
-      $channel->msg("I've received a request from {$message['nick']} to stop responding to requests, messages, and activities. Don't forget to unsuspend me with /msg $nick Resume when finished.", true);
-      $channel->part("Logging and presence suspended by {$message['nick']}", true);
+      $channel->part("suspended by {$message['nick']}", true);
     }
   }
-  else if ( in_array($message['nick'], $privileged_list) && $message['message'] == 'Resume' && $message['action'] == 'PRIVMSG' )
+  else if ( $message['message'] == 'Resume' && $message['action'] == 'PRIVMSG' && check_permissions($message['nick'], array('context' => 'suspend'), false) )
   {
     global $nick;
     foreach ( $part_cache as $chan_data )
     {
       $chan_name = substr($chan_data[0], 1);
       $GLOBALS[$chan_name] = $irc->join($chan_data[0], $chan_data[1]);
-      $GLOBALS[$chan_name]->msg("Bot resumed by {$message['nick']}.", true);
+      $GLOBALS[$chan_name]->msg("(resumed by {$message['nick']})", true);
       $irc->privmsg('ChanServ', "OP {$chan_data[0]} $nick");
     }
     $part_cache = array();
   }
-  else if ( in_array($message['nick'], $privileged_list) && preg_match('/^Shutdown(?: (.+))?$/i', $message['message'], $match) && $message['action'] == 'PRIVMSG' )
+  else if ( preg_match('/^Shutdown(?: (.+))?$/i', $message['message'], $match) && $message['action'] == 'PRIVMSG' && check_permissions($message['nick'], array('context' => 'shutdown'), false) )
   {
     $GLOBALS['_shutdown'] = true;
     $quitmessage = empty($match[1]) ? "Remote bot shutdown requested by {$message['nick']}" : $match[1];
     $irc->close($quitmessage, true);
     return 'BREAK';
   }
-  else if ( in_array($message['nick'], $privileged_list) && preg_match('/^re(?:hash|load)?(?:config)?(?: |$)/', $message['message']) )
+  else if ( preg_match('/^re(?:hash|load)?(?:config)?(?: |$)/', $message['message']) && check_permissions($message['nick'], array('context' => 'rehash'), false) )
   {
+    $oldnick = $GLOBALS['nick'];
     require('config.php');
     $GLOBALS['privileged_list'] = $privileged_list;
     $GLOBALS['alert_list'] = $alert_list;
     $GLOBALS['channels'] = $channels;
+    $GLOBALS['permissions'] = $permissions;
+    if ( $nick != $oldnick )
+    {
+      $irc->change_nick($nick, $pass);
+      $GLOBALS['nick'] = $nick;
+      $GLOBALS['pass'] = $pass;
+    }
     $in = array();
     foreach ( $irc->channels as $channel )
     {
--- a/libirc.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/libirc.php	Tue Jan 20 22:08:07 2009 -0500
@@ -256,6 +256,58 @@
   }
   
   /**
+   * Returns WHOIS information about a nick.
+   * @param string Nick
+   * @return array
+   */
+  
+  public function whois($nick)
+  {
+    static $cache = array();
+    if ( isset($cache[$nick]) )
+    {
+      if ( $cache[$nick]['time'] + 20 >= time() )
+      {
+        return $cache[$nick];
+      }
+    }
+    $this->put("WHOIS $nick\r\n");
+    $lines = array();
+    $return = array(
+        'identified' => false,
+        'time' => time()
+      );
+    while ( $line = $this->get(3) )
+    {
+      $lines[] = $line;
+      list(, $code) = explode(' ', $line);
+      $code = intval($code);
+      switch($code)
+      {
+        case 401:
+          return false;
+        case 311:
+          list(, , , $return['nick'], $return['user'], $return['host']) = explode(' ', $line);
+          $return['ircname'] = substr($line, strpos(substr($line, 1), ':') + 2);
+          break;
+        case 319:
+          $return['channels'] = explode(' ', substr($line, strpos(substr($line, 1), ':') + 2));
+          break;
+        case 307:
+        case 320:
+          if ( strstr($line, 'identified') )
+            $return['identified'] = true;
+          break;
+        case 318:
+          $cache[$nick] = $return;
+          return $return;
+      }
+    }
+    $cache[$nick] = $return;
+    return $return;
+  }
+  
+  /**
    * Parse bold (<b>...</b>) tags and color tags in a text into IRC speak, and process /me commands. Colors are <cyan>...</cyan>, specify background with <fg:bg>...</fgcolor:bgcolor>. Valid colors are white, black, navy, green, red, maroon, purple, orange, yellow, lime, teal, aqua, cyan, blue, pink, grey, and silver
    * @param string Text to filter
    * @return string
--- a/modules/autoop.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/modules/autoop.php	Tue Jan 20 22:08:07 2009 -0500
@@ -9,7 +9,7 @@
   $channelname = $chan->get_channel_name();
   
   // if a known op joins the channel, send mode +o
-  if ( in_array($message['nick'], $privileged_list) )
+  if ( check_permissions($message['nick'], array('context' => 'channel', 'channel' => $channelname)))
   {
     $chan->parent->put("MODE $channelname +o {$message['nick']}\r\n");
   }
--- a/modules/ctcp.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/modules/ctcp.php	Tue Jan 20 22:08:07 2009 -0500
@@ -5,7 +5,7 @@
 function handle_ctcp($ctcp, $params, $message)
 {
   global $irc;
-  global $alert_list;
+  global $permissions;
   switch($ctcp)
   {
     case 'PING':
@@ -20,8 +20,9 @@
       break;
   }
   $now = date('r');
-  foreach ( $alert_list as $alertme )
+  foreach ( $permissions as $alertme => $perms )
   {
-    $irc->privmsg($alertme, "Received CTCP \"$ctcp\" from {$message['nick']}, " . $now);
+    if ( check_permissions($alertme, array('context' => 'alert')) )
+      $irc->privmsg($alertme, "Received CTCP \"$ctcp\" from {$message['nick']}, " . $now);
   }
 }
--- a/modules/echo.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/modules/echo.php	Tue Jan 20 22:08:07 2009 -0500
@@ -7,7 +7,7 @@
 {
   global $privileged_list;
   
-  if ( preg_match('/^\!echo /', $message['message']) && in_array($message['nick'], $privileged_list) )
+  if ( preg_match('/^\!echo /', $message['message']) && check_permissions($message['nick'], array('context' => 'echo')) )
   {
     $chan->msg(eb_censor_words(preg_replace('/^\!echo /', '', $message['message'])), true);
   }
@@ -17,7 +17,7 @@
 {
   global $privileged_list;
   
-  if ( in_array($message['nick'], $privileged_list) && preg_match("/^(?:\!echo-|\/msg )([^\007, \r\n\a\t]+) (.+)/", $message['message'], $match) )
+  if ( preg_match("/^(?:\!echo-|\/msg )([#&][^\007, \r\n\a\t]+) (.+)/", $message['message'], $match) && check_permissions($message['nick'], array('context' => 'echo')) )
   {
     global $libirc_channels;
     $channel_name =& $match[1];
@@ -26,7 +26,7 @@
       $libirc_channels[$channel_name]->msg(eb_censor_words($match[2]), true);
     }
   }
-  else if ( in_array($message['nick'], $privileged_list) && preg_match("/^(?:\!pm|\/msg) ([^\007, \r\n\a\t]+) (.+)/", $message['message'], $match) )
+  else if ( preg_match("/^(?:\!pm|\/msg) ([^\007, \r\n\a\t]+) (.+)/", $message['message'], $match) && check_permissions($message['nick'], array('context' => 'pm'), false) )
   {
     global $irc;
     $irc->privmsg($match[1], eb_censor_words($match[2]));
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/permissions.php	Tue Jan 20 22:08:07 2009 -0500
@@ -0,0 +1,72 @@
+<?php
+
+function check_permissions($nick, $params, $quiet = true)
+{
+  global $permissions, $irc;
+  
+  // I have all the power.
+  if ( $nick === $GLOBALS['nick'] )
+  {
+    if ( defined('LIBIRC_DEBUG') )
+      echo "[!!!] Granted action {$params['context']} to {$GLOBALS['nick']} (self)\n";
+    return true;
+  }
+  
+  // Is the user in the permissions table?
+  if ( !isset($permissions[$nick]) )
+  {
+    if ( defined('LIBIRC_DEBUG') )
+      echo "[!!!] Denied action {$params['context']} to {$nick} (not in table)\n";
+    return false;
+  }
+  
+  // Make sure the user is identified
+  $whois = $irc->whois($nick);
+  if ( !$whois || ( $whois && !$whois['identified']) )
+  {
+    if ( defined('LIBIRC_DEBUG') )
+      echo "[!!!] Denied action {$params['context']} to {$nick} (whois check failed)\n";
+    if ( !$quiet )
+      $irc->privmsg($nick, "Please identify to services before you do that. (If you are already identified, wait 20 seconds for the whois cache to clear and try again)");
+    return false;
+  }
+  
+  // Is the user an admin?
+  if ( in_array('admin', $permissions[$nick]) && $params['context'] !== 'alert' )
+  {
+    if ( defined('LIBIRC_DEBUG') )
+      echo "[!!!] Granted action {$params['context']} to {$nick} (has admin rights)\n";
+    return true;
+  }
+  
+  switch($params['context']):
+    case 'channel':
+      if ( isset($permissions[$nick]['channel']) && is_array($permissions[$nick]['channel']) )
+      {
+        if ( in_array($params['channel'], $permissions[$nick]['channel']) )
+        {
+          if ( defined('LIBIRC_DEBUG') )
+            echo "[!!!] Granted action {$params['context']} to {$nick} in channel {$params['channel']} (on channel whitelist)\n";
+          return true;
+        }
+      }
+      if ( defined('LIBIRC_DEBUG') )
+        echo "[!!!] Denied action {$params['context']} to {$nick} in channel {$params['channel']} (not on channel whitelist)\n";
+      return false;
+    default:
+      eval(eb_fetch_hook('permission_check'));
+      if ( isset($result) )
+      {
+        $perm = $result ? 'Granted' : 'Denied';
+        if ( defined('LIBIRC_DEBUG') )
+          echo "[!!!] $perm action {$params['context']} to {$nick} (plugin overridden)\n";
+        return $result;
+      }
+      $result = in_array($params['context'], $permissions[$nick]);
+      $perm = $result ? 'Granted' : 'Denied';
+      if ( defined('LIBIRC_DEBUG') )
+        echo "[!!!] $perm action {$params['context']} to {$nick} (default handler)\n";
+      return $result;
+  endswitch;
+}
+
--- a/statsincludes/stats_frontend.php	Sat Jan 10 14:12:36 2009 -0500
+++ b/statsincludes/stats_frontend.php	Tue Jan 20 22:08:07 2009 -0500
@@ -15,7 +15,7 @@
   if ( empty($targetuser) )
     $targetuser = $message['nick'];
   
-  if ( $targetuser != $message['nick'] && !in_array($message['nick'], $privileged_list) )
+  if ( $targetuser != $message['nick'] && !check_permissions($message['nick'], array('context' => 'deletestats')) )
   {
     $irc->privmsg($message['nick'], "Sorry, you need to be a moderator to delete statistics for users other than yourself.");
     return true;