]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - lib/rbot/core/webservice.rb
[webservice] dispatch command in post aswell
[user/henk/code/ruby/rbot.git] / lib / rbot / core / webservice.rb
1 #-- vim:sw=2:et
2 #++
3 #
4 # :title: Web service for bot
5 #
6 # Author:: Matthias Hecker (apoc@geekosphere.org)
7 #
8 # HTTP(S)/json based web service for remote controlling the bot,
9 # similar to remote but much more portable.
10 #
11 # For more info/documentation:
12 # https://github.com/4poc/rbot/wiki/Web-Service
13 #
14
15 require 'webrick'
16 require 'webrick/https'
17 require 'openssl'
18 require 'cgi'
19
20 class ::WebServiceUser < Irc::User
21   def initialize(str, botuser, opts={})
22     super(str, opts)
23     @botuser = botuser
24     @response = []
25   end
26   attr_reader :botuser
27   attr_accessor :response
28 end
29
30 class DispatchServlet < WEBrick::HTTPServlet::AbstractServlet
31   def initialize(server, bot)
32     super server
33     @bot = bot
34   end
35
36   def do_POST(req, res)
37     # NOTE: still wip.
38     uri = req.path_info
39     post = CGI::parse(req.body)
40     ip = req.peeraddr[3]
41
42     if post['command']
43       command = post['command'].first
44     else
45       command = uri.gsub('/', ' ').strip
46     end
47
48     username = post['username'].first
49     password = post['password'].first
50
51     botuser = @bot.auth.get_botuser(username)
52     netmask = '%s!%s@%s' % [botuser.username, botuser.username, ip]
53
54     if not botuser or botuser.password != password
55       raise 'Permission Denied'
56     end
57
58     ws_user = WebServiceUser.new(netmask, botuser)
59     message = Irc::PrivMessage.new(@bot, nil, ws_user, @bot.myself, command)
60
61     @bot.plugins.irc_delegate('privmsg', message)
62
63     res.status = 200
64     res['Content-Type'] = 'text/plain'
65     res.body = ws_user.response.join("\n") + "\n"
66   end
67 end
68
69 class WebServiceModule < CoreBotModule
70
71   Config.register Config::BooleanValue.new('webservice.autostart',
72     :default => false,
73     :requires_rescan => true,
74     :desc => 'Whether the web service should be started automatically')
75
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')
80
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')
85
86   Config.register Config::BooleanValue.new('webservice.ssl',
87     :default => false,
88     :requires_rescan => true,
89     :desc => 'Whether the web server should use SSL (recommended!)')
90
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')
95
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')
100
101   def initialize
102     super
103     @port = @bot.config['webservice.port']
104     @host = @bot.config['webservice.host']
105     @server = nil
106     begin
107       start_service if @bot.config['webservice.autostart']
108     rescue => e
109       error "couldn't start web service provider: #{e.inspect}"
110     end
111   end
112
113   def start_service
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'
122         opts.merge!({
123           :SSLCertificate => OpenSSL::X509::Certificate.new(File.read(cert)),
124           :SSLPrivateKey => OpenSSL::PKey::RSA.new(File.read(key))
125         })
126       else
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.
131       end
132     end
133     @server = WEBrick::HTTPServer.new(opts)
134     debug 'webservice started: ' + opts.inspect
135     @server.mount('/dispatch', DispatchServlet, @bot)
136     Thread.new { @server.start }
137   end
138
139   def stop_service
140     @server.shutdown if @server
141     @server = nil
142   end
143
144   def cleanup
145     stop_service
146     super
147   end
148
149   def handle_start(m, params)
150     s = ''
151     if @server
152       s << 'web service already running'
153     else
154       begin
155         start_service
156         s << 'web service started'
157       rescue
158         s << 'unable to start web service, error: ' + $!.to_s
159       end
160     end
161     m.reply s
162   end
163
164 end
165
166 webservice = WebServiceModule.new
167
168 webservice.map 'webservice start',
169   :action => 'handle_start',
170   :auth_path => ':manage:'
171
172 webservice.map 'webservice stop',
173   :action => 'handle_stop',
174   :auth_path => ':manage:'
175
176 webservice.default_auth('*', false)
177