]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/commitdiff
Auth now follows the specs defined in NewAuthModule even though there is no actual...
authorGiuseppe Bilotta <giuseppe.bilotta@gmail.com>
Wed, 2 Aug 2006 16:26:29 +0000 (16:26 +0000)
committerGiuseppe Bilotta <giuseppe.bilotta@gmail.com>
Wed, 2 Aug 2006 16:26:29 +0000 (16:26 +0000)
lib/rbot/botuser.rb
lib/rbot/config.rb
lib/rbot/core/core.rb
lib/rbot/ircbot.rb
lib/rbot/messagemapper.rb
lib/rbot/plugins.rb

index 98408a0d424b58a019dadf059d7f15e347da4be5..6c84a93bca2461d80c56629e8eb8b4c26672aced 100644 (file)
@@ -252,13 +252,29 @@ module Irc
         @perm = {}\r
       end\r
 \r
+      # Inspection simply inspects the internal hash\r
+      def inspect\r
+        @perm.inspect\r
+      end\r
+\r
       # Sets the permission for command _cmd_ to _val_,\r
-      # creating intermediate permissions if needed.\r
       #\r
       def set_permission(cmd, val)\r
-        raise TypeError, "#{val.inspect} must be true or false" unless [true,false].include?(val)\r
         Irc::error_if_not_command(cmd)\r
-        @perm[cmd.command] = val\r
+        case val\r
+        when true, false\r
+          @perm[cmd.command] = val\r
+        when nil\r
+          @perm.delete(cmd.command)\r
+        else\r
+          raise TypeError, "#{val.inspect} must be true or false" unless [true,false].include?(val)\r
+        end\r
+      end\r
+\r
+      # Resets the permission for command _cmd_\r
+      #\r
+      def reset_permission(cmd)\r
+        set_permission(cmd, nil)\r
       end\r
 \r
       # Tells if command _cmd_ is permitted. We do this by returning\r
@@ -313,6 +329,12 @@ module Irc
         end\r
       end\r
 \r
+      # Resets the permission for command _cmd_ on channel _chan_\r
+      #\r
+      def reset_permission(cmd, chan ="*")\r
+        set_permission(cmd, nil, chan)\r
+      end\r
+\r
       # Checks if BotUser is allowed to do something on channel _chan_,\r
       # or on all channels if _chan_ is nil\r
       #\r
@@ -415,17 +437,27 @@ module Irc
     end\r
 \r
 \r
-    # This is the anonymous BotUser: it's used for all users which haven't\r
+    # This is the default BotUser: it's used for all users which haven't\r
     # identified with the bot\r
     #\r
-    class AnonBotUserClass < BotUser\r
+    class DefaultBotUserClass < BotUser\r
       include Singleton\r
       def initialize\r
-        super("anonymous")\r
+        super("everyone")\r
+        @default_perm = PermissionSet.new\r
       end\r
       private :login, :add_netmask, :delete_netmask\r
 \r
-      # Anon knows everybody\r
+      # Sets the default permission for the default user (i.e. the ones\r
+      # set by the BotModule writers) on all channels\r
+      #\r
+      def set_default_permission(cmd, val)\r
+        @default_perm.set_permission(Command.new(cmd), val)\r
+        debug "Default permissions now:\n#{@default_perm.inspect}"\r
+      end\r
+\r
+      # default knows everybody\r
+      #\r
       def knows?(user)\r
         Irc::error_if_not_user(user)\r
         return true\r
@@ -436,12 +468,24 @@ module Irc
         super\r
         add_netmask("*!*@*")\r
       end\r
+\r
+      # DefaultBotUser will check the default_perm after checking\r
+      # the global ones\r
+      # or on all channels if _chan_ is nil\r
+      #\r
+      def permit?(cmd, chan=nil)\r
+        allow = super(cmd, chan)\r
+        if allow.nil? && chan.nil?\r
+          allow = @default_perm.permit?(cmd)\r
+        end\r
+        return allow\r
+      end\r
     end\r
 \r
