# :title: rbot auth management from IRC
#
# Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
-# Copyright:: (C) 2006,2007 Giuseppe Bilotta
-# License:: GPL v2
class AuthModule < CoreBotModule
def load_array(key=:default, forced=false)
debug "loading botusers (#{key}): #{@registry[key].pretty_inspect}"
@bot.auth.load_array(@registry[key], forced) if @registry.has_key?(key)
+ if @bot.auth.botowner.password != @bot.config['auth.password']
+ error "Master password is out of sync!"
+ debug " db password: #{@bot.auth.botowner.password}"
+ debug "conf password: #{@bot.config['auth.password']}"
+ error "Using conf password"
+ @bot.auth.botowner.password = @bot.config['auth.password']
+ end
end
# The permission parameters accept arguments with the following syntax:
def auth_view_perm(m, params)
begin
if params[:user].nil?
- user = get_botusername_for(m.source)
+ user = get_botuser_for(m.source)
return m.reply(_("you are owner, you can do anything")) if user.owner?
else
user = @bot.auth.get_botuser(params[:user].sub(/^all$/,"everyone"))
next if val.perm.empty?
case k
when :*
- str << _("on any channel: ")
+ str << _("on any channel: ").dup
when :"?"
- str << _("in private: ")
+ str << _("in private: ").dup
else
- str << _("on #{k}: ")
+ str << _("on #{k}: ").dup
end
sub = []
val.perm.each { |cmd, bool|
}
end
+ def find_auth(pseudo)
+ k = pseudo.plugin.intern
+ cmds = @bot.plugins.commands
+ auth = nil
+ if cmds.has_key?(k)
+ cmds[k][:botmodule].handler.each do |tmpl|
+ options = tmpl.recognize(pseudo)
+ next if options.kind_of? MessageMapper::Failure
+ auth = tmpl.options[:full_auth_path]
+ break
+ end
+ end
+ return auth
+ end
+
+ def auth_allow_deny(m, p)
+ begin
+ botuser = @bot.auth.get_botuser(p[:user].sub(/^all$/,"everyone"))
+ rescue
+ return m.reply(_("couldn't find botuser %{name}") % {:name => p[:user]})
+ end
+
+ if p[:where].to_s.empty?
+ where = :*
+ else
+ where = m.parse_channel_list(p[:where].to_s).first # should only be one anyway
+ end
+
+ if p.has_key? :auth_path
+ auth_path = p[:auth_path]
+ else
+ # pseudo-message to find the template. The source is ignored, and the
+ # target is set according to where the template should be checked
+ # (public or private)
+ # This might still fail in the case of 'everywhere' for commands there are
+ # really only private
+ case where
+ when :"?"
+ pseudo_target = @bot.myself
+ when :*
+ pseudo_target = m.channel
+ else
+ pseudo_target = m.server.channel(where)
+ end
+
+ pseudo = PrivMessage.new(bot, m.server, m.source, pseudo_target, p[:stuff].to_s)
+
+ auth_path = find_auth(pseudo)
+ end
+ debug auth_path
+
+ if auth_path
+ allow = p[:allow]
+ if @bot.auth.permit?(botuser, auth_path, where)
+ return m.reply(_("%{user} can already do that") % {:user => botuser}) if allow
+ else
+ return m.reply(_("%{user} can't do that already") % {:user => botuser}) if !allow
+ end
+ cmd = PrivMessage.new(bot, m.server, m.source, m.target, "permissions set %{sign}%{path} %{where} for %{user}" % {
+ :path => auth_path,
+ :user => p[:user],
+ :sign => (allow ? '+' : '-'),
+ :where => p[:where].to_s
+ })
+ handle(cmd)
+ else
+ m.reply(_("sorry, %{cmd} doesn't look like a valid command. maybe you misspelled it, or you need to specify it should be in private?") % {
+ :cmd => p[:stuff].to_s
+ })
+ end
+ end
+
+ def auth_allow(m, p)
+ auth_allow_deny(m, p.merge(:allow => true))
+ end
+
+ def auth_deny(m, p)
+ auth_allow_deny(m, p.merge(:allow => false))
+ end
+
def get_botuser_for(user)
@bot.auth.irc_to_botuser(user)
end
get_botuser_for(user).username
end
- def welcome(user)
- _("welcome, %{user}") % {:user => get_botusername_for(user)}
+ def say_welcome(m)
+ m.reply _("welcome, %{user}") % {:user => get_botusername_for(m.source)}
end
def auth_auth(m, params)
begin
case @bot.auth.login(m.source, params[:botuser], params[:password])
when true
- m.reply welcome(m.source)
+ say_welcome(m)
@bot.auth.set_changed
else
m.reply _("sorry, can't do")
if u.default?
m.reply _("I couldn't find anything to let you login automatically")
else
- m.reply welcome(m.source)
+ say_welcome(m)
end
end
return _("user list : lists all the botusers")
when "destroy"
return _("user destroy <botuser> : destroys <botuser>. This function %{highlight}must%{highlight} be called in two steps. On the first call <botuser> is queued for destruction. On the second call, which must be in the form 'user confirm destroy <botuser>', the botuser will be destroyed. If you want to cancel the destruction, issue the command 'user cancel destroy <botuser>'") % {:highlight => Bold}
+ when "export"
+ return _("user export [to <filename>]: exports user data to file <filename> (default: new-auth.users)")
+ when "import"
+ return _("user import [from <filename>]: import user data from file <filename> (default: new-auth.users)")
else
- return _("user topics: show, enable|disable, add|rm netmask, set, reset, tell, create, list, destroy")
+ return _("user topics: show, enable|disable, add|rm netmask, set, reset, tell, create, list, destroy, import, export")
end
when "auth"
- return _("auth <masterpassword>: log in as the bot owner; other commands: login, whoami, permission syntax, permissions [re]set, permissions view, user, meet, hello")
+ return _("auth <masterpassword>: log in as the bot owner; other commands: login, whoami, permissions syntax, permissions [re]set, permissions view, user, meet, hello, allow, deny")
when "meet"
return _("meet <nick> [as <user>]: creates a bot user for nick, calling it user (defaults to the nick itself)")
when "hello"
return _("hello: creates a bot user for the person issuing the command")
+ when "allow"
+ return [
+ _("allow <user> to do <sample command> [<where>]: gives botuser <user> the permissions to execute a command such as the provided sample command"),
+ _("(in private or in channel, according to the optional <where>)."),
+ _("<sample command> should be a full command, not just the command keyword --"),
+ _("correct: allow user to do addquote stuff --"),
+ _("wrong: allow user to do addquote.")
+ ].join(" ")
+ when "deny"
+ return [
+ _("deny <user> from doing <sample command> [<where>]: removes from botuser <user> the permissions to execute a command such as the provided sample command"),
+ _("(in private or in channel, according to the optional <where>)."),
+ _("<sample command> should be a full command, not just the command keyword --"),
+ _("correct: deny user from doing addquote stuff --"),
+ _("wrong: deny user from doing addquote.")
+ ].join(" ")
else
- return _("auth commands: auth, login, whoami, who, permission[s], user, meet, hello")
+ return _("auth commands: auth, login, whoami, who, permission[s], user, meet, hello, allow, deny")
end
end
if !nick
# we are actually responding to a 'hello' command
unless m.botuser.transient?
- m.reply @bot.lang.get('hello_X') % m.botuser
+ m.reply @bot.lang.get('hello_X') % m.botuser, :nick => false
return
end
nick = m.sourcenick
met = @bot.auth.make_permanent(irc_user, buname)
@bot.auth.set_changed
call_event(:botuser,:post_perm, {:irc_user => irc_user, :bot_user => buname})
- m.reply @bot.lang.get('hello_X') % met
+ m.reply @bot.lang.get('hello_X') % met, :nick => false
@bot.say nick, _("you are now registered as %{buname}. I created a random password for you : %{pass} and you can change it at any time by telling me 'user set password <password>' in private" % {
:buname => buname,
:pass => met.password
def auth_list_users(m, params)
# TODO name regexp to filter results
- list = @bot.auth.save_array.inject([]) { |list, x| ['everyone', 'owner'].include?(x[:username]) ? list : list << x[:username] }
+ list = @bot.auth.save_array.inject([]) { |lst, x| ['everyone', 'owner'].include?(x[:username]) ? lst : lst << x[:username] }
if defined?(@destroy_q)
list.map! { |x|
@destroy_q.include?(x) ? x + _(" (queued for destruction)") : x
buname = params[:name]
return m.reply(_("You can't destroy %{user}") % {:user => buname}) if
["everyone", "owner"].include?(buname)
- mod = params[:modifier].to_sym rescue nil
+ mod = params[:modifier].nil_or_empty? ? nil : params[:modifier].to_sym
buser_array = @bot.auth.save_array
buser_hash = buser_array.inject({}) { |h, u|
def auth_export(m, params)
- exportfile = "#{@bot.botclass}/new-auth.users"
+ exportfile = @bot.path "new-auth.users"
what = params[:things]
has_to = what[-2] == "to"
if has_to
- exportfile = "#{@bot.botclass}/#{what[-1]}"
+ exportfile = @bot.path what[-1]
what.slice!(-2,2)
end
def auth_import(m, params)
- importfile = "#{@bot.botclass}/new-auth.users"
+ importfile = @bot.path "new-auth.users"
what = params[:things]
has_from = what[-2] == "from"
if has_from
- importfile = "#{@bot.botclass}/#{what[-1]}"
+ importfile = @bot.path what[-1]
what.slice!(-2,2)
end
auth.map "user *data",
:action => 'auth_manage_user'
+auth.map "allow :user to do *stuff [*where]",
+ :action => 'auth_allow',
+ :requirements => {:where => /^(?:anywhere|everywhere|[io]n \S+)$/},
+ :auth_path => ':edit::other:'
+
+auth.map "deny :user from doing *stuff [*where]",
+ :action => 'auth_deny',
+ :requirements => {:where => /^(?:anywhere|everywhere|[io]n \S+)$/},
+ :auth_path => ':edit::other:'
+
auth.default_auth("user", true)
auth.default_auth("edit::other", false)