Software /
code /
prosody-modules
File
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 |
line wrap: on
line source
module:depends("http"); local http = require "net.http"; local format = require "util.format".format; local json_encode = require "util.json".encode; local promise = require "util.promise"; local xml = require "util.xml"; local t_insert = table.insert; local function new_options(host) return { headers = { ["Content-Type"] = "text/xml; charset=utf-8", ["Host"] = host, }, method = "POST", }; end local function connect_to_bosh(url, hostname) local rid = math.random(100000, 100000000) local options = new_options(hostname); options.body = format([[<body content='text/xml; charset=utf-8' hold='1' rid='%d' to='%s' wait='60' xml:lang='en' xmpp:version='1.0' xmlns='http://jabber.org/protocol/httpbind' xmlns:xmpp='urn:xmpp:xbosh'/>]], rid, hostname); local rid = rid + 1; return promise.new(function (on_fulfilled, on_error) assert(http.request(url, options, function (body, code) if code ~= 200 then on_error("Failed to fetch, HTTP error code "..code); return; end local body = xml.parse(body); local sid = body.attr.sid; local mechanisms = {}; for mechanism in body:get_child("features", "http://etherx.jabber.org/streams") :get_child("mechanisms", "urn:ietf:params:xml:ns:xmpp-sasl") :childtags("mechanism", "urn:ietf:params:xml:ns:xmpp-sasl") do mechanisms[mechanism:get_text()] = true; end on_fulfilled({ url = url, sid = sid, rid = rid, mechanisms = mechanisms }); end)); end); end local function authenticate(data) local options = new_options(); options.body = format([[<body sid='%s' rid='%d' xmlns='http://jabber.org/protocol/httpbind'> <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='ANONYMOUS'/> </body>]], data.sid, data.rid); data.rid = data.rid + 1; return promise.new(function (on_fulfilled, on_error) if data.mechanisms["ANONYMOUS"] == nil then on_error("No SASL ANONYMOUS mechanism supported on this host."); return; end assert(http.request(data.url, options, function (body, code) if code ~= 200 then on_error("Failed to fetch, HTTP error code "..code); return; end local body = xml.parse(body); local success = body:get_child("success", "urn:ietf:params:xml:ns:xmpp-sasl"); if success then data.mechanisms = nil; on_fulfilled(data); else on_error("Authentication failed."); end end)); end); end; local function restart_stream(data) local options = new_options(); options.body = format([[ <body sid='%s' rid='%d' xml:lang='en' xmlns='http://jabber.org/protocol/httpbind' xmlns:xmpp='urn:xmpp:xbosh' xmpp:restart='true'/>]], data.sid, data.rid); data.rid = data.rid + 1; return promise.new(function (on_fulfilled, on_error) assert(http.request(data.url, options, function (body, code) if code ~= 200 then on_error("Failed to fetch, HTTP error code "..code); return; end local body = xml.parse(body); on_fulfilled(data); end)); end); end; local function bind(data) local options = new_options(); options.body = format([[ <body sid='%s' rid='%d' xmlns='http://jabber.org/protocol/httpbind'> <iq xmlns='jabber:client' type='set'> <bind xmlns='urn:ietf:params:xml:ns:xmpp-bind'/> </iq> </body>]], data.sid, data.rid); data.rid = data.rid + 1; return promise.new(function (on_fulfilled, on_error) assert(http.request(data.url, options, function (body, code) if code ~= 200 then on_error("Failed to fetch, HTTP error code "..code); return; end local body = xml.parse(body); local jid = body:get_child("iq", "jabber:client") :get_child("bind", "urn:ietf:params:xml:ns:xmpp-bind") :get_child_text("jid", "urn:ietf:params:xml:ns:xmpp-bind"); on_fulfilled(json_encode({rid = data.rid, sid = data.sid, jid = jid})); end)); end); end; module:provides("http", { route = { ["GET"] = function (event) return connect_to_bosh("http://[::1]:5280/http-bind", "anon.localhost") :next(authenticate) :next(restart_stream) :next(bind); end; }; });