4 # :title: Web service for bot
6 # Author:: Matthias Hecker (apoc@geekosphere.org)
8 # HTTP(S)/json based web service for remote controlling the bot,
9 # similar to remote but much more portable.
11 # For more info/documentation:
12 # https://github.com/4poc/rbot/wiki/Web-Service
16 require 'webrick/https'
20 class ::WebServiceUser < Irc::User
21 def initialize(str, botuser, opts={})
27 attr_accessor :response
30 class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
31 def initialize(server, bot)
39 post = CGI::parse(req.body)
43 command = post['command'].first
45 command = uri.gsub('/', ' ').strip
48 username = post['username'].first
49 password = post['password'].first
51 botuser = @bot.auth.get_botuser(username)
52 netmask = '%s!%s@%s' % [botuser.username, botuser.username, ip]
54 if not botuser or botuser.password != password
55 raise 'Permission Denied'
58 ws_user = WebServiceUser.new(netmask, botuser)
59 message = Irc::PrivMessage.new(@bot, nil, ws_user, @bot.myself, command)
61 @bot.plugins.irc_delegate('privmsg', message)
64 res['Content-Type'] = 'text/plain'
65 res.body = ws_user.response.join("\n") + "\n"
69 class WebServiceModule < CoreBotModule
71 Config.register Config::BooleanValue.new('webservice.autostart',
73 :requires_rescan => true,
74 :desc => 'Whether the web service should be started automatically')
76 Config.register Config::IntegerValue.new('webservice.port',
77 :default => 7260, # that's 'rbot'
78 :requires_rescan => true,
79 :desc => 'Port on which the web service will listen')
81 Config.register Config::StringValue.new('webservice.host',
82 :default => '127.0.0.1',
83 :requires_rescan => true,
84 :desc => 'Host the web service will bind on')
86 Config.register Config::BooleanValue.new('webservice.ssl',
88 :requires_rescan => true,
89 :desc => 'Whether the web server should use SSL (recommended!)')
91 Config.register Config::StringValue.new('webservice.ssl_key',
92 :default => '~/.rbot/wskey.pem',
93 :requires_rescan => true,
94 :desc => 'Private key file to use for SSL')
96 Config.register Config::StringValue.new('webservice.ssl_cert',
97 :default => '~/.rbot/wscert.pem',
98 :requires_rescan => true,
99 :desc => 'Certificate file to use for SSL')
103 @port = @bot.config['webservice.port']
104 @host = @bot.config['webservice.host']
107 start_service if @bot.config['webservice.autostart']
109 error "couldn't start web service provider: #{e.inspect}"
114 raise "Remote service provider already running" if @server
115 opts = {:BindAddress => @host, :Port => @port}
116 if @bot.config['webservice.ssl']
117 opts.merge! :SSLEnable => true
118 cert = File.expand_path @bot.config['webservice.ssl_cert']
119 key = File.expand_path @bot.config['webservice.ssl_key']
120 if File.exists? cert and File.exists? key
121 debug 'using ssl certificate files'
123 :SSLCertificate => OpenSSL::X509::Certificate.new(File.read(cert)),
124 :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read(key))
127 debug 'using on-the-fly generated ssl certs'
128 opts.merge! :SSLCertName => [ %w[CN localhost] ]
129 # the problem with this is that it will always use the same
130 # serial number which makes this feature pretty much useless.
133 @server = WEBrick::HTTPServer.new(opts)
134 debug 'webservice started: ' + opts.inspect
135 @server.mount('/dispatch', DispatchServlet, @bot)
136 Thread.new { @server.start }
140 @server.shutdown if @server
149 def handle_start(m, params)
152 s << 'web service already running'
156 s << 'web service started'
158 s << 'unable to start web service, error: ' + $!.to_s
166 webservice = WebServiceModule.new
168 webservice.map 'webservice start',
169 :action => 'handle_start',
170 :auth_path => ':manage:'
172 webservice.map 'webservice stop',
173 :action => 'handle_stop',
174 :auth_path => ':manage:'
176 webservice.default_auth('*', false)