summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/rbot/botuser.rb86
-rw-r--r--lib/rbot/config.rb33
-rw-r--r--lib/rbot/core/core.rb61
-rw-r--r--lib/rbot/ircbot.rb1
-rw-r--r--lib/rbot/messagemapper.rb46
-rw-r--r--lib/rbot/plugins.rb71
6 files changed, 206 insertions, 92 deletions
diff --git a/lib/rbot/botuser.rb b/lib/rbot/botuser.rb
index 98408a0d..6c84a93b 100644
--- a/lib/rbot/botuser.rb
+++ b/lib/rbot/botuser.rb
@@ -252,13 +252,29 @@ module Irc
@perm = {}
end
+ # Inspection simply inspects the internal hash
+ def inspect
+ @perm.inspect
+ end
+
# Sets the permission for command _cmd_ to _val_,
- # creating intermediate permissions if needed.
#
def set_permission(cmd, val)
- raise TypeError, "#{val.inspect} must be true or false" unless [true,false].include?(val)
Irc::error_if_not_command(cmd)
- @perm[cmd.command] = val
+ case val
+ when true, false
+ @perm[cmd.command] = val
+ when nil
+ @perm.delete(cmd.command)
+ else
+ raise TypeError, "#{val.inspect} must be true or false" unless [true,false].include?(val)
+ end
+ end
+
+ # Resets the permission for command _cmd_
+ #
+ def reset_permission(cmd)
+ set_permission(cmd, nil)
end
# Tells if command _cmd_ is permitted. We do this by returning
@@ -313,6 +329,12 @@ module Irc
end
end
+ # Resets the permission for command _cmd_ on channel _chan_
+ #
+ def reset_permission(cmd, chan ="*")
+ set_permission(cmd, nil, chan)
+ end
+
# Checks if BotUser is allowed to do something on channel _chan_,
# or on all channels if _chan_ is nil
#
@@ -415,17 +437,27 @@ module Irc
end
- # This is the anonymous BotUser: it's used for all users which haven't
+ # This is the default BotUser: it's used for all users which haven't
# identified with the bot
#
- class AnonBotUserClass < BotUser
+ class DefaultBotUserClass < BotUser
include Singleton
def initialize
- super("anonymous")
+ super("everyone")
+ @default_perm = PermissionSet.new
end
private :login, :add_netmask, :delete_netmask
- # Anon knows everybody
+ # Sets the default permission for the default user (i.e. the ones
+ # set by the BotModule writers) on all channels
+ #
+ def set_default_permission(cmd, val)
+ @default_perm.set_permission(Command.new(cmd), val)
+ debug "Default permissions now:\n#{@default_perm.inspect}"
+ end
+
+ # default knows everybody
+ #
def knows?(user)
Irc::error_if_not_user(user)
return true
@@ -436,12 +468,24 @@ module Irc
super
add_netmask("*!*@*")
end
+
+ # DefaultBotUser will check the default_perm after checking
+ # the global ones
+ # or on all channels if _chan_ is nil
+ #
+ def permit?(cmd, chan=nil)
+ allow = super(cmd, chan)
+ if allow.nil? && chan.nil?
+ allow = @default_perm.permit?(cmd)
+ end
+ return allow
+ end
end
- # Returns the only instance of AnonBotUserClass
+ # Returns the only instance of DefaultBotUserClass
#
- def Auth.anonbotuser
- return AnonBotUserClass.instance
+ def Auth.defaultbotuser
+ return DefaultBotUserClass.instance
end
# This is the BotOwner: he can do everything
@@ -470,10 +514,15 @@ module Irc
class AuthManagerClass
include Singleton
+ attr_reader :everyone
+ attr_reader :botowner
+
# The instance manages two <code>Hash</code>es: one that maps
# <code>Irc::User</code>s onto <code>BotUser</code>s, and the other that maps
# usernames onto <code>BotUser</code>
def initialize
+ @everyone = Auth::defaultbotuser
+ @botowner = Auth::botowner
bot_associate(nil)
end
@@ -494,7 +543,9 @@ module Irc
def reset_hashes
@botusers = Hash.new
@allbotusers = Hash.new
- [Auth::anonbotuser, Auth::botowner].each { |x| @allbotusers[x.username.to_sym] = x }
+ [everyone, botowner].each { |x|
+ @allbotusers[x.username.to_sym] = x
+ }
end
# load botlist from userfile
@@ -524,7 +575,8 @@ module Irc
# Maps <code>Irc::User</code> to BotUser
def irc_to_botuser(ircuser)
Irc::error_if_not_user(ircuser)
- return @botusers[ircuser] || Auth::anonbotuser
+ # TODO check netmasks
+ return @botusers[ircuser] || everyone
end
# creates a new BotUser
@@ -569,8 +621,8 @@ module Irc
# is returned:
# * associated BotUser on _chan_
# * associated BotUser on all channels
- # * anonbotuser on _chan_
- # * anonbotuser on all channels
+ # * everyone on _chan_
+ # * everyone on all channels
#
def permit?(user, cmdtxt, chan=nil)
botuser = irc_to_botuser(user)
@@ -590,10 +642,10 @@ module Irc
allow = botuser.permit?(cmd)
return allow unless allow.nil?
- unless botuser == Auth::anonbotuser
- allow = Auth::anonbotuser.permit?(cmd, chan) if chan
+ unless botuser == everyone
+ allow = everyone.permit?(cmd, chan) if chan
return allow unless allow.nil?
- allow = Auth::anonbotuser.permit?(cmd)
+ allow = everyone.permit?(cmd)
return allow unless allow.nil?
end
diff --git a/lib/rbot/config.rb b/lib/rbot/config.rb
index ab16c442..f91cfa70 100644
--- a/lib/rbot/config.rb
+++ b/lib/rbot/config.rb
@@ -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"))
diff --git a/lib/rbot/core/core.rb b/lib/rbot/core/core.rb
index fcf5ac3a..55da1a7d 100644
--- a/lib/rbot/core/core.rb
+++ b/lib/rbot/core/core.rb
@@ -165,77 +165,78 @@ core = Core.new
core.map "quit *msg",
:action => 'bot_quit',
:defaults => { :msg => nil },
- :auth => 'core::quit::quit'
+ :auth_path => 'quit'
core.map "restart *msg",
:action => 'bot_restart',
:defaults => { :msg => nil },
- :auth => 'core::quit::restart'
+ :auth_path => 'quit'
core.map "save",
:action => 'bot_save',
- :auth => 'core::config::save'
+ :auth_path => 'config'
core.map "rescan",
:action => 'bot_rescan',
- :auth => 'core::config::rescan'
+ :auth_path => 'config'
core.map "nick :nick",
:action => 'bot_nick',
- :auth => 'core::config::nick'
+ :auth_path => 'config'
core.map "status",
:action => 'bot_status',
- :auth => 'core::config::show::status'
+ :auth_path => 'config::show'
# TODO see above
#
# core.map "registry stats",
# :action => 'bot_reg_stat',
- # :auth => 'core::config::show::registry'
+ # :auth_path => 'config::show'
core.map "version",
:action => 'bot_version',
- :auth => 'core::config::show::version'
+ :auth_path => 'config::show'
core.map "quiet",
:action => 'bot_quiet',
- :auth => 'core::talk::quiet'
+ :auth_path => 'talk::set'
core.map "quiet in :chan",
:action => 'bot_quiet',
- :auth => 'core::talk::quiet'
+ :auth_path => 'talk::set'
core.map "talk",
:action => 'bot_talk',
- :auth => 'core::talk::talk'
+ :auth_path => 'talk::set'
core.map "quiet in :chan",
:action => 'bot_quiet',
- :auth => 'core::talk::talk'
+ :auth_path => 'talk::set'
+
+core.map "say :where *what",
+ :action => 'bot_say',
+ :auth_path => 'talk::do'
+core.map "action :where *what",
+ :action => 'bot_action',
+ :auth_path => 'talk::do'
+core.map "mode :where :what *who",
+ :action => 'bot_mode',
+ :auth_path => 'talk::do'
core.map "join :chan :pass",
:action => 'bot_join',
:defaults => {:pass => nil},
- :auth => 'core::movearound::join'
+ :auth_path => 'move'
core.map "part :chan",
:action => 'bot_part',
:defaults => {:chan => nil},
- :auth => 'core::movearound::part'
+ :auth_path => 'move'
core.map "hide",
:action => 'bot_hide',
- :auth => 'core::movearound::hide'
-
-core.map "say :where *what",
- :action => 'bot_say',
- :auth => 'core::talk::say'
-core.map "action :where *what",
- :action => 'bot_action',
- :auth => 'core::talk::act'
-core.map "mode :where :what *who",
- :action => 'bot_mode',
- :auth => 'core::talk::mode'
+ :auth_path => 'move'
core.map "ping",
- :action => 'bot_ping'
+ :action => 'bot_ping',
+ :auth_path => '!ping!'
core.map "help *topic",
:action => 'bot_help',
- :default => { :topic => [""] }
+ :default => { :topic => [""] },
+ :auth_path => '!help!'
# TODO the first line should probably go to the auth module?
#
-core.default_auth('*', true)
-core.default_auth('core', false)
-core.default_auth('core::config::show', true)
+core.default_auth('*', false)
+core.default_auth('config::show', true)
diff --git a/lib/rbot/ircbot.rb b/lib/rbot/ircbot.rb
index f1d9e127..d96e0368 100644
--- a/lib/rbot/ircbot.rb
+++ b/lib/rbot/ircbot.rb
@@ -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
diff --git a/lib/rbot/messagemapper.rb b/lib/rbot/messagemapper.rb
index 200c676d..e4ad60b0 100644
--- a/lib/rbot/messagemapper.rb
+++ b/lib/rbot/messagemapper.rb
@@ -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 == ""
diff --git a/lib/rbot/plugins.rb b/lib/rbot/plugins.rb
index 31fb1134..7e98b1b3 100644
--- a/lib/rbot/plugins.rb
+++ b/lib/rbot/plugins.rb
@@ -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