-    # Returns the only instance of AnonBotUserClass\r
+    # Returns the only instance of DefaultBotUserClass\r
     #\r
-    def Auth.anonbotuser\r
-      return AnonBotUserClass.instance\r
+    def Auth.defaultbotuser\r
+      return DefaultBotUserClass.instance\r
     end\r
 \r
     # This is the BotOwner: he can do everything\r
@@ -470,10 +514,15 @@ module Irc
     class AuthManagerClass\r
       include Singleton\r
 \r
+      attr_reader :everyone\r
+      attr_reader :botowner\r
+\r
       # The instance manages two <code>Hash</code>es: one that maps\r
       # <code>Irc::User</code>s onto <code>BotUser</code>s, and the other that maps\r
       # usernames onto <code>BotUser</code>\r
       def initialize\r
+        @everyone = Auth::defaultbotuser\r
+        @botowner = Auth::botowner\r
         bot_associate(nil)\r
       end\r
 \r
@@ -494,7 +543,9 @@ module Irc
       def reset_hashes\r
         @botusers = Hash.new\r
         @allbotusers = Hash.new\r
-        [Auth::anonbotuser, Auth::botowner].each { |x| @allbotusers[x.username.to_sym] = x }\r
+        [everyone, botowner].each { |x|\r
+          @allbotusers[x.username.to_sym] = x\r
+        }\r
       end\r
 \r
       # load botlist from userfile\r
@@ -524,7 +575,8 @@ module Irc
       # Maps <code>Irc::User</code> to BotUser\r
       def irc_to_botuser(ircuser)\r
         Irc::error_if_not_user(ircuser)\r
-        return @botusers[ircuser] || Auth::anonbotuser\r
+        # TODO check netmasks\r
+        return @botusers[ircuser] || everyone\r
       end\r
 \r
       # creates a new BotUser\r
@@ -569,8 +621,8 @@ module Irc
       # is returned:\r
       # * associated BotUser on _chan_\r
       # * associated BotUser on all channels\r
-      # * anonbotuser on _chan_\r
-      # * anonbotuser on all channels\r
+      # * everyone on _chan_\r
+      # * everyone on all channels\r
       #\r
       def permit?(user, cmdtxt, chan=nil)\r
         botuser = irc_to_botuser(user)\r
@@ -590,10 +642,10 @@ module Irc
         allow = botuser.permit?(cmd)\r
         return allow unless allow.nil?\r
 \r
-        unless botuser == Auth::anonbotuser\r
-          allow = Auth::anonbotuser.permit?(cmd, chan) if chan\r
+        unless botuser == everyone\r
+          allow = everyone.permit?(cmd, chan) if chan\r
           return allow unless allow.nil?\r
-          allow = Auth::anonbotuser.permit?(cmd)\r
+          allow = everyone.permit?(cmd)\r
           return allow unless allow.nil?\r
         end\r
 \r
index ab16c442f0986f746e9d1b176ecc3a8c75b8b8dc..f91cfa70914fc3f74ee1a967fde990b224272da5 100644 (file)
@@ -352,6 +352,9 @@ module Irc
 
     # bot:: parent bot class
     # create a new config hash from #{botclass}/conf.rbot
+    # TODO make this into a core module to guide a BotCOnfigManagerClass
+    # singleton instance from IRC
+    #
     def initialize(bot)
       @@bot = bot
 
@@ -363,24 +366,24 @@ module Irc
       #  unset
       #  desc
       #  and for arrays:
-      #    add TODO
-      #    remove TODO
+      #    add
+      #    remove
       @handler = MessageMapper.new(self)
-      @handler.map 'config list :module', :action => 'handle_list',
+      @handler.map 'config', 'config list :module', :action => 'handle_list',
                    :defaults => {:module => false}
