12 local httpserver = require "net.httpserver"; |
12 local httpserver = require "net.httpserver"; |
13 local st = require "util.stanza"; |
13 local st = require "util.stanza"; |
14 local pcall = pcall; |
14 local pcall = pcall; |
15 local unpack = unpack; |
15 local unpack = unpack; |
16 local tostring = tostring; |
16 local tostring = tostring; |
|
17 local is_admin = require "core.usermanager".is_admin; |
|
18 local jid_split = require "util.jid".split; |
|
19 local b64_decode = require "util.encodings".base64.decode; |
|
20 local get_method = require "core.objectmanager".get_object; |
|
21 local validate_credentials = require "core.usermanager".validate_credentials; |
17 |
22 |
18 local translate_request = require "util.xmlrpc".translate_request; |
23 local translate_request = require "util.xmlrpc".translate_request; |
19 local create_response = require "util.xmlrpc".create_response; |
24 local create_response = require "util.xmlrpc".create_response; |
20 local create_error_response = require "util.xmlrpc".create_error_response; |
25 local create_error_response = require "util.xmlrpc".create_error_response; |
21 |
26 |
58 end |
63 end |
59 end |
64 end |
60 return stanza.tags[1]; |
65 return stanza.tags[1]; |
61 end |
66 end |
62 |
67 |
63 --[[local function get_method(method) |
|
64 return function(...) |
|
65 return {method = method; args = {...}}; |
|
66 end |
|
67 end]] |
|
68 local get_method = require "core.objectmanager".get_object; |
|
69 |
|
70 local function handle_xmlrpc_request(method, args) |
68 local function handle_xmlrpc_request(method, args) |
71 method = get_method(method); |
69 method = get_method(method); |
72 if not method then return create_error_response(404, "method not found"); end |
70 if not method then return create_error_response(404, "method not found"); end |
73 args = args or {}; |
71 args = args or {}; |
74 local success, result = pcall(method, unpack(args)); |
72 local success, result = pcall(method, unpack(args)); |
84 |
82 |
85 local function handle_xmpp_request(origin, stanza) |
83 local function handle_xmpp_request(origin, stanza) |
86 local query = stanza.tags[1]; |
84 local query = stanza.tags[1]; |
87 if query.name == "query" then |
85 if query.name == "query" then |
88 if #query.tags == 1 then |
86 if #query.tags == 1 then |
89 local success, method, args = pcall(translate_request, query.tags[1]); |
87 if is_admin(stanza.attr.from) then |
90 if success then |
88 local success, method, args = pcall(translate_request, query.tags[1]); |
91 local result = handle_xmlrpc_request(method, args); |
89 if success then |
92 origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:rpc'}):add_child(result)); |
90 local result = handle_xmlrpc_request(method, args); |
93 else |
91 origin.send(st.reply(stanza):tag('query', {xmlns='jabber:iq:rpc'}):add_child(result)); |
94 origin.send(st.error_reply(stanza, "modify", "bad-request", method)); |
92 else |
95 end |
93 origin.send(st.error_reply(stanza, "modify", "bad-request", method)); |
96 else |
94 end |
97 origin.send(st.error_reply(stanza, "modify", "bad-request", "No content in XML-RPC request")); |
95 else origin.send(st.error_reply(stanza, "auth", "forbidden", "No content in XML-RPC request")); end |
98 end |
96 else origin.send(st.error_reply(stanza, "modify", "bad-request", "No content in XML-RPC request")); end |
99 else |
97 else origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); end |
100 origin.send(st.error_reply(stanza, "cancel", "service-unavailable")); |
|
101 end |
|
102 end |
98 end |
103 module:add_iq_handler({"c2s", "s2sin"}, "jabber:iq:rpc", handle_xmpp_request); |
99 module:add_iq_handler({"c2s", "s2sin"}, "jabber:iq:rpc", handle_xmpp_request); |
104 module:add_feature("jabber:iq:rpc"); |
100 module:add_feature("jabber:iq:rpc"); |
|
101 -- TODO add <identity category='automation' type='rpc'/> to disco replies |
105 |
102 |
106 local default_headers = { ["Content-Type"] = "text/xml" }; |
103 local default_headers = { ['Content-Type'] = 'text/xml' }; |
|
104 local unauthorized_response = { status = '401 UNAUTHORIZED', headers = {['Content-Type']='text/html', ['WWW-Authenticate']='Basic realm="WallyWorld"'}; body = "<html><body>Authentication required</body></html>"; }; |
107 local function handle_http_request(method, body, request) |
105 local function handle_http_request(method, body, request) |
|
106 -- authenticate user |
|
107 local username, password = b64_decode(request['authorization'] or ''):gmatch('([^:]*):(.*)')(); -- TODO digest auth |
|
108 local node, host = jid_split(username); |
|
109 if not validate_credentials(host, node, password) and is_admin(username) then |
|
110 return unauthorized_response; |
|
111 end |
|
112 -- parse request |
108 local stanza = body and parse_xml(body); |
113 local stanza = body and parse_xml(body); |
109 if (not stanza) or request.method ~= "POST" then |
114 if (not stanza) or request.method ~= "POST" then |
110 return "<html><body>You really don't look like an XML-RPC client to me... what do you want?</body></html>"; |
115 return "<html><body>You really don't look like an XML-RPC client to me... what do you want?</body></html>"; |
111 end |
116 end |
|
117 -- execute request |
112 local success, method, args = pcall(translate_request, stanza); |
118 local success, method, args = pcall(translate_request, stanza); |
113 if success then |
119 if success then |
114 return { headers = default_headers; body = tostring(handle_xmlrpc_request(method, args)) }; |
120 return { headers = default_headers; body = tostring(handle_xmlrpc_request(method, args)) }; |
115 end |
121 end |
116 return "<html><body>Error parsing XML-RPC request: "..tostring(method).."</body></html>"; |
122 return "<html><body>Error parsing XML-RPC request: "..tostring(method).."</body></html>"; |