Comparison

mod_http_prebind/mod_http_prebind.lua @ 4229:3943032533a7

mod_http_prebind: New module
author Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
date Sun, 25 Oct 2020 17:58:02 +0100
child 4230:495a23d61418
comparison
equal deleted inserted replaced
4228:3eb595cf847f 4229:3943032533a7
1 module:depends("http");
2
3 local http = require "net.http";
4 local format = require "util.format".format;
5 local json_encode = require "util.json".encode;
6 local promise = require "util.promise";
7 local xml = require "util.xml";
8 local t_insert = table.insert;
9
10 local function new_options(host)
11 return {
12 headers = {
13 ["Content-Type"] = "text/xml; charset=utf-8",
14 ["Host"] = host,
15 },
16 method = "POST",
17 };
18 end
19
20 local function connect_to_bosh(url, hostname)
21 local rid = math.random(100000, 100000000)
22 local options = new_options(hostname);
23 options.body = format([[<body content='text/xml; charset=utf-8'
24 hold='1'
25 rid='%d'
26 to='%s'
27 wait='60'
28 xml:lang='en'
29 xmpp:version='1.0'
30 xmlns='http://jabber.org/protocol/httpbind'
31 xmlns:xmpp='urn:xmpp:xbosh'/>]], rid, hostname);
32 local rid = rid + 1;
33 return promise.new(function (on_fulfilled, on_error)
34 assert(http.request(url, options, function (body, code)
35 if code ~= 200 then
36 on_error("Failed to fetch, HTTP error code "..code);
37 return;
38 end
39 local body = xml.parse(body);
40 local sid = body.attr.sid;
41 local mechanisms = {};
42 for mechanism in body:get_child("features", "http://etherx.jabber.org/streams")
43 :get_child("mechanisms", "urn:ietf:params:xml:ns:xmpp-sasl")
44 :childtags("mechanism", "urn:ietf:params:xml:ns:xmpp-sasl") do
45 mechanisms[mechanism:get_text()] = true;
46 end
47 on_fulfilled({ url = url, sid = sid, rid = rid, mechanisms = mechanisms });
48 end));
49 end);
50 end
51
52 local function authenticate(data)
53 local options = new_options();
54 options.body = format([[<body sid='%s'
55 rid='%d'
56 xmlns='http://jabber.org/protocol/httpbind'>
57 <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl'
58 mechanism='ANONYMOUS'/>
59 </body>]], data.sid, data.rid);
60 data.rid = data.rid + 1;
61 return promise.new(function (on_fulfilled, on_error)
62 if data.mechanisms["ANONYMOUS"] == nil then
63 on_error("No SASL ANONYMOUS mechanism supported on this host.");
64 return;
65 end
66 assert(http.request(data.url, options, function (body, code)
67 if code ~= 200 then
68 on_error("Failed to fetch, HTTP error code "..code);
69 return;
70 end
71 local body = xml.parse(body);
72 local success = body:get_child("success", "urn:ietf:params:xml:ns:xmpp-sasl");
73 if success then
74 data.mechanisms = nil;
75 on_fulfilled(data);
76 else
77 on_error("Authentication failed.");
78 end
79 end));
80 end);
81 end;
82
83 local function restart_stream(data)
84 local options = new_options();
85 options.body = format([[
86 <body sid='%s'
87 rid='%d'
88 xml:lang='en'
89 xmlns='http://jabber.org/protocol/httpbind'
90 xmlns:xmpp='urn:xmpp:xbosh'
91 xmpp:restart='true'/>]], data.sid, data.rid);
92 data.rid = data.rid + 1;
93 return promise.new(function (on_fulfilled, on_error)
94 assert(http.request(data.url, options, function (body, code)
95 if code ~= 200 then
96 on_error("Failed to fetch, HTTP error code "..code);
97 return;
98 end
99 local body = xml.parse(body);
100 on_fulfilled(data);
101 end));
102 end);
103 end;
104
105 local function bind(data)
106 local options = new_options();
107 options.body = format([[
108 <body sid='%s'
109 rid='%d'
110 xmlns='http://jabber.org/protocol/httpbind'>
111 <iq xmlns='jabber:client'
112 type='set'>
113 <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/>
114 </iq>
115 </body>]], data.sid, data.rid);
116 data.rid = data.rid + 1;
117 return promise.new(function (on_fulfilled, on_error)
118 assert(http.request(data.url, options, function (body, code)
119 if code ~= 200 then
120 on_error("Failed to fetch, HTTP error code "..code);
121 return;
122 end
123 local body = xml.parse(body);
124 local jid = body:get_child("iq", "jabber:client")
125 :get_child("bind", "urn:ietf:params:xml:ns:xmpp-bind")
126 :get_child_text("jid", "urn:ietf:params:xml:ns:xmpp-bind");
127 on_fulfilled(json_encode({rid = data.rid, sid = data.sid, jid = jid}));
128 end));
129 end);
130 end;
131
132 module:provides("http", {
133 route = {
134 ["GET"] = function (event)
135 return connect_to_bosh("http://[::1]:5280/http-bind", "anon.localhost")
136 :next(authenticate)
137 :next(restart_stream)
138 :next(bind);
139 end;
140 };
141 });