-      @handler.map 'config get :key', :action => 'handle_get'
-      @handler.map 'config desc :key', :action => 'handle_desc'
-      @handler.map 'config describe :key', :action => 'handle_desc'
-      @handler.map 'config set :key *value', :action => 'handle_set'
-      @handler.map 'config add :value to :key', :action => 'handle_add'
-      @handler.map 'config rm :value from :key', :action => 'handle_rm'
-      @handler.map 'config del :value from :key', :action => 'handle_rm'
-      @handler.map 'config delete :value from :key', :action => 'handle_rm'
-      @handler.map 'config unset :key', :action => 'handle_unset'
-      @handler.map 'config reset :key', :action => 'handle_unset'
-      @handler.map 'config help :topic', :action => 'handle_help',
+      @handler.map 'config', 'config get :key', :action => 'handle_get'
+      @handler.map 'config', 'config desc :key', :action => 'handle_desc'
+      @handler.map 'config', 'config describe :key', :action => 'handle_desc'
+      @handler.map 'config', 'config set :key *value', :action => 'handle_set'
+      @handler.map 'config', 'config add :value to :key', :action => 'handle_add'
+      @handler.map 'config', 'config rm :value from :key', :action => 'handle_rm'
+      @handler.map 'config', 'config del :value from :key', :action => 'handle_rm'
+      @handler.map 'config', 'config delete :value from :key', :action => 'handle_rm'
+      @handler.map 'config', 'config unset :key', :action => 'handle_unset'
+      @handler.map 'config', 'config reset :key', :action => 'handle_unset'
+      @handler.map 'config', 'config help :topic', :action => 'handle_help',
                    :defaults => {:topic => false}
-      @handler.map 'help config :topic', :action => 'handle_help',
+      @handler.map 'config', 'help config :topic', :action => 'handle_help',
                    :defaults => {:topic => false}
       
       if(File.exist?("#{@@bot.botclass}/conf.yaml"))
index fcf5ac3a33f209b95357fd6972693efdc6acf17d..55da1a7d4ea604ca7f2eb43cddfa8e841975af29 100644 (file)
@@ -165,77 +165,78 @@ core = Core.new
 core.map "quit *msg",\r
   :action => 'bot_quit',\r
   :defaults => { :msg => nil },\r
-  :auth => 'core::quit::quit'\r
+  :auth_path => 'quit'\r
 core.map "restart *msg",\r
   :action => 'bot_restart',\r
   :defaults => { :msg => nil },\r
-  :auth => 'core::quit::restart'\r
+  :auth_path => 'quit'\r
 \r
 core.map "save",\r
   :action => 'bot_save',\r
-  :auth => 'core::config::save'\r
+  :auth_path => 'config'\r
 core.map "rescan",\r
   :action => 'bot_rescan',\r
-  :auth => 'core::config::rescan'\r
+  :auth_path => 'config'\r
 core.map "nick :nick",\r
   :action => 'bot_nick',\r
-  :auth => 'core::config::nick'\r
+  :auth_path => 'config'\r
 core.map "status",\r
   :action => 'bot_status',\r
-  :auth => 'core::config::show::status'\r
+  :auth_path => 'config::show'\r
   # TODO see above\r
   #\r
   # core.map "registry stats",\r
   #   :action => 'bot_reg_stat',\r
-  #   :auth => 'core::config::show::registry'\r
+  #   :auth_path => 'config::show'\r
 core.map "version",\r
   :action => 'bot_version',\r
-  :auth => 'core::config::show::version'\r
+  :auth_path => 'config::show'\r
 \r
 core.map "quiet",\r
   :action => 'bot_quiet',\r
-  :auth => 'core::talk::quiet'\r
+  :auth_path => 'talk::set'\r
 core.map "quiet in :chan",\r
   :action => 'bot_quiet',\r
-  :auth => 'core::talk::quiet'\r
+  :auth_path => 'talk::set'\r
 core.map "talk",\r
   :action => 'bot_talk',\r
-  :auth => 'core::talk::talk'\r
+  :auth_path => 'talk::set'\r
 core.map "quiet in :chan",\r
   :action => 'bot_quiet',\r
