Nickserv plugin now defaults to very strict permissions. Only owner can make the...
[rbot] / data / rbot / plugins / nickserv.rb
1 # Automatically lookup nicks in @registry and identify when asked
2 # Takes over proper nick if required and nick is registered
3 # TODO allow custom IDENTIFY and GHOST names
4 # TODO instead of nickserv.wait it would be ideal if we could just
5 # set up "don't send further commands until you receive this particular message"
6
7 class NickServPlugin < Plugin
8   
9   BotConfig.register BotConfigStringValue.new('nickserv.name',
10     :default => "nickserv", :requires_restart => false,
11     :desc => "Name of the nick server (all lowercase)")
12   BotConfig.register BotConfigStringValue.new('nickserv.ident_request',
13     :default => "IDENTIFY", :requires_restart => false,
14     :on_change => Proc.new { |bot, v| bot.plugins.delegate "set_ident_request", v },
15     :desc => "String to look for to see if the nick server is asking us to identify")
16   BotConfig.register BotConfigBooleanValue.new('nickserv.wants_nick',
17     :default => true, :requires_restart => false,
18     :desc => "Set to false if the nick server doesn't expect the nick as a parameter in the identify command")
19   BotConfig.register BotConfigIntegerValue.new('nickserv.wait',
20     :default => 30, :validate => Proc.new { |v| v > 0 }, :requires_restart => false,
21     :desc => "Seconds to wait after sending a message to nickserv, e.g. after ghosting")
22
23   def help(plugin, topic="")
24     case topic
25     when ""
26       return "nickserv plugin: handles nickserv protected IRC nicks. topics password, register, identify, listnicks"
27     when "password"
28       return "nickserv password <nick> <passwd>: remember the password for nick <nick> and use it to identify in future"
29     when "register"
30       return "nickserv register [<password> [<email>]]: register the current nick, choosing a random password unless <password> is supplied - current nick must not already be registered for this to work. Also specify email if required by your services"
31     when "identify"
32       return "nickserv identify: identify with nickserv - shouldn't be needed - bot should identify with nickserv immediately on request - however this could be useful after splits or service disruptions, or when you just set the password for the current nick"
33     when "listnicks"
34       return "nickserv listnicks: lists nicknames and associated password the bot knows about - you will need config level auth access to do this one and it will reply by privmsg only"
35     end
36   end
37   
38   def genpasswd
39     # generate a random password
40     passwd = ""
41     8.times do
42       passwd += (rand(26) + (rand(2) == 0 ? 65 : 97) ).chr
43     end
44     return passwd
45   end
46
47   def set_ident_request(val)
48     @ident_request = Regexp.new(val)
49   end
50
51   def initialize
52     super
53     # this plugin only wants to store strings!
54     class << @registry
55       def store(val)
56         val
57       end
58       def restore(val)
59         val
60       end
61     end
62     set_ident_request(@bot.config['nickserv.ident_request'])
63   end
64
65   def password(m, params)
66     @registry[params[:nick]] = params[:passwd]
67     m.okay
68   end
69
70   def nick_register(m, params)
71     passwd = params[:passwd] ? params[:passwd] : genpasswd
72     message = "REGISTER #{passwd}"
73     message += " #{params[:email]}" if params[:email]
74     @bot.sendmsg "PRIVMSG", @bot.config['nickserv.name'], message
75     @registry[@bot.nick] = passwd
76     m.okay
77   end
78
79   def listnicks(m, params)
80     if @registry.length > 0
81       @registry.each {|k,v|
82         @bot.say m.sourcenick, "#{k} => #{v}"
83       }
84     else
85       m.reply "none known"
86     end
87   end
88
89   def do_identify(nick=@bot.nick)
90     if @registry.has_key?(nick)
91       if @bot.config['nickserv.wants_nick']
92         @bot.sendmsg "PRIVMSG", @bot.config['nickserv.name'], "IDENTIFY #{nick} #{@registry[nick]}"
93       else
94         if nick == @bot.nick
95           @bot.sendmsg "PRIVMSG", @bot.config['nickserv.name'], "IDENTIFY #{@registry[nick]}"
96         else
97           # We cannot identify for different nicks if we can't use the nickname ...
98           return false
99         end
100       end
101       return true
102     end
103     return false
104   end
105
106   def identify(m, params)
107     if do_identify
108       m.okay
109     else
110       m.reply "I dunno the nickserv password for the nickname #{@bot.nick} :("
111     end
112   end
113   
114   def connect
115     do_identify
116   end
117   
118   def nicktaken(nick)
119     if @registry.has_key?(nick)
120       @bot.sendmsg "PRIVMSG", @bot.config['nickserv.name'], "GHOST #{nick} #{@registry[nick]}"
121       if do_identify nick
122         sleep @bot.config['nickserv.wait']
123         @bot.nickchg nick
124         # We need to wait after changing nick, otherwise the server
125         # might refuse to execute further commangs, e.g. subsequent JOIN
126         # commands until the nick has changed.
127         sleep @bot.config['nickserv.wait']
128       else
129         debug "Failed to identify for nick #{nick}, cannot take over"
130       end
131     end
132   end
133
134   def listen(m)
135     return unless(m.kind_of? NoticeMessage)
136
137     if (m.sourcenick == @bot.config['nickserv.name'] && m.message =~ @ident_request)
138       debug "nickserv asked us to identify for nick #{@bot.nick}"
139       do_identify
140     end
141   end
142
143 end
144 plugin = NickServPlugin.new
145 plugin.map 'nickserv password :nick :passwd', :action => "password"
146 plugin.map 'nickserv register :passwd :email', :action => 'nick_register',
147            :defaults => {:passwd => false, :email => false}
148 plugin.map 'nickserv listnicks', :action => "listnicks"
149 plugin.map 'nickserv identify', :action => "identify"
150
151 plugin.default_auth('*', false)
152