|
1 -- RESTful API |
|
2 -- |
|
3 -- Copyright (c) 2019 Kim Alvefur |
|
4 -- |
|
5 -- This file is MIT/X11 licensed. |
|
6 |
|
7 local errors = require "util.error"; |
|
8 local id = require "util.id"; |
|
9 local jid = require "util.jid"; |
|
10 local xml = require "util.xml"; |
|
11 |
|
12 local allow_any_source = module:get_host_type() == "component"; |
|
13 local validate_from_addresses = module:get_option_boolean("validate_from_addresses", true); |
|
14 |
|
15 local function handle_post(event) |
|
16 local request, response = event.request, event.response; |
|
17 if request.headers.content_type ~= "application/xmpp+xml" then |
|
18 return errors.new({ code = 415, text = "'application/xmpp+xml' expected" }); |
|
19 end |
|
20 local payload, err = xml.parse(request.body); |
|
21 if not payload then |
|
22 -- parse fail |
|
23 return errors.new({ code = 400, text = err }); |
|
24 end |
|
25 local to = jid.prep(payload.attr.to); |
|
26 if not to then |
|
27 return errors.new({ code = 400, text = "Invalid destination JID" }); |
|
28 end |
|
29 local from = module.host; |
|
30 if allow_any_source and payload.attr.from then |
|
31 from = jid.prep(payload.attr.from); |
|
32 if not from then |
|
33 return errors.new({ code = 400, text = "Invalid source JID" }); |
|
34 end |
|
35 if validate_from_addresses and not jid.compare(from, module.host) then |
|
36 return errors.new({ code = 403, text = "Source JID must belong to current host" }); |
|
37 end |
|
38 end |
|
39 payload.attr = { |
|
40 from = from, |
|
41 to = to, |
|
42 id = payload.attr.id or id.medium(), |
|
43 type = payload.attr.type, |
|
44 ["xml:lang"] = payload.attr["xml:lang"], |
|
45 }; |
|
46 if payload.name == "iq" then |
|
47 if payload.attr.type ~= "get" and payload.attr.type ~= "set" then |
|
48 return errors.new({ code = 400, text = "'iq' stanza must be of type 'get' or 'set'" }); |
|
49 end |
|
50 return module:send_iq(payload):next( |
|
51 function (result) |
|
52 response.headers.content_type = "application/xmpp+xml"; |
|
53 return tostring(result.stanza); |
|
54 end, |
|
55 function (error) |
|
56 if error.context.stanza then |
|
57 response.headers.content_type = "application/xmpp+xml"; |
|
58 return tostring(error.context.stanza); |
|
59 else |
|
60 return error; |
|
61 end |
|
62 end); |
|
63 elseif payload.name == "message" or payload.name == "presence" then |
|
64 if module:send(payload) then |
|
65 return 202; |
|
66 else |
|
67 return 500; |
|
68 end |
|
69 else |
|
70 return errors.new({ code = 400, text = "Invalid stanza, must be 'message', 'presence' or 'iq'." }); |
|
71 end |
|
72 end |
|
73 |
|
74 -- Handle stanzas submitted via HTTP |
|
75 module:depends("http"); |
|
76 module:provides("http", { |
|
77 route = { |
|
78 POST = handle_post; |
|
79 }; |
|
80 }); |