-  :auth => 'core::talk::talk'\r
+  :auth_path => 'talk::set'\r
+\r
+core.map "say :where *what",\r
+  :action => 'bot_say',\r
+  :auth_path => 'talk::do'\r
+core.map "action :where *what",\r
+  :action => 'bot_action',\r
+  :auth_path => 'talk::do'\r
+core.map "mode :where :what *who",\r
+  :action => 'bot_mode',\r
+  :auth_path => 'talk::do'\r
 \r
 core.map "join :chan :pass", \r
   :action => 'bot_join',\r
   :defaults => {:pass => nil},\r
-  :auth => 'core::movearound::join'\r
+  :auth_path => 'move'\r
 core.map "part :chan",\r
   :action => 'bot_part',\r
   :defaults => {:chan => nil},\r
-  :auth => 'core::movearound::part'\r
+  :auth_path => 'move'\r
 core.map "hide",\r
   :action => 'bot_hide',\r
-  :auth => 'core::movearound::hide'\r
-\r
-core.map "say :where *what",\r
-  :action => 'bot_say',\r
-  :auth => 'core::talk::say'\r
-core.map "action :where *what",\r
-  :action => 'bot_action',\r
-  :auth => 'core::talk::act'\r
-core.map "mode :where :what *who",\r
-  :action => 'bot_mode',\r
-  :auth => 'core::talk::mode'\r
+  :auth_path => 'move'\r
 \r
 core.map "ping",\r
-  :action => 'bot_ping'\r
+  :action => 'bot_ping',\r
+  :auth_path => '!ping!'\r
 core.map "help *topic",\r
   :action => 'bot_help',\r
-  :default => { :topic => [""] }\r
+  :default => { :topic => [""] },\r
+  :auth_path => '!help!'\r
 \r
 # TODO the first line should probably go to the auth module?\r
 #\r
-core.default_auth('*', true)\r
-core.default_auth('core', false)\r
-core.default_auth('core::config::show', true)\r
+core.default_auth('*', false)\r
+core.default_auth('config::show', true)\r
 \r
index f1d9e127860d0d70d9b0e4ad26e98cafe7be10e9..d96e036896555699ec237878c41f0e8071688a23 100644 (file)
@@ -346,6 +346,7 @@ class IrcBot
       log_session_end
       exit 2
     end
+    @auth.everyone.set_default_permission("*", true)
 
     Dir.mkdir("#{botclass}/plugins") unless File.exist?("#{botclass}/plugins")
     @plugins = Plugins::pluginmanager
index 200c676d70580fb68430e830022d21478b1521ef..e4ad60b08905723a249051e540c0865c8ef67e10 100644 (file)
@@ -93,13 +93,14 @@ module Irc
     #             :requirements => {:limit => /^\d+$/},
     #             :private => false
     #
-    def map(*args)
-      @templates << Template.new(*args)
+    def map(botmodule, *args)
+      @templates << Template.new(botmodule, *args)
     end
 
     def each
       @templates.each {|tmpl| yield tmpl}
     end
+
     def last
       @templates.last
     end
@@ -125,7 +126,7 @@ module Irc
             failures << [tmpl, "class does not respond to action #{action}"]
             next
           end
-          auth = tmpl.options[:auth] ? tmpl.options[:auth] : tmpl.items[0]
+          auth = tmpl.options[:full_auth_path]
           debug "checking auth for #{auth}"
           if m.bot.auth.allow?(auth, m.source, m.replyto)
             debug "template match found and auth'd: #{action.inspect} #{options.inspect}"
@@ -157,13 +158,48 @@ module Irc
     attr_reader :defaults # The defaults hash
     attr_reader :options  # The options hash
     attr_reader :items
-    def initialize(template, hash={})
-      raise ArgumentError, "Second argument must be a hash!" unless hash.kind_of?(Hash)
+
+    def initialize(botmodule, template, hash={})
+      raise ArgumentError, "Third argument must be a hash!" unless hash.kind_of?(Hash)
       @defaults = hash[:defaults].kind_of?(Hash) ? hash.delete(:defaults) : {}
       @requirements = hash[:requirements].kind_of?(Hash) ? hash.delete(:requirements) : {}
       self.items = template
