Software /
code /
prosody-modules
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 }); |