diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index e4d77868d..8128a65c2 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -26,9 +26,13 @@ jobs: run: | echo deb http://packages.prosody.im/debian $(lsb_release -sc) main | sudo tee /etc/apt/sources.list.d/prosody.list sudo wget https://prosody.im/files/prosody-debian-packages.key -O/etc/apt/trusted.gpg.d/prosody.gpg - sudo apt-get update - sudo apt-get -y install lua5.3 prosody-trunk lua-bitop lua-sec + sudo apt update + sudo apt install lua5.4 prosody-trunk lua-bitop lua-sec luarocks sudo service prosody stop + prosodyctl --config server/prosody.cfg.lua install mod_sasl2 + prosodyctl --config server/prosody.cfg.lua install mod_sasl2_bind2 + prosodyctl --config server/prosody.cfg.lua install mod_sasl2_fast + prosodyctl --config server/prosody.cfg.lua install mod_sasl2_sm # - run: npm install -g npm - run: make diff --git a/packages/sasl2/test.js b/packages/sasl2/test.js index fc53c62d1..844430eae 100644 --- a/packages/sasl2/test.js +++ b/packages/sasl2/test.js @@ -195,7 +195,12 @@ test("with bind2", async () => { , ); - entity.mockInput(); + entity.mockInput( + + {entity.jid} + + , + ); entity.mockInput(); await promise(entity, "online"); diff --git a/server/modules/.gitkeep b/server/modules/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/server/modules/mod_sasl2.lua b/server/modules/mod_sasl2.lua deleted file mode 100644 index 9eeff4b15..000000000 --- a/server/modules/mod_sasl2.lua +++ /dev/null @@ -1,228 +0,0 @@ --- Prosody IM --- Copyright (C) 2019 Kim Alvefur --- --- This project is MIT/X11 licensed. Please see the --- COPYING file in the source package for more information. --- --- XEP-0388: Extensible SASL Profile --- - -local st = require "util.stanza"; -local errors = require "util.error"; -local base64 = require "util.encodings".base64; -local jid_join = require "util.jid".join; -local set = require "util.set"; - -local usermanager_get_sasl_handler = require "core.usermanager".get_sasl_handler; -local sm_make_authenticated = require "core.sessionmanager".make_authenticated; - -local xmlns_sasl2 = "urn:xmpp:sasl:2"; - -local secure_auth_only = module:get_option_boolean("c2s_require_encryption", module:get_option_boolean("require_encryption", true)); -local allow_unencrypted_plain_auth = module:get_option_boolean("allow_unencrypted_plain_auth", false) -local insecure_mechanisms = module:get_option_set("insecure_sasl_mechanisms", allow_unencrypted_plain_auth and {} or {"PLAIN", "LOGIN"}); -local disabled_mechanisms = module:get_option_set("disable_sasl_mechanisms", { "DIGEST-MD5" }); - -local host = module.host; - -local function tls_unique(self) - return self.userdata["tls-unique"]:ssl_peerfinished(); -end - -local function tls_exporter(conn) - if not conn.ssl_exportkeyingmaterial then return end - return conn:ssl_exportkeyingmaterial("EXPORTER-Channel-Binding", 32, ""); -end - -local function sasl_tls_exporter(self) - return tls_exporter(self.userdata["tls-exporter"]); -end - -module:hook("stream-features", function(event) - local origin, features = event.origin, event.features; - local log = origin.log or module._log; - - if origin.type ~= "c2s_unauthed" then - log("debug", "Already authenticated"); - return - elseif secure_auth_only and not origin.secure then - log("debug", "Not offering authentication on insecure connection"); - return; - end - - local sasl_handler = usermanager_get_sasl_handler(host, origin) - origin.sasl_handler = sasl_handler; - - local channel_bindings = set.new() - if origin.encrypted then - -- check whether LuaSec has the nifty binding to the function needed for tls-unique - -- FIXME: would be nice to have this check only once and not for every socket - if sasl_handler.add_cb_handler then - local info = origin.conn:ssl_info(); - if info and info.protocol == "TLSv1.3" then - log("debug", "Channel binding 'tls-unique' undefined in context of TLS 1.3"); - if tls_exporter(origin.conn) then - log("debug", "Channel binding 'tls-exporter' supported"); - sasl_handler:add_cb_handler("tls-exporter", sasl_tls_exporter); - channel_bindings:add("tls-exporter"); - else - log("debug", "Channel binding 'tls-exporter' not supported"); - end - elseif origin.conn.ssl_peerfinished and origin.conn:ssl_peerfinished() then - log("debug", "Channel binding 'tls-unique' supported"); - sasl_handler:add_cb_handler("tls-unique", tls_unique); - channel_bindings:add("tls-unique"); - else - log("debug", "Channel binding 'tls-unique' not supported (by LuaSec?)"); - end - sasl_handler["userdata"] = { - ["tls-unique"] = origin.conn; - ["tls-exporter"] = origin.conn; - }; - else - log("debug", "Channel binding not supported by SASL handler"); - end - end - - local mechanisms = st.stanza("authentication", { xmlns = xmlns_sasl2 }); - - local available_mechanisms = sasl_handler:mechanisms() - for mechanism in pairs(available_mechanisms) do - if disabled_mechanisms:contains(mechanism) then - log("debug", "Not offering disabled mechanism %s", mechanism); - elseif not origin.secure and insecure_mechanisms:contains(mechanism) then - log("debug", "Not offering mechanism %s on insecure connection", mechanism); - else - log("debug", "Offering mechanism %s", mechanism); - mechanisms:text_tag("mechanism", mechanism); - end - end - - features:add_direct_child(mechanisms); - - local inline = st.stanza("inline"); - module:fire_event("advertise-sasl-features", { origin = origin, features = inline, stream = event.stream }); - mechanisms:add_direct_child(inline); -end, 1); - -local function handle_status(session, status, ret, err_msg) - local err = nil; - if status == "error" then - ret, err = nil, ret; - if not errors.is_err(err) then - err = errors.new({ condition = err, text = err_msg }, { session = session }); - end - end - - return module:fire_event("sasl2/"..session.base_type.."/"..status, { - session = session, - message = ret; - error = err; - error_text = err_msg; - }); -end - -module:hook("sasl2/c2s/failure", function (event) - module:fire_event("authentication-failure", event); - local session, condition, text = event.session, event.message, event.error_text; - local failure = st.stanza("failure", { xmlns = xmlns_sasl2 }) - :tag(condition, { xmlns = "urn:ietf:params:xml:ns:xmpp-sasl" }):up(); - if text then - failure:text_tag("text", text); - end - session.send(failure); - return true; -end); - -module:hook("sasl2/c2s/error", function (event) - local session = event.session - session.send(st.stanza("failure", { xmlns = xmlns_sasl2 }) - :tag(event.error and event.error.condition)); - return true; -end); - -module:hook("sasl2/c2s/challenge", function (event) - local session = event.session; - session.send(st.stanza("challenge", { xmlns = xmlns_sasl2 }) - :text(base64.encode(event.message))); - return true; -end); - -module:hook("sasl2/c2s/success", function (event) - local session = event.session - local ok, err = sm_make_authenticated(session, session.sasl_handler.username); - if not ok then - handle_status(session, "failure", err); - return true; - end - event.success = st.stanza("success", { xmlns = xmlns_sasl2 }); - if event.message then - event.success:text_tag("additional-data", base64.encode(event.message)); - end -end, 1000); - -module:hook("sasl2/c2s/success", function (event) - local session = event.session - event.success:text_tag("authorization-identifier", jid_join(session.username, session.host, session.resource)); - session.send(event.success); -end, -1000); - -module:hook("sasl2/c2s/success", function (event) - module:fire_event("authentication-success", event); - local session = event.session; - local features = st.stanza("stream:features"); - module:fire_event("stream-features", { origin = session, features = features }); - session.send(features); -end, -1500); - --- The gap here is to allow modules to do stuff to the stream after the stanza --- is sent, but before we proceed with anything else. This is expected to be --- a common pattern with SASL2, which allows atomic negotiation of a bunch of --- stream features. -module:hook("sasl2/c2s/success", function (event) --luacheck: ignore 212/event - event.session.sasl_handler = nil; - return true; -end, -2000); - -local function process_cdata(session, cdata) - if cdata then - cdata = base64.decode(cdata); - if not cdata then - return handle_status(session, "failure", "incorrect-encoding"); - end - end - return handle_status(session, session.sasl_handler:process(cdata)); -end - -module:hook_tag(xmlns_sasl2, "authenticate", function (session, auth) - if secure_auth_only and not session.secure then - return handle_status(session, "failure", "encryption-required"); - end - local sasl_handler = session.sasl_handler; - if not sasl_handler then - sasl_handler = usermanager_get_sasl_handler(host, session); - session.sasl_handler = sasl_handler; - end - local mechanism = assert(auth.attr.mechanism); - if not sasl_handler:select(mechanism) then - return handle_status(session, "failure", "invalid-mechanism"); - end - local user_agent = auth:get_child("user-agent"); - if user_agent then - session.client_id = user_agent.attr.id; - sasl_handler.user_agent = { - software = user_agent:get_child_text("software"); - device = user_agent:get_child_text("device"); - }; - end - local initial = auth:get_child_text("initial-response"); - return process_cdata(session, initial); -end); - -module:hook_tag(xmlns_sasl2, "response", function (session, response) - local sasl_handler = session.sasl_handler; - if not sasl_handler or not sasl_handler.selected then - return handle_status(session, "failure", "invalid-mechanism"); - end - return process_cdata(session, response:get_text()); -end); diff --git a/server/modules/mod_sasl2_bind2.lua b/server/modules/mod_sasl2_bind2.lua deleted file mode 100644 index fb02ffd59..000000000 --- a/server/modules/mod_sasl2_bind2.lua +++ /dev/null @@ -1,110 +0,0 @@ -local base64 = require "util.encodings".base64; -local id = require "util.id"; -local sha1 = require "util.hashes".sha1; -local st = require "util.stanza"; - -local sm_bind_resource = require "core.sessionmanager".bind_resource; - -local xmlns_bind2 = "urn:xmpp:bind:0"; -local xmlns_sasl2 = "urn:xmpp:sasl:2"; - -module:depends("sasl2"); - --- Advertise what we can do - -module:hook("advertise-sasl-features", function(event) - local bind = st.stanza("bind", { xmlns = xmlns_bind2 }); - local inline = st.stanza("inline"); - module:fire_event("advertise-bind-features", { origin = event.origin, features = inline }); - bind:add_direct_child(inline); - - event.features:add_direct_child(bind); -end, 1); - --- Helper to actually bind a resource to a session - -local function do_bind(session, bind_request) - local resource = session.sasl_handler.resource; - - if not resource then - local client_name_tag = bind_request:get_child_text("tag"); - if client_name_tag then - local client_id = session.client_id; - local tag_suffix = client_id and base64.encode(sha1(client_id):sub(1, 9)) or id.medium(); - resource = ("%s~%s"):format(client_name_tag, tag_suffix); - end - end - - local success, err_type, err, err_msg = sm_bind_resource(session, resource); - if not success then - session.log("debug", "Resource bind failed: %s", err_msg or err); - return nil, { type = err_type, condition = err, text = err_msg }; - end - - session.log("debug", "Resource bound: %s", session.full_jid); - return st.stanza("bound", { xmlns = xmlns_bind2 }); -end - --- Enable inline features requested by the client - -local function enable_features(session, bind_request, bind_result) - module:fire_event("enable-bind-features", { - session = session; - request = bind_request; - result = bind_result; - }); -end - --- SASL 2 integration - -module:hook_tag(xmlns_sasl2, "authenticate", function (session, auth) - -- Cache action for future processing (after auth success) - session.sasl2_bind_request = auth:child_with_ns(xmlns_bind2); -end, 100); - -module:hook("sasl2/c2s/success", function (event) - local session = event.session; - - local bind_request = session.sasl2_bind_request; - if not bind_request then return; end -- No bind requested - session.sasl2_bind_request = nil; - - local sm_success = session.sasl2_sm_success; - if sm_success and sm_success.type == "resumed" then - return; -- No need to bind a resource - end - - local bind_result, err = do_bind(session, bind_request); - if not bind_result then - bind_result = st.stanza("failed", { xmlns = xmlns_bind2 }) - :add_error(err); - else - enable_features(session, bind_request, bind_result); - end - - event.success:add_child(bind_result); -end, 100); - --- Inline features - -module:hook("advertise-bind-features", function (event) - local features = event.features; - features:tag("feature", { var = "urn:xmpp:carbons:2" }):up(); - features:tag("feature", { var = "urn:xmpp:csi:0" }):up(); -end); - -module:hook("enable-bind-features", function (event) - local session, request = event.session, event.request; - - -- Carbons - if request:get_child("enable", "urn:xmpp:carbons:2") then - session.want_carbons = true; - event.result:tag("enabled", { xmlns = "urn:xmpp:carbons:2" }):up(); - end - - -- CSI - local csi_state_tag = request:child_with_ns("urn:xmpp:csi:0"); - if csi_state_tag then - session.state = csi_state_tag.name; - end -end, 10); diff --git a/server/modules/mod_sasl2_fast.lua b/server/modules/mod_sasl2_fast.lua deleted file mode 100644 index 4a4c4475f..000000000 --- a/server/modules/mod_sasl2_fast.lua +++ /dev/null @@ -1,271 +0,0 @@ -local usermanager = require "core.usermanager"; - -local sasl = require "util.sasl"; -local dt = require "util.datetime"; -local id = require "util.id"; -local jid = require "util.jid"; -local st = require "util.stanza"; -local now = require "util.time".now; -local hash = require "util.hashes"; - -local sasl_mt = getmetatable(sasl.new("", { mechanisms = {} })); -local function is_util_sasl(sasl_handler) - return getmetatable(sasl_handler) == sasl_mt; -end - -module:depends("sasl2"); - --- Tokens expire after 21 days by default -local fast_token_ttl = module:get_option_number("sasl2_fast_token_ttl", 86400*21); --- Tokens are automatically rotated daily -local fast_token_min_ttl = module:get_option_number("sasl2_fast_token_min_ttl", 86400); - -local xmlns_fast = "urn:xmpp:fast:0"; -local xmlns_sasl2 = "urn:xmpp:sasl:2"; - -local token_store = module:open_store("fast_tokens", "map"); - -local log = module._log; - -local function make_token(username, client_id, mechanism) - local new_token = "secret-token:fast-"..id.long(); - local key = hash.sha256(client_id, true).."-new"; - local issued_at = now(); - local token_info = { - mechanism = mechanism; - secret = new_token; - issued_at = issued_at; - expires_at = issued_at + fast_token_ttl; - }; - if not token_store:set(username, key, token_info) then - return nil; - end - return token_info; -end - -local function new_token_tester(hmac_f) - return function (mechanism, username, client_id, token_hash, cb_data, invalidate) - local account_info = usermanager.get_account_info(username, module.host); - local last_password_change = account_info and account_info.password_updated; - local tried_current_token = false; - local key = hash.sha256(client_id, true).."-new"; - local token; - repeat - log("debug", "Looking for %s token %s/%s", mechanism, username, key); - token = token_store:get(username, key); - if token and token.mechanism == mechanism then - local expected_hash = hmac_f(token.secret, "Initiator"..(cb_data or "")); - if hash.equals(expected_hash, token_hash) then - local current_time = now(); - if token.expires_at < current_time then - log("debug", "Token found, but it has expired (%ds ago). Cleaning up...", current_time - token.expires_at); - token_store:set(username, key, nil); - return nil, "credentials-expired"; - elseif last_password_change and token.issued_at < last_password_change then - log("debug", "Token found, but issued prior to password change (%ds ago). Cleaning up...", - current_time - last_password_change - ); - token_store:set(username, key, nil); - return nil, "credentials-expired"; - end - if not tried_current_token and not invalidate then - -- The new token is becoming the current token - token_store:set_keys(username, { - [key] = token_store.remove; - [key:sub(1, -5).."-cur"] = token; - }); - end - local rotation_needed; - if invalidate then - token_store:set(username, key, nil); - elseif current_time - token.issued_at > fast_token_min_ttl then - log("debug", "FAST token due for rotation (age: %d)", current_time - token.issued_at); - rotation_needed = true; - end - return true, username, hmac_f(token.secret, "Responder"..(cb_data or "")), rotation_needed; - end - end - if not tried_current_token then - log("debug", "Trying next token..."); - -- Try again with the current token instead - tried_current_token = true; - key = key:sub(1, -5).."-cur"; - else - log("debug", "No matching %s token found for %s/%s", mechanism, username, key); - return nil; - end - until false; - end -end - -function get_sasl_handler() - local token_auth_profile = { - ht_sha_256 = new_token_tester(hash.hmac_sha256); - }; - local handler = sasl.new(module.host, token_auth_profile); - handler.fast = true; - return handler; -end - --- Advertise FAST to connecting clients -module:hook("advertise-sasl-features", function (event) - local session = event.origin; - local username = session.username; - if not username then - username = jid.node(event.stream.from); - if not username then return; end - end - local sasl_handler = get_sasl_handler(username); - if not sasl_handler then return; end - sasl_handler.fast_auth = true; -- For informational purposes - -- Copy channel binding info from primary SASL handler if it's compatible - if is_util_sasl(session.sasl_handler) then - sasl_handler.profile.cb = session.sasl_handler.profile.cb; - sasl_handler.userdata = session.sasl_handler.userdata; - end - -- Store this handler, in case we later want to use it for authenticating - session.fast_sasl_handler = sasl_handler; - local fast = st.stanza("fast", { xmlns = xmlns_fast }); - for mech in pairs(sasl_handler:mechanisms()) do - fast:text_tag("mechanism", mech); - end - event.features:add_child(fast); -end); - --- Process any FAST elements in -module:hook_tag(xmlns_sasl2, "authenticate", function (session, auth) - -- Cache action for future processing (after auth success) - local fast_auth = auth:get_child("fast", xmlns_fast); - if fast_auth then - -- Client says it is using FAST auth, so set our SASL handler - local fast_sasl_handler = session.fast_sasl_handler; - local client_id = auth:get_child_attr("user-agent", nil, "id"); - if fast_sasl_handler and client_id then - session.log("debug", "Client is authenticating using FAST"); - fast_sasl_handler.client_id = client_id; - fast_sasl_handler.profile.cb = session.sasl_handler.profile.cb; - fast_sasl_handler.userdata = session.sasl_handler.userdata; - local invalidate = fast_auth.attr.invalidate; - fast_sasl_handler.invalidate = invalidate == "1" or invalidate == "true"; - -- Set our SASL handler as the session's SASL handler - session.sasl_handler = fast_sasl_handler; - else - session.log("warn", "Client asked to auth via FAST, but SASL handler or client id missing"); - local failure = st.stanza("failure", { xmlns = xmlns_sasl2 }) - :tag("malformed-request"):up() - :text_tag("text", "FAST is not available on this stream"); - session.send(failure); - return true; - end - end - session.fast_sasl_handler = nil; - local fast_token_request = auth:get_child("request-token", xmlns_fast); - if fast_token_request then - local mech = fast_token_request.attr.mechanism; - session.log("debug", "Client requested new FAST token for %s", mech); - session.fast_token_request = { - mechanism = mech; - }; - end -end, 100); - --- Process post-success (new token generation, etc.) -module:hook("sasl2/c2s/success", function (event) - local session = event.session; - - local token_request = session.fast_token_request; - local client_id = session.client_id; - local sasl_handler = session.sasl_handler; - if token_request or (sasl_handler.fast and sasl_handler.rotation_needed) then - if not client_id then - session.log("warn", "FAST token requested, but missing client id"); - return; - end - local mechanism = token_request and token_request.mechanism or session.sasl_handler.selected; - local token_info = make_token(session.username, client_id, mechanism) - if token_info then - session.log("debug", "Provided new FAST token to client"); - event.success:tag("token", { - xmlns = xmlns_fast; - expiry = dt.datetime(token_info.expires_at); - token = token_info.secret; - }):up(); - end - end -end, 75); - --- HT-* mechanisms - -local function new_ht_mechanism(mechanism_name, backend_profile_name, cb_name) - return function (sasl_handler, message) - local backend = sasl_handler.profile[backend_profile_name]; - local authc_username, token_hash = message:match("^([^%z]+)%z(.+)$"); - if not authc_username then - return "failure", "malformed-request"; - end - local cb_data; - if cb_name then - if not sasl_handler.profile.cb then - module:log("warn", "Attempt to use channel binding %s with SASL profile that does not support any channel binding (FAST: %s)", cb_name, sasl_handler.fast); - return "failure", "malformed-request"; - elseif not sasl_handler.profile.cb[cb_name] then - module:log("warn", "SASL profile does not support %s channel binding (FAST: %s)", cb_name, sasl_handler.fast); - return "failure", "malformed-request"; - end - cb_data = sasl_handler.profile.cb[cb_name](sasl_handler) or ""; - end - local ok, authz_username, response, rotation_needed = backend( - mechanism_name, - authc_username, - sasl_handler.client_id, - token_hash, - cb_data, - sasl_handler.invalidate - ); - if not ok then - -- authz_username is error condition - return "failure", authz_username or "not-authorized"; - end - sasl_handler.username = authz_username; - sasl_handler.rotation_needed = rotation_needed; - return "success", response; - end -end - -local function register_ht_mechanism(name, backend_profile_name, cb_name) - return sasl.registerMechanism(name, { backend_profile_name }, new_ht_mechanism( - name, - backend_profile_name, - cb_name - ), - cb_name and { cb_name } or nil); -end - -register_ht_mechanism("HT-SHA-256-NONE", "ht_sha_256", nil); -register_ht_mechanism("HT-SHA-256-UNIQ", "ht_sha_256", "tls-unique"); -register_ht_mechanism("HT-SHA-256-ENDP", "ht_sha_256", "tls-server-end-point"); -register_ht_mechanism("HT-SHA-256-EXPR", "ht_sha_256", "tls-exporter"); - --- Public API - ---luacheck: ignore 131 -function is_client_fast(username, client_id, last_password_change) - local client_id_hash = hash.sha256(client_id, true); - local curr_time = now(); - local cur = token_store:get(username, client_id_hash.."-cur"); - if cur and cur.expires_at >= curr_time and (not last_password_change or last_password_change < cur.issued_at) then - return true; - end - local new = token_store:get(username, client_id_hash.."-new"); - if new and new.expires_at >= curr_time and (not last_password_change or last_password_change < new.issued_at) then - return true; - end - return false; -end - -function revoke_fast_tokens(username, client_id) - local client_id_hash = hash.sha256(client_id, true); - local cur_ok = token_store:set(username, client_id_hash.."-cur", nil); - local new_ok = token_store:set(username, client_id_hash.."-new", nil); - return cur_ok and new_ok; -end diff --git a/server/modules/mod_sasl2_sm.lua b/server/modules/mod_sasl2_sm.lua deleted file mode 100644 index 4ed0fb1ac..000000000 --- a/server/modules/mod_sasl2_sm.lua +++ /dev/null @@ -1,90 +0,0 @@ -local st = require "util.stanza"; - -local mod_smacks = module:depends("smacks"); - -local xmlns_sasl2 = "urn:xmpp:sasl:2"; -local xmlns_sm = "urn:xmpp:sm:3"; - -module:depends("sasl2"); - --- Advertise what we can do - -module:hook("advertise-sasl-features", function (event) - local features = event.features; - features:tag("sm", { xmlns = xmlns_sm }):up(); -end); - -module:hook("advertise-bind-features", function (event) - local features = event.features; - features:tag("feature", { var = xmlns_sm }):up(); -end); - -module:hook_tag(xmlns_sasl2, "authenticate", function (session, auth) - -- Cache action for future processing (after auth success) - session.sasl2_sm_request = auth:child_with_ns(xmlns_sm); -end, 100); - --- SASL 2 integration (for resume) - -module:hook("sasl2/c2s/success", function (event) - local session = event.session; - local sm_request = session.sasl2_sm_request; - if not sm_request then return; end - session.sasl2_sm_request = nil; - local sm_result; - if sm_request.name ~= "resume" then return; end - - local resumed, err = mod_smacks.do_resume(session, sm_request); - if not resumed then - local h = err.context and err.context.h; - sm_result = st.stanza("failed", { xmlns = xmlns_sm, h = h and ("%d"):format(h) or nil }) - :add_error(err); - else - event.session = resumed.session; -- Update to resumed session - event.session.sasl2_sm_success = resumed; -- To be called after sending final SASL response - sm_result = st.stanza("resumed", { xmlns = xmlns_sm, - h = ("%d"):format(event.session.handled_stanza_count); - previd = resumed.id; }); - end - - if sm_result then - event.success:add_child(sm_result); - end -end, 110); - --- Bind 2 integration (for enable) - -module:hook("enable-bind-features", function (event) - local sm_enable = event.request:get_child("enable", xmlns_sm); - if not sm_enable then return; end - - local sm_result; - local enabled, err = mod_smacks.do_enable(event.session, sm_enable); - if not enabled then - sm_result = st.stanza("failed", { xmlns = xmlns_sm }) - :add_error(err); - else - event.session.sasl2_sm_success = enabled; -- To be called after sending final SASL response - sm_result = st.stanza("enabled", { - xmlns = xmlns_sm; - id = enabled.id; - resume = enabled.id and "1" or nil; - max = enabled.resume_max; - }); - end - event.result:add_child(sm_result); -end, 100); - --- Finish and/or clean up after SASL 2 completed - -module:hook("sasl2/c2s/success", function (event) - -- The authenticate response has already been sent at this point - local success = event.session.sasl2_sm_success; - if success then - success.finish(); -- Finish enable/resume and sync stanzas - end -end, -1100); - -module:hook("sasl2/c2s/failure", function (event) - event.session.sasl2_sm_request = nil; -end); diff --git a/server/prosody.cfg.lua b/server/prosody.cfg.lua index 2d14a9fca..9fd2a7749 100644 --- a/server/prosody.cfg.lua +++ b/server/prosody.cfg.lua @@ -4,7 +4,9 @@ local lfs = require "lfs"; -plugin_paths = { "modules" } +-- plugin_paths = { "modules" } +plugin_server = "https://modules.prosody.im/rocks/" +installer_plugin_path = lfs.currentdir() .. "/modules"; modules_enabled = { "roster";