+      if hash.has_key?(:auth)
+        warning "Command #{template} in #{botmodule} uses old :auth syntax, please upgrade"
+      end
+      if hash.has_key?(:full_auth_path)
+        warning "Command #{template} in #{botmodule} sets :full_auth_path, please don't do this"
+      else
+        case botmodule
+        when String
+          pre = botmodule
+        when Plugins::BotModule
+          pre = botmodule.name
+        else
+          raise ArgumentError, "Can't find auth base in #{botmodule.inspect}"
+        end
+        post = items.reject{ |x|
+          x == pre || x.kind_of?(Symbol)
+        }
+        if post.empty?
+          post = nil
+        else
+          post = post.first
+        end
+        if hash.has_key?(:auth_path)
+          extra = hash[:auth_path]
+          pre = nil if extra.sub!(/^!/, "")
+          post = nil if extra.sub!(/!$/, "")
+        else
+          extra = nil
+        end
+        hash[:full_auth_path] = [pre,extra,post].compact.join("::")
+        # TODO check if the full_auth_path is sane
+      end
+
       @options = hash
     end
+
     def items=(str)
       items = str.split(/\s+/).collect {|c| (/^(:|\*)(\w+)$/ =~ c) ? (($1 == ':' ) ? $2.intern : "*#{$2}".intern) : c} if str.kind_of?(String) # split and convert ':xyz' to symbols
       items.shift if items.first == ""
index 31fb11344c9861e8e5f46bb56fe78ceae177f5c0..7e98b1b34f138933e8db0066e88f2a7483ef4ab0 100644 (file)
@@ -112,7 +112,7 @@ module Plugins
       @handler = MessageMapper.new(self)
       @registry = BotRegistryAccessor.new(@bot, self.class.to_s.gsub(/^.*::/, ""))
 
-      @manager.add_botmodule(kl, self)
+      @manager.add_botmodule(self)
     end
 
     def flush_registry
@@ -130,10 +130,11 @@ module Plugins
     end
 
     def map(*args)
-      @handler.map(*args)
+      @handler.map(self, *args)
       # register this map
       name = @handler.last.items[0]
-      self.register name
+      auth = @handler.last.options[:full_auth_path]
+      self.register name, :auth => auth
       unless self.respond_to?('privmsg')
         def self.privmsg(m)
           handle(m)
@@ -142,10 +143,10 @@ module Plugins
     end
 
     def map!(*args)
-      @handler.map(*args)
+      @handler.map(self, *args)
       # register this map
       name = @handler.last.items[0]
-      self.register name, {:hidden => true}
+      self.register name, :auth => auth, :hidden => true
       unless self.respond_to?('privmsg')
         def self.privmsg(m)
           handle(m)
@@ -153,12 +154,23 @@ module Plugins
       end
     end
 
-    # Sets the default auth for command _cmd_ to _val_ on channel _chan_:
-    # usually _chan_ is either "*" for everywhere, public and private (in
-    # which case it can be omitted) or "?" for private communications
+    # Sets the default auth for command path _cmd_ to _val_ on channel _chan_:
+    # usually _chan_ is either "*" for everywhere, public and private (in which
+    # case it can be omitted) or "?" for private communications
     #
     def default_auth(cmd, val, chan="*")
-      Auth::anonbotuser.set_permission(cmd, val)
+      case cmd
+      when "*", ""
+        c = nil
+      else
+        c = cmd
+      end
+      Auth::defaultbotuser.set_default_permission(propose_default_path(c), val)
+    end
+
+    # Gets the default command path which would be given to command _cmd_
+    def propose_default_path(cmd)
+      [name, cmd].compact.join("::")
     end
 
     # return an identifier for this plugin, defaults to a list of the message
@@ -184,11 +196,15 @@ module Plugins
     # register the plugin as a handler for messages prefixed +name+
     # this can be called multiple times for a plugin to handle multiple
     # message prefixes
-    def register(name, opts={})
+    def register(cmd, opts={})
       raise ArgumentError, "Second argument must be a hash!" unless opts.kind_of?(Hash)
