view plugins/mod_groups.lua @ 13587:fdb2e0568cf8

mod_authz_internal: Make 'prosody:guest' default role for all unknown JIDs This fixes an issue where e.g. remote users or even other users on the server were unable to list MUC rooms. We want to define a permission to list MUC rooms, but we want it to be available to everyone by default (the traditional behaviour). prosody:guest is the lowest role we have. I ran a quick check and it isn't really used for anything right now that would be concerning. It was originally designed for anonymous logins. I think it's safe to treat remote JIDs as equivalent, since we have no trust relationship with anonymous users either.
author Matthew Wild <mwild1@gmail.com>
date Tue, 07 Jan 2025 14:41:32 +0000
parents 74b9e05af71e
children
line wrap: on
line source

-- Prosody IM
-- Copyright (C) 2008-2010 Matthew Wild
-- Copyright (C) 2008-2010 Waqas Hussain
--
-- This project is MIT/X11 licensed. Please see the
-- COPYING file in the source package for more information.
--


local groups;
local members;

local datamanager = require "prosody.util.datamanager";
local jid_prep = require "prosody.util.jid".prep;

local module_host = module:get_host();

function inject_roster_contacts(event)
	local username, host= event.username, event.host;
	--module:log("debug", "Injecting group members to roster");
	local bare_jid = username.."@"..host;
	if not members[bare_jid] and not members[false] then return; end -- Not a member of any groups

	local roster = event.roster;
	local function import_jids_to_roster(group_name)
		for jid in pairs(groups[group_name]) do
			-- Add them to roster
			--module:log("debug", "processing jid %s in group %s", jid, group_name);
			if jid ~= bare_jid then
				if not roster[jid] then roster[jid] = {}; end
				roster[jid].subscription = "both";
				if groups[group_name][jid] then
					roster[jid].name = groups[group_name][jid];
				end
				if not roster[jid].groups then
					roster[jid].groups = { [group_name] = true };
				end
				roster[jid].groups[group_name] = true;
				roster[jid].persist = false;
			end
		end
	end

	-- Find groups this JID is a member of
	if members[bare_jid] then
		for _, group_name in ipairs(members[bare_jid]) do
			--module:log("debug", "Importing group %s", group_name);
			import_jids_to_roster(group_name);
		end
	end

	-- Import public groups
	if members[false] then
		for _, group_name in ipairs(members[false]) do
			--module:log("debug", "Importing group %s", group_name);
			import_jids_to_roster(group_name);
		end
	end

	if roster[false] then
		roster[false].version = true;
	end
end

function remove_virtual_contacts(username, host, datastore, data)
	if host == module_host and datastore == "roster" then
		local new_roster = {};
		for jid, contact in pairs(data) do
			if contact.persist ~= false then
				new_roster[jid] = contact;
			end
		end
		if new_roster[false] then
			new_roster[false].version = nil; -- Version is void
		end
		return username, host, datastore, new_roster;
	end

	return username, host, datastore, data;
end

function module.load()
	local groups_file = module:get_option_path("groups_file", nil, "config");
	if not groups_file then return; end

	module:hook("roster-load", inject_roster_contacts);
	datamanager.add_callback(remove_virtual_contacts);

	groups = { default = {} };
	members = { };
	local curr_group = "default";
	for line in io.lines(groups_file) do
		if line:match("^%s*%[.-%]%s*$") then
			curr_group = line:match("^%s*%[(.-)%]%s*$");
			if curr_group:match("^%+") then
				curr_group = curr_group:gsub("^%+", "");
				if not members[false] then
					members[false] = {};
				end
				members[false][#members[false]+1] = curr_group; -- Is a public group
			end
			module:log("debug", "New group: %s", curr_group);
			groups[curr_group] = groups[curr_group] or {};
		else
			-- Add JID
			local entryjid, name = line:match("([^=]*)=?(.*)");
			module:log("debug", "entryjid = '%s', name = '%s'", entryjid, name);
			local jid;
			jid = jid_prep(entryjid:match("%S+"));
			if jid then
				module:log("debug", "New member of %s: %s", curr_group, jid);
				groups[curr_group][jid] = name or false;
				members[jid] = members[jid] or {};
				members[jid][#members[jid]+1] = curr_group;
			elseif entryjid:match("%S") then
				module:log("warn", "Invalid JID: %q", entryjid);
			end
		end
	end
	module:log("info", "Groups loaded successfully");
end

function module.unload()
	datamanager.remove_callback(remove_virtual_contacts);
end

-- Public for other modules to access
function group_contains(group_name, jid)
	return groups[group_name][jid];
end