We extend the ManagerClass to handle remote logins
This is the ManagerClass singleton, used to manage Irc::User/Irc::Bot::Auth::BotUser connections and everything
The instance manages two Hash
es: one that maps
Irc::User
s onto BotUser
s, and the other that maps
usernames onto BotUser
# File lib/rbot/botuser.rb, line 662 def initialize @everyone = Auth::defaultbotuser @botowner = Auth::botowner bot_associate(nil) end
Checks if command cmd is allowed to User user on chan, optionally telling if the user is authorized
# File lib/rbot/botuser.rb, line 907 def allow?(cmdtxt, user, chan=nil) if permit?(user, cmdtxt, chan) return true else # cmds = cmdtxt.split('::') # @bot.say chan, "you don't have #{cmds.last} (#{cmds.first}) permissions here" if chan @bot.say chan, _("%{user}, you don't have '%{command}' permissions here") % {:user=>user, :command=>cmdtxt} if chan return false end end
Tries to auto-login Irc::User user by looking at the known botusers that allow autologin and trying to login without a password
# File lib/rbot/botuser.rb, line 783 def autologin(user) ircuser = user.to_irc_user debug "Trying to autologin #{ircuser}" return @botusers[ircuser] if @botusers.has_key?(ircuser) bu = maskdb.find(ircuser) if bu debug "trying #{bu}" bu.login(ircuser) or raise '...what?!' @botusers[ircuser] = bu return bu end # Finally, create a transient if we're set to allow it if @bot.config['auth.autouser'] bu = create_transient_botuser(ircuser) @botusers[ircuser] = bu return bu end return everyone end
# File lib/rbot/botuser.rb, line 668 def bot_associate(bot) raise "Cannot associate with a new bot! Save first" if defined?(@has_changes) && @has_changes reset_hashes # Associated bot @bot = bot # This variable is set to true when there have been changes # to the botusers list, so that we know when to save @has_changes = false end
# File lib/rbot/botuser.rb, line 689 def changed? @has_changes end
creates a new BotUser
# File lib/rbot/botuser.rb, line 741 def create_botuser(name, password=nil) n = BotUser.sanitize_username(name) k = n.to_sym raise "botuser #{n} exists" if include?(k) bu = BotUser.new(n) bu.password = password @allbotusers[k] = bu return bu end
Creates a new transient BotUser associated with Irc::User user, automatically logging him in. Note that transient botuser creation can fail, typically if we don’t have the complete user netmask (e.g. for messages coming in from a linkbot)
# File lib/rbot/botuser.rb, line 808 def create_transient_botuser(user) ircuser = user.to_irc_user bu = everyone begin bu = BotUser.new(ircuser, :transient => true, :masks => ircuser) bu.login(ircuser) rescue warning "failed to create transient for #{user}" error $! end return bu end
returns the botuser with name name
# File lib/rbot/botuser.rb, line 752 def get_botuser(name) @allbotusers.fetch(BotUser.sanitize_username(name).to_sym) end
checks if we know about a certain BotUser username
# File lib/rbot/botuser.rb, line 729 def include?(botusername) @allbotusers.has_key?(botusername.to_sym) end
Maps Irc::User
to BotUser
# File lib/rbot/botuser.rb, line 734 def irc_to_botuser(ircuser) logged = @botusers[ircuser.to_irc_user] return logged if logged return autologin(ircuser) end
# File lib/rbot/botuser.rb, line 703 def load_array(ary, forced) unless ary warning "Tried to load an empty array" return end raise "Won't load with unsaved changes" if @has_changes and not forced reset_hashes ary.each { |x| raise TypeError, "#{x} should be a Hash" unless x.kind_of?(Hash) u = x[:username] unless include?(u) create_botuser(u) end get_botuser(u).from_hash(x) get_botuser(u).transient = false } @has_changes=false end
Logs Irc::User user in to BotUser botusername with password pwd
raises an error if botusername is not a known BotUser username
It is possible to autologin by Netmask, on request
# File lib/rbot/botuser.rb, line 762 def login(user, botusername, pwd=nil) ircuser = user.to_irc_user n = BotUser.sanitize_username(botusername) k = n.to_sym raise "No such BotUser #{n}" unless include?(k) if @botusers.has_key?(ircuser) return true if @botusers[ircuser].username == n # TODO # @botusers[ircuser].logout(ircuser) end bu = @allbotusers[k] if bu.login(ircuser, pwd) @botusers[ircuser] = bu return true end return false end
Logs out any Irc::User matching Irc::Netmask m and logged in to a transient BotUser
# File lib/rbot/botuser.rb, line 824 def logout_transients(m) debug "to check: #{@botusers.keys.join ' '}" @botusers.keys.each do |iu| debug "checking #{iu.fullform} against #{m.fullform}" bu = @botusers[iu] bu.transient? or next iu.matches?(m) or next @botusers.delete(iu).autologin = false end end
Makes transient BotUser user into a permanent BotUser named name; if user is an Irc::User, act on the transient BotUser (if any) it’s logged in as
# File lib/rbot/botuser.rb, line 839 def make_permanent(user, name) buname = BotUser.sanitize_username(name) # TODO merge BotUser instead? raise "there's already a BotUser called #{name}" if include?(buname) tuser = nil case user when String, Irc::User tuser = irc_to_botuser(user) when BotUser tuser = user else raise TypeError, "sorry, don't know how to make #{user.class} into a permanent BotUser" end return nil unless tuser raise TypeError, "#{tuser} is not transient" unless tuser.transient? tuser.make_permanent(buname) @allbotusers[tuser.username.to_sym] = tuser return tuser end
Checks if User user can do cmd on chan.
Permission are checked in this order, until a true or false is returned:
associated BotUser on chan
associated BotUser on all channels
everyone on chan
everyone on all channels
# File lib/rbot/botuser.rb, line 871 def permit?(user, cmdtxt, channel=nil) if user.class <= BotUser botuser = user else botuser = irc_to_botuser(user) end cmd = cmdtxt.to_irc_auth_command chan = channel case chan when User chan = "?" when Channel chan = chan.name end allow = nil allow = botuser.permit?(cmd, chan) if chan return allow unless allow.nil? allow = botuser.permit?(cmd) return allow unless allow.nil? unless botuser == everyone allow = everyone.permit?(cmd, chan) if chan return allow unless allow.nil? allow = everyone.permit?(cmd) return allow unless allow.nil? end raise "Could not check permission for user #{user.inspect} to run #{cmdtxt.inspect} on #{chan.inspect}" end
Creates a session id when the given password matches the given botusername
# File lib/rbot/core/remote.rb, line 46 def remote_login(botusername, pwd) @remote_users = Hash.new unless defined? @remote_users n = BotUser.sanitize_username(botusername) k = n.to_sym raise "No such BotUser #{n}" unless include?(k) bu = @allbotusers[k] if bu.remote_login(pwd) raise "ran out of session ids!" if @remote_users.length == MAX_SESSION_ID session_id = rand(MAX_SESSION_ID) while @remote_users.has_key?(session_id) session_id = rand(MAX_SESSION_ID) end @remote_users[session_id] = bu return session_id end return false end
Returns the botuser associated with the given session id
# File lib/rbot/core/remote.rb, line 65 def remote_user(session_id) return everyone unless session_id return nil unless defined? @remote_users if @remote_users.has_key?(session_id) return @remote_users[session_id] else return nil end end
# File lib/rbot/botuser.rb, line 685 def reset_changed @has_changes = false end
resets the hashes
# File lib/rbot/botuser.rb, line 694 def reset_hashes @botusers = Hash.new @maskdb = NetmaskDb.new @allbotusers = Hash.new [everyone, botowner].each do |x| @allbotusers[x.username.to_sym] = x end end
# File lib/rbot/botuser.rb, line 722 def save_array @allbotusers.values.map { |x| x.transient? ? nil : x.to_hash }.compact end
# File lib/rbot/botuser.rb, line 681 def set_changed @has_changes = true end