Diff

plugins/muc/occupant_id.lib.lua @ 11215:9ce0a899ff07

MUC: Merge mod_muc_occupant_id into a sub-module (thanks pep.!)
author Matthew Wild <mwild1@gmail.com>
date Tue, 24 Nov 2020 10:38:56 +0000
child 12108:e9882c4c397f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/plugins/muc/occupant_id.lib.lua	Tue Nov 24 10:38:56 2020 +0000
@@ -0,0 +1,70 @@
+-- Implementation of https://xmpp.org/extensions/inbox/occupant-id.html
+-- XEP-0421: Anonymous unique occupant identifiers for MUCs
+
+-- (C) 2020 Maxime “pep” Buquet <pep@bouah.net>
+-- (C) 2020 Matthew Wild <mwild1@gmail.com>
+
+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 get_occupant_id(room, occupant)
+	if occupant.stable_id then
+		return occupant.stable_id;
+	end
+
+	local salt = room._data.occupant_id_salt;
+	if not salt then
+		salt = uuid.generate();
+		room._data.occupant_id_salt = salt;
+	end
+
+	occupant.stable_id = b64encode(hmac_sha256(occupant.bare_jid, salt));
+
+	return occupant.stable_id;
+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 = get_occupant_id(room, occupant);
+	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
+
+if module:get_option_boolean("muc_occupant_id", true) then
+	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);
+end
+
+return {
+	get_occupant_id = get_occupant_id;
+};