view mod_muc_occupant_id/mod_muc_occupant_id.lua @ 5298:12f7d8b901e0

mod_audit: Support for adding location (GeoIP) to audit events This can be more privacy-friendly than logging full IP addresses, and also more informative to a user - IP addresses don't mean much to the average person, however if they see activity from outside their expected country, they can immediately identify suspicious activity. As with IPs, this field is configurable for deployments that would like to disable it. Location is also not logged when the geoip library is not available.
author Matthew Wild <mwild1@gmail.com>
date Sat, 01 Apr 2023 13:11:53 +0100 (21 months ago)
parents ae27f3359df8
children
line wrap: on
line source

-- Implementation of https://xmpp.org/extensions/inbox/occupant-id.html
-- XEP-0421: Anonymous unique occupant identifiers for MUCs

module:depends("muc");

local uuid = require "util.uuid";
local hmac_sha256 = require "util.hashes".hmac_sha256;
local b64encode = require "util.encodings".base64.encode;

local xmlns_occupant_id = "urn:xmpp:occupant-id:0";

local function generate_id(occupant, room)
	local bare = occupant.bare_jid;

	if room._data.occupant_id_salt == nil then
		room._data.occupant_id_salt = uuid.generate();
	end

	-- XXX: Temporary not-so-important migration measure. Remove this next time
	-- somebody looks at it. This module used to store every participant's
	-- occupant-id all the time forever.
	room._data.occupant_ids = nil;

	return b64encode(hmac_sha256(bare, room._data.occupant_id_salt));
end

local function update_occupant(event)
	local stanza, room, occupant, dest_occupant = event.stanza, event.room, event.occupant, event.dest_occupant;

	-- "muc-occupant-pre-change" provides "dest_occupant" but not "occupant".
	if dest_occupant ~= nil then
		occupant = dest_occupant;
	end

	-- strip any existing <occupant-id/> tags to avoid forgery
	stanza:remove_children("occupant-id", xmlns_occupant_id);

	local unique_id = generate_id(occupant, room);
	stanza:tag("occupant-id", { xmlns = xmlns_occupant_id, id = unique_id }):up();
end

local function muc_private(event)
	local stanza, room = event.stanza, event.room;
	local occupant = room._occupants[stanza.attr.from];

	update_occupant({
		stanza = stanza,
		room = room,
		occupant = occupant,
	});
end

module:add_feature(xmlns_occupant_id);
module:hook("muc-disco#info", function (event)
	event.reply:tag("feature", { var = xmlns_occupant_id }):up();
end);

module:hook("muc-broadcast-presence", update_occupant);
module:hook("muc-occupant-pre-join", update_occupant);
module:hook("muc-occupant-pre-change", update_occupant);
module:hook("muc-occupant-groupchat", update_occupant);
module:hook("muc-private-message", muc_private);