%%%---------------------------------------------------------------------- %%% File : mod_muc_occupantid.erl %%% Author : Badlop %%% Purpose : Add Occupant Ids to stanzas in anonymous MUC rooms (XEP-0421) %%% Created : %%% %%% %%% ejabberd, Copyright (C) 2002-2024 ProcessOne %%% %%% This program is free software; you can redistribute it and/or %%% modify it under the terms of the GNU General Public License as %%% published by the Free Software Foundation; either version 2 of the %%% License, or (at your option) any later version. %%% %%% This program is distributed in the hope that it will be useful, %%% but WITHOUT ANY WARRANTY; without even the implied warranty of %%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU %%% General Public License for more details. %%% %%% You should have received a copy of the GNU General Public License along %%% with this program; if not, write to the Free Software Foundation, Inc., %%% 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. %%% %%%---------------------------------------------------------------------- -module(mod_muc_occupantid). -author('badlop@process-one.net'). -protocol({xep, 421, '0.1.0', '23.10', "complete", ""}). -behaviour(gen_mod). -include_lib("xmpp/include/xmpp.hrl"). -include("logger.hrl"). -include("translate.hrl"). -include("mod_muc_room.hrl"). -export([start/2, stop/1, mod_options/1, mod_doc/0, depends/2]). -export([filter_packet/3, remove_room/3]). %%% %%% gen_mod %%% start(_Host, _Opts) -> create_table(), {ok, [{hook, muc_filter_presence, filter_packet, 10}, {hook, muc_filter_message, filter_packet, 10}, {hook, remove_room, remove_room, 50}]}. stop(_Host) -> ok. %%% %%% Hooks %%% filter_packet(Packet, State, _Nick) -> add_occupantid_packet(Packet, State#state.jid). remove_room(_LServer, Name, Host) -> delete_salt(jid:make(Name, Host)). %%% %%% XEP-0421 Occupant-id %%% add_occupantid_packet(Packet, RoomJid) -> From = xmpp:get_from(Packet), OccupantId = calculate_occupantid(From, RoomJid), OccupantElement = #occupant_id{id = OccupantId}, xmpp:set_subtag(Packet, OccupantElement). calculate_occupantid(From, RoomJid) -> Term = {jid:remove_resource(From), get_salt(RoomJid)}, misc:term_to_base64(crypto:hash(sha256, io_lib:format("~p", [Term]))). %%% %%% Table storing rooms' salt %%% -record(muc_occupant_id, {room_jid, salt}). create_table() -> ejabberd_mnesia:create(?MODULE, muc_occupant_id, [{ram_copies, [node()]}, {local_content, true}, {attributes, record_info(fields, muc_occupant_id)}, {type, set}]). get_salt(RoomJid) -> case mnesia:dirty_read(muc_occupant_id, RoomJid) of [] -> Salt = p1_rand:get_string(), ok = write_salt(RoomJid, Salt), Salt; [#muc_occupant_id{salt = Salt}] -> Salt end. write_salt(RoomJid, Salt) -> mnesia:dirty_write(#muc_occupant_id{room_jid = RoomJid, salt = Salt}). delete_salt(RoomJid) -> mnesia:dirty_delete(muc_occupant_id, RoomJid). %%% %%% Doc %%% mod_options(_Host) -> []. mod_doc() -> #{desc => [?T("This module implements " "https://xmpp.org/extensions/xep-0421.html" "[XEP-0421: Anonymous unique occupant identifiers for MUCs]."), "", ?T("When the module is enabled, the feature is enabled " "in all semi-anonymous rooms.")], note => "added in 23.10" }. depends(_, _) -> [{mod_muc, hard}].