Software /
code /
prosody-modules
File
mod_auth_external_insecure/mod_auth_external_insecure.lua @ 6110:1a6cd0bbb7ab
mod_compliance_2023: Add 2023 Version of the compliance module, basis is the 2021 Version.
diff --git a/mod_compliance_2023/README.md b/mod_compliance_2023/README.md
new file mode 100644
--- /dev/null
+++ b/mod_compliance_2023/README.md
@@ -0,0 +1,22 @@
+---
+summary: XMPP Compliance Suites 2023 self-test
+labels:
+- Stage-Beta
+rockspec:
+ dependencies:
+ - mod_cloud_notify
+
+...
+
+Compare the list of enabled modules with
+[XEP-0479: XMPP Compliance Suites 2023] and produce basic report to the
+Prosody log file.
+
+If installed with the Prosody plugin installer then all modules needed for a green checkmark should be included. (With prosody 0.12 only [mod_cloud_notify] is not included with prosody and we need the community module)
+
+# Compatibility
+
+ Prosody-Version Status
+ --------------- ----------------------
+ trunk Works as of 2024-12-21
+ 0.12 Works
diff --git a/mod_compliance_2023/mod_compliance_2023.lua b/mod_compliance_2023/mod_compliance_2023.lua
new file mode 100644
--- /dev/null
+++ b/mod_compliance_2023/mod_compliance_2023.lua
@@ -0,0 +1,79 @@
+-- Copyright (c) 2021 Kim Alvefur
+--
+-- This module is MIT licensed.
+
+local hostmanager = require "core.hostmanager";
+
+local array = require "util.array";
+local set = require "util.set";
+
+local modules_enabled = module:get_option_inherited_set("modules_enabled");
+
+for host in pairs(hostmanager.get_children(module.host)) do
+ local component = module:context(host):get_option_string("component_module");
+ if component then
+ modules_enabled:add(component);
+ modules_enabled:include(module:context(host):get_option_set("modules_enabled", {}));
+ end
+end
+
+local function check(suggested, alternate, ...)
+ if set.intersection(modules_enabled, set.new({suggested; alternate; ...})):empty() then return suggested; end
+ return false;
+end
+
+local compliance = {
+ array {"Server"; check("tls"); check("disco")};
+
+ array {"Advanced Server"; check("pep", "pep_simple")};
+
+ array {"Web"; check("bosh"); check("websocket")};
+
+ -- No Server requirements for Advanced Web
+
+ array {"IM"; check("vcard_legacy", "vcard"); check("carbons"); check("http_file_share", "http_upload")};
+
+ array {
+ "Advanced IM";
+ check("vcard_legacy", "vcard");
+ check("blocklist");
+ check("muc");
+ check("private");
+ check("smacks");
+ check("mam");
+ check("bookmarks");
+ };
+
+ array {"Mobile"; check("smacks"); check("csi_simple", "csi_battery_saver")};
+
+ array {"Advanced Mobile"; check("cloud_notify")};
+
+ array {"A/V Calling"; check("turn_external", "external_services", "turncredentials", "extdisco")};
+
+};
+
+function check_compliance()
+ local compliant = true;
+ for _, suite in ipairs(compliance) do
+ local section = suite:pop(1);
+ if module:get_option_boolean("compliance_" .. section:lower():gsub("%A", "_"), true) then
+ local missing = set.new(suite:filter(function(m) return type(m) == "string" end):map(function(m) return "mod_" .. m end));
+ if suite[1] then
+ if compliant then
+ compliant = false;
+ module:log("warn", "Missing some modules for XMPP Compliance 2023");
+ end
+ module:log("info", "%s Compliance: %s", section, missing);
+ end
+ end
+ end
+
+ if compliant then module:log("info", "XMPP Compliance 2023: Compliant ✔️"); end
+end
+
+if prosody.start_time then
+ check_compliance()
+else
+ module:hook_global("server-started", check_compliance);
+end
+
author | Menel <menel@snikket.de> |
---|---|
date | Sun, 22 Dec 2024 16:06:28 +0100 |
parent | 3884:f84ede3e9e3b |
line wrap: on
line source
-- -- Prosody IM -- Copyright (C) 2010 Waqas Hussain -- Copyright (C) 2010 Jeff Mitchell -- Copyright (C) 2013 Mikael Nordfeldth -- Copyright (C) 2013 Matthew Wild, finally came to fix it all -- -- This project is MIT/X11 licensed. Please see the -- COPYING file in the source package for more information. -- local lpty = assert(require "lpty", "mod_auth_external requires lpty: https://modules.prosody.im/mod_auth_external.html#installation"); local usermanager = require "core.usermanager"; local new_sasl = require "util.sasl".new; local server = require "net.server"; local have_async, async = pcall(require, "util.async"); local log = module._log; local host = module.host; local script_type = module:get_option_string("external_auth_protocol", "generic"); local command = module:get_option_string("external_auth_command", ""); local read_timeout = module:get_option_number("external_auth_timeout", 5); local blocking = module:get_option_boolean("external_auth_blocking", true); -- non-blocking is very experimental local auth_processes = module:get_option_number("external_auth_processes", 1); assert(script_type == "ejabberd" or script_type == "generic", "Config error: external_auth_protocol must be 'ejabberd' or 'generic'"); assert(not host:find(":"), "Invalid hostname"); if not blocking then assert(server.event, "External auth non-blocking mode requires libevent installed and enabled"); log("debug", "External auth in non-blocking mode, yay!") waiter, guard = async.waiter, async.guarder(); elseif auth_processes > 1 then log("warn", "external_auth_processes is greater than 1, but we are in blocking mode - reducing to 1"); auth_processes = 1; end local ptys = {}; local pty_options = { throw_errors = false, no_local_echo = true, use_path = false }; for i = 1, auth_processes do ptys[i] = lpty.new(pty_options); end function module.unload() for i = 1, auth_processes do ptys[i]:endproc(); end end module:hook_global("server-cleanup", module.unload); local curr_process = 0; function send_query(text) curr_process = (curr_process%auth_processes)+1; local pty = ptys[curr_process]; local finished_with_pty if not blocking then finished_with_pty = guard(pty); -- Prevent others from crossing this line while we're busy end if not pty:hasproc() then local status, ret = pty:exitstatus(); if status and (status ~= "exit" or ret ~= 0) then log("warn", "Auth process exited unexpectedly with %s %d, restarting", status, ret or 0); return nil; end local ok, err = pty:startproc(command); if not ok then log("error", "Failed to start auth process '%s': %s", command, err); return nil; end log("debug", "Started auth process"); end pty:send(text); if blocking then return pty:read(read_timeout); else local response; local wait, done = waiter(); server.addevent(pty:getfd(), server.event.EV_READ, function () response = pty:read(); done(); return -1; end); wait(); finished_with_pty(); return response; end end function do_query(kind, username, password) if not username then return nil, "not-acceptable"; end local query = (password and "%s:%s:%s:%s" or "%s:%s:%s"):format(kind, username, host, password); local len = #query if len > 1000 then return nil, "policy-violation"; end if script_type == "ejabberd" then local lo = len % 256; local hi = (len - lo) / 256; query = string.char(hi, lo)..query; elseif script_type == "generic" then query = query..'\n'; end local response, err = send_query(query); if not response then log("warn", "Error while waiting for result from auth process: %s", err or "unknown error"); elseif (script_type == "ejabberd" and response == "\0\2\0\0") or (script_type == "generic" and response:gsub("\r?\n$", "") == "0") then return nil, "not-authorized"; elseif (script_type == "ejabberd" and response == "\0\2\0\1") or (script_type == "generic" and response:gsub("\r?\n$", "") == "1") then return true; else log("warn", "Unable to interpret data from auth process, %s", (response:match("^error:") and response) or ("["..#response.." bytes]")); return nil, "internal-server-error"; end end local provider = {}; function provider.test_password(username, password) return do_query("auth", username, password); end function provider.set_password(username, password) return do_query("setpass", username, password); end function provider.user_exists(username) return do_query("isuser", username); end function provider.create_user(username, password) -- luacheck: ignore 212 return nil, "Account creation/modification not available."; end function provider.get_sasl_handler() local testpass_authentication_profile = { plain_test = function(sasl, username, password, realm) return usermanager.test_password(username, realm, password), true; end, }; return new_sasl(host, testpass_authentication_profile); end module:provides("auth", provider);