-
Notifications
You must be signed in to change notification settings - Fork 19
Develop:WebService
The web service is a built-in http server that can be used to remotely control or query the bot. It has the built-in ability to dispatch commands and retreive the plaintext response exactly like a IRC user would. Any plugin can easily add their own url routes to respond to requests.
- uses the ruby built-in WEBrick server implementation
- support for ssl, which is recommended if you expose the server to the internet
- easy to use interface for plugins similar to how irc command mapping work
- integrates in the security architecture of rbot, requesting HTTP authentication if necessary
- replaces the DRb remote interface with a more secure and portable solution
Web service configuration values can be modified using the irc interface.
Name | Type/Default | Description |
---|---|---|
webservice.autostart |
Boolean (false) | Whether the web service should be started automatically |
webservice.port |
Integer (7260) | Port on which the web service will listen |
webservice.host |
String (127.0.0.1) | Host the web service will bind on |
webservice.ssl |
Boolean (false) | Whether the web server should use SSL |
webservice.ssl_key |
String (~/.rbot/wskey.pem) | Private key file to use for SSL |
webservice.ssl_cert |
String (~/.rbot/wscert.pem) | Certificate file to use for SSL |
webservice.allow_dispatch |
Boolean (true) | If you want to allow dispatching irc commands |
As you can see the web service does not start by default, you can start/stop it manually or set autostart
:
<user> bot: webservice start
<user> bot: webservice stop
<user> bot: config set webservice.autostart true
If you want to use SSL for the web service you need to create a SSL certificate, to create a self signed certificate using openssl you can use:
openssl req -x509 -newkey rsa:2048 -keyout ~/.rbot/wskey.pem -out ~/.rbot/wscert.pem -days 2000 -nodes
You can also use a web server like nginx as a frontend server.
Requests are handled as the default bot user (without special permissions) you can send a HTTP authentication header to login as a bot user.
This allows you to execute a bot command just like a IRC user would, the configuration value webservice.allow_dispatch
can be used to deactivate this feature.
Query Parameter | Type | |
---|---|---|
command |
string | IRC command (like in a private message to the bot) |
This will respond with a text/plain
response or if a Accept: application/json
header was sent in the request a application/json
json encoded response:
Response Object | Type | |
---|---|---|
reply |
array | Array with strings the bot said in response to the command |
% curl -d 'command=ping' http://127.0.0.1:7268/dispatch
pong
% curl -d 'command=help urban' http://127.0.0.1:7268/dispatch
urban [word] [n]: give the [n]th definition of [word] from urbandictionary.com. urbanday: give the word-of-the-day at urban
% curl -d 'command=urban matrix' http://127.0.0.1:7268/dispatch
matrix (1/7): computer-generated dream world built to keep us under control in order to change a human being into a battery. NO ONE CAN BE TOLD WHAT THE MATRIX IS, YOU HAVE TO SEE IT FOR YOURSELF. k.
% curl -d 'command=imdb the matrix' http://127.0.0.1:7268/dispatch
Matrix (USA | Australia, 1999) : http://www.imdb.com/title/tt0133093/
Ratings: 8.7/10 (969,878 voters). Genre: Action/Sci-Fi. Plot: A computer hacker learns from mysterious rebels about the true nature of his reality and his role in the war against its controllers
Plugins can register url "routes" they want to handle, right now the template syntax for this is not very featureful just supporting arguments /method/:<argument>
that match against the url path. Here is a minimal plugin that handles the url /hello
:
class WSPlugin < Plugin
include WebPlugin
def hello(m, params)
'World!'
end
end
plugin = WSPlugin.new
plugin.web_map '/hello',
:action => :hello
- Plugins need to include the
WebPlugin
mixin to use theweb_map
method to register handled urls. - The
hello
action method needs to be declared as a option parameter inweb_map
. - The
hello
method returns a string that is then encoded as json and sent as a response.
Here is a another example that is using a url path parameter:
class WSPlugin < Plugin
include WebPlugin
def hello(m, params)
name = params[:name]
m.send_html('<h1>Hello, %s!</h1>' % [name])
end
end
plugin = WSPlugin.new
plugin.web_map '/hello/:name',
:action => :hello,
:method => 'GET'
-
:<argument-name>
is used as a optional argument and exposed in the params hash with<argument-name>
as a key. - The
:method
mapping option might be used to constrain a route to a HTTP method. - The
send_html
helper method takes a body and optionally a HTTP status code, that is then sent as atext/html
response. Other helpers includesend_json(body, [status])
,send_plaintext(body, [status])
,send_response(body, [status], [content type])
. - You can also directly access the WEBrick request and response objects in
m.req
(HTTPRequest) andm.res
(HTTPResponse).
% curl http://127.0.0.1:7268/hello/world
<h1>Hello, world!</h1>
If you want to restrict access to the route, you can do something like this: (This works similar to irc command mappings)
class WSPlugin < Plugin
include WebPlugin
def hello(m, params)
'World!'
end
end
plugin = WSPlugin.new
plugin.web_map '/hello',
:action => :hello
plugin.web_map '/restricted',
:action => :hello,
:auth_path => 'private'
plugin.default_auth('private', false)
-
:auth_path
sets a specific auth path for this command. -
default_auth
uses this auth path to restrict access to this action.
If you try to access the route:
% curl -i http://127.0.0.1:7268/restricted
HTTP/1.1 401 Unauthorized
Server: RBot Web Service (http://ruby-rbot.org/)
Content-Type: text/plain
Date: Mon, 12 Jan 2015 10:48:28 GMT
Content-Length: 24
Connection: Keep-Alive
Authentication Required!
You might use the default owner
user to access this, but its not recommended, instead you should create a new bot user and allow it to access the route (in irc):
<user> bot: user create hello swordfish
<user> bot: permissions set +ws::private for hello
In this case "ws::private", ws is determined by the name of the plugin, this can be overwritten. Afterwards you can use basic HTTP auth to login and use the restricted command:
% curl -u hello:swordfish -i http://127.0.0.1:7268/restricted
HTTP/1.1 200 OK
Server: RBot Web Service (http://ruby-rbot.org/)
Content-Type: application/json
Date: Mon, 12 Jan 2015 11:01:25 GMT
Content-Length: 8
Connection: Keep-Alive
"World!"
Our original example used default_auth
to specify a single route that is restricted, but you can also do it the other way around, you specify all routes as restricted and allow the ones you want to make unrestricted:
class WSPlugin < Plugin
include WebPlugin
def hello(m, params)
'World!'
end
end
plugin = WSPlugin.new
plugin.web_map '/hello',
:action => :hello,
:auth_path => 'public'
plugin.web_map '/restricted',
:action => :hello
plugin.default_auth('*', false)
plugin.default_auth('public', true)