-      return if @manager.knows?(name, @botmodule_class)
-      @manager.register(name, @botmodule_class, self)
-      @botmodule_triggers << name unless opts.fetch(:hidden, false)
+      return if @manager.knows?(cmd, @botmodule_class)
+      if opts.has_key?(:auth)
+        @manager.register(self, cmd, opts[:auth])
+      else
+        @manager.register(self, cmd, propose_default_path(cmd))
+      end
+      @botmodule_triggers << cmd unless opts.fetch(:hidden, false)
     end
 
     # default usage method provided as a utility for simple plugins. The
@@ -249,14 +265,16 @@ module Plugins
       return @commandmappers[kl.to_sym].has_key?(name.to_sym)
     end
 
-    # Returns +true+ if _name_ is a known botmodule of class kl
-    def register(name, kl, botmodule)
-      raise TypeError, "Third argument #{botmodule.inspect} is not of class BotModule" unless botmodule.class <= BotModule
-      @commandmappers[kl.to_sym][name.to_sym] = botmodule
+    # Registers botmodule _botmodule_ with command _cmd_ and command path _auth_path_
+    def register(botmodule, cmd, auth_path)
+      raise TypeError, "First argument #{botmodule.inspect} is not of class BotModule" unless botmodule.class <= BotModule
+      kl = botmodule.botmodule_class
+      @commandmappers[kl.to_sym][cmd.to_sym] = {:botmodule => botmodule, :auth => auth_path}
     end
 
-    def add_botmodule(kl, botmodule)
-      raise TypeError, "Second argument #{botmodule.inspect} is not of class BotModule" unless botmodule.class <= BotModule
+    def add_botmodule(botmodule)
+      raise TypeError, "Argument #{botmodule.inspect} is not of class BotModule" unless botmodule.class <= BotModule
+      kl = botmodule.botmodule_class
       raise "#{kl.to_s} #{botmodule.name} already registered!" if @botmodules[kl.to_sym].include?(botmodule)
       @botmodules[kl.to_sym] << botmodule
     end
@@ -488,11 +506,12 @@ module Plugins
         # TODO should also check core_module and plugins
         [core_commands, plugin_commands].each { |pl|
           if(pl.has_key?(key))
+            p = pl[key][:botmodule] 
             begin
-              return pl[key].help(key, params)
+              return p.help(key, params)
             rescue Exception => err
               #rescue TimeoutError, StandardError, NameError, SyntaxError => err
-              error report_error("#{p.botmodule_class} #{plugins[key].name} help() failed:", err)
+              error report_error("#{p.botmodule_class} #{p.name} help() failed:", err)
             end
           else
             return false
@@ -532,14 +551,16 @@ module Plugins
           # FIXME use fetch?
           k = m.plugin.to_sym
           if pl.has_key?(k)
-            p = pl[k]
+            p = pl[k][:botmodule]
+            a = pl[k][:auth]
           else
             p = nil
+            a = nil
           end
           if p
             # TODO This should probably be checked elsewhere
             debug "Checking auth ..."
-            if @bot.auth.allow?(m.plugin, m.source, m.replyto)
+            if @bot.auth.allow?(a, m.source, m.replyto)
               debug "Checking response ..."
               if p.respond_to?("privmsg")
                 begin
@@ -558,9 +579,9 @@ module Plugins
               debug "#{p.botmodule_class} #{p.name} is registered, but #{m.source} isn't allowed to use #{m.plugin} on #{m.replyto}"
             end
           else
-            debug "No #{pl.values.first.botmodule_class} registered #{m.plugin}" unless pl.empty?
+            debug "No #{pl.values.first[:botmodule].botmodule_class} registered #{m.plugin}" unless pl.empty?
           end
-          debug "Finished delegating privmsg with key #{m.plugin}" + ( pl.empty? ? "" : " to #{pl.values.first.botmodule_class}s" )
+          debug "Finished delegating privmsg with key #{m.plugin}" + ( pl.empty? ? "" : " to #{pl.values.first[:botmodule].botmodule_class}s" )
         }
         return false
       rescue Exception => e