3 # globmask:: glob to test with
4 # netmask:: netmask to test against
5 # Compare a netmask with a standard IRC glob, e.g foo!bar@baz.com would
6 # match *!*@baz.com, foo!*@*, *!bar@*, etc.
7 def Irc.netmaskmatch(globmask, netmask)
8 regmask = globmask.gsub(/\*/, ".*?")
9 return true if(netmask =~ /#{regmask}/)
13 # check if a string is an actual IRC hostmask
19 # User-level authentication to allow/disallow access to bot commands based
20 # on hostmask and userlevel.
22 BotConfig.register BotConfigStringValue.new('auth.password',
23 :default => "rbotauth", :wizard => true,
24 :desc => "Your password for maxing your auth with the bot (used to associate new hostmasks with your owner-status etc)")
26 # create a new IrcAuth instance.
27 # bot:: associated bot class
32 if(File.exist?("#{@bot.botclass}/users.rbot"))
33 IO.foreach("#{@bot.botclass}/users.rbot") do |line|
34 if(line =~ /\s*(\d+)\s*(\S+)/)
41 if(File.exist?("#{@bot.botclass}/levels.rbot"))
42 IO.foreach("#{@bot.botclass}/levels.rbot") do |line|
43 if(line =~ /\s*(\d+)\s*(\S+)/)
46 @levels[command] = level
52 # save current users and levels to files.
53 # levels are written to #{botclass}/levels.rbot
54 # users are written to #{botclass}/users.rbot
56 Dir.mkdir("#{@bot.botclass}") if(!File.exist?("#{@bot.botclass}"))
57 File.open("#{@bot.botclass}/users.rbot", "w") do |file|
58 @users.each do |key, value|
59 file.puts "#{value} #{key}"
62 File.open("#{@bot.botclass}/levels.rbot", "w") do |file|
63 @levels.each do |key, value|
64 file.puts "#{value} #{key}"
69 # command:: command user wishes to perform
70 # mask:: hostmask of user
71 # tell:: optional recipient for "insufficient auth" message
73 # returns true if user with hostmask +mask+ is permitted to perform
74 # +command+ optionally pass tell as the target for the "insufficient auth"
75 # message, if the user is not authorised
76 def allow?(command, mask, tell=nil)
77 auth = userlevel(mask)
78 if(auth >= @levels[command])
81 debug "#{mask} is not allowed to perform #{command}"
82 @bot.say tell, "insufficient \"#{command}\" auth (have #{auth}, need #{@levels[command]})" if tell
87 # add user with hostmask matching +mask+ with initial auth level +level+
88 def useradd(mask, level)
94 # mask:: mask of user to remove
95 # remove user with mask +mask+
102 # command:: command to adjust
103 # level:: new auth level for the command
104 # set required auth level of +command+ to +level+
105 def setlevel(command, level)
106 @levels[command] = level
110 # mask:: mask of user
111 # returns the authlevel of user with mask +mask+
112 # finds the matching user which has the highest authlevel (so you can have
113 # a default level of 5 for *!*@*, and yet still give higher levels to
115 # go through hostmask list, find match with _highest_ level (all users
118 @users.each {|user,userlevel|
119 if(Irc.netmaskmatch(user, mask))
120 level = userlevel if userlevel > level
126 # return all currently defined commands (for which auth is required) and
127 # their required authlevels
129 reply = "Current levels are:"
130 @levels.sort.each {|a|
133 reply += " #{key}(#{value})"
138 # return all currently defined users and their authlevels
140 reply = "Current users are:"
141 @users.sort.each {|a|
144 reply += " #{key}(#{value})"
153 return "setlevel <command> <level> => Sets required level for <command> to <level> (private addressing only)"
155 return "useradd <mask> <level> => Add user <mask> at level <level> (private addressing only)"
157 return "userdel <mask> => Remove user <mask> (private addressing only)"
159 return "auth <masterpw> => Recognise your hostmask as bot master (private addressing only)"
161 return "levels => list commands and their required levels (private addressing only)"
163 return "users => list users and their levels (private addressing only)"
165 return "Auth module (User authentication) topics: setlevel, useradd, userdel, auth, levels, users"
171 if(m.address? && m.private?)
173 when (/^setlevel\s+(\S+)\s+(\d+)$/)
174 if(@bot.auth.allow?("auth", m.source, m.replyto))
175 @bot.auth.setlevel($1, $2.to_i)
176 m.reply "level for #$1 set to #$2"
178 when (/^useradd\s+(\S+)\s+(\d+)/)
179 if(@bot.auth.allow?("auth", m.source, m.replyto))
180 @bot.auth.useradd($1, $2.to_i)
181 m.reply "added user #$1 at level #$2"
183 when (/^userdel\s+(\S+)/)
184 if(@bot.auth.allow?("auth", m.source, m.replyto))
185 @bot.auth.userdel($1)
186 m.reply "user #$1 is gone"
188 when (/^auth\s+(\S+)/)
189 if($1 == @bot.config["auth.password"])
190 @bot.auth.useradd(Regexp.escape(m.source), 1000)
191 m.reply "Identified, security level maxed out"
193 m.reply "incorrect password"
196 m.reply @bot.auth.showlevels if(@bot.auth.allow?("config", m.source, m.replyto))
198 m.reply @bot.auth.showusers if(@bot.auth.allow?("config", m.source, m.replyto))