view mod_auth_ldap/mod_auth_ldap.lua @ 6214:cc5c0f1dc89b

mod_muc_anonymize_moderation_actions: Fix mentioning Virtualhost for MUC, Compatibility section and License. diff --git a/mod_muc_anonymize_moderation_actions/README.md b/mod_muc_anonymize_moderation_actions/README.md --- a/mod_muc_anonymize_moderation_actions/README.md +++ b/mod_muc_anonymize_moderation_actions/README.md @@ -1,8 +1,10 @@ -<!-- -SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/> -SPDX-License-Identifier: AGPL-3.0-only ---> -# mod_muc_anonymize_moderation_actions +--- +labels: +- 'Stage-Alpha' +summary: Anonymize moderator actions for participants +--- + +## Introduction This modules allows to anonymize affiliation and role changes in MUC rooms. @@ -11,13 +13,10 @@ When the feature is enabled, when a mode This is particularly usefull to prevent some revenge when a moderator bans someone. -This module is under AGPL-3.0 license. - -It was tested on Prosody 0.12.x. ## Configuration -Just enable the module on your MUC VirtualHost. +Just enable the module on your MUC Component. The feature will be accessible throught the room configuration form. You can tweak the position of the settings in the MUC configuration form using `anonymize_moderation_actions_form_position`. @@ -26,7 +25,20 @@ This value will be passed as priority fo By default, the field will be between muc#roomconfig_changesubject and muc#roomconfig_moderatedroom (default value is `78`). ``` lua -VirtualHost "muc.example.com" +Component "muc.example.com" "muc" modules_enabled = { "muc_anonymize_moderation_actions" } anonymize_moderation_actions_form_position = 96 ``` + +## Compatibility + + ------ ---------------------- + trunk Works as of 25-05-12 + 0.13 Works + 0.12 Works + ------ ---------------------- + +### License + +SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/> +SPDX-License-Identifier: AGPL-3.0-only
author Menel <menel@snikket.de>
date Mon, 12 May 2025 10:42:26 +0200
parents f2b29183ef08
children
line wrap: on
line source

-- mod_auth_ldap

local jid_split = require "util.jid".split;
local new_sasl = require "util.sasl".new;
local lualdap = require "lualdap";

local function ldap_filter_escape(s)
	return (s:gsub("[*()\\%z]", function(c) return ("\\%02x"):format(c:byte()) end));
end

-- Config options
local ldap_server = module:get_option_string("ldap_server", "localhost");
local ldap_rootdn = module:get_option_string("ldap_rootdn", "");
local ldap_password = module:get_option_string("ldap_password", "");
local ldap_tls = module:get_option_boolean("ldap_tls");
local ldap_scope = module:get_option_string("ldap_scope", "subtree");
local ldap_filter = module:get_option_string("ldap_filter", "(uid=$user)"):gsub("%%s", "$user", 1);
local ldap_base = assert(module:get_option_string("ldap_base"), "ldap_base is a required option for ldap");
local ldap_mode = module:get_option_string("ldap_mode", "bind");
local ldap_admins = module:get_option_string("ldap_admin_filter",
	module:get_option_string("ldap_admins")); -- COMPAT with mistake in documentation
local host = ldap_filter_escape(module:get_option_string("realm", module.host));

-- Initiate connection
local ld = nil;
module.unload = function() if ld then pcall(ld, ld.close); end end

function ldap_do_once(method, ...)
	if ld == nil then
		local err;
		ld, err = lualdap.open_simple(ldap_server, ldap_rootdn, ldap_password, ldap_tls);
		if not ld then return nil, err, "reconnect"; end
	end

	-- luacheck: ignore 411/success
	local success, iterator, invariant, initial = pcall(ld[method], ld, ...);
	if not success then ld = nil; return nil, iterator, "search"; end

	local success, dn, attr = pcall(iterator, invariant, initial);
	if not success then ld = nil; return success, dn, "iter"; end

	return dn, attr, "return";
end

function ldap_do(method, retry_count, ...)
	local dn, attr, where;
	for _=1,1+retry_count do
		dn, attr, where = ldap_do_once(method, ...);
		if dn or not(attr) then break; end -- nothing or something found
		module:log("warn", "LDAP: %s %s (in %s)", tostring(dn), tostring(attr), where);
		-- otherwise retry
	end
	if not dn and attr then
		module:log("error", "LDAP: %s", tostring(attr));
	end
	return dn, attr;
end

function get_user(username)
	module:log("debug", "get_user(%q)", username);
	return ldap_do("search", 2, {
		base = ldap_base;
		scope = ldap_scope;
		sizelimit = 1;
		filter = ldap_filter:gsub("%$(%a+)", {
			user = ldap_filter_escape(username);
			host = host;
		});
	});
end

local provider = {};

function provider.create_user(username, password) -- luacheck: ignore 212
	return nil, "Account creation not available with LDAP.";
end

function provider.user_exists(username)
	return not not get_user(username);
end

function provider.set_password(username, password)
	local dn, attr = get_user(username);
	if not dn then return nil, attr end
	if attr.userPassword == password then return true end
	return ldap_do("modify", 2, dn, { '=', userPassword = password });
end

if ldap_mode == "getpasswd" then
	function provider.get_password(username)
		local dn, attr = get_user(username);
		if dn and attr then
			return attr.userPassword;
		end
	end

	function provider.test_password(username, password)
		return provider.get_password(username) == password;
	end

	function provider.get_sasl_handler()
		return new_sasl(module.host, {
			plain = function(sasl, username) -- luacheck: ignore 212/sasl
				local password = provider.get_password(username);
				if not password then return "", nil; end
				return password, true;
			end
		});
	end
elseif ldap_mode == "bind" then
	local function test_password(userdn, password)
		local ok, err = lualdap.open_simple(ldap_server, userdn, password, ldap_tls);
		if not ok then
			module:log("debug", "ldap open_simple error: %s", err);
		end
		return not not ok;
	end

	function provider.test_password(username, password)
		local dn = get_user(username);
		if not dn then return end
		return test_password(dn, password)
	end

	function provider.get_sasl_handler()
		return new_sasl(module.host, {
			plain_test = function(sasl, username, password) -- luacheck: ignore 212/sasl
				return provider.test_password(username, password), true;
			end
		});
	end
else
	module:log("error", "Unsupported ldap_mode %s", tostring(ldap_mode));
end

if ldap_admins then
	function provider.is_admin(jid)
		local username, user_host = jid_split(jid);
		if user_host ~= module.host then
			return false;
		end
		return ldap_do("search", 2, {
			base = ldap_base;
			scope = ldap_scope;
			sizelimit = 1;
			filter = ldap_admins:gsub("%$(%a+)", {
				user = ldap_filter_escape(username);
				host = host;
			});
		});
	end
end

module:provides("auth", provider);