changeset 3629:cfe0907808e1

mod_muc_occupant_id: initial commit Implementation of XEP-XXXX: Anonymous unique occupant identifiers for MUCs. https://dino.im/xeps/occupant-id.html
author Maxime “pep” Buquet <pep@bouah.net>
date Sun, 14 Jul 2019 18:45:10 +0200
parents 2444fb3b05b7
children c05e157d987c
files mod_muc_occupant_id/README.markdown mod_muc_occupant_id/mod_muc_occupant_id.lua
diffstat 2 files changed, 78 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_muc_occupant_id/README.markdown	Sun Jul 14 18:45:10 2019 +0200
@@ -0,0 +1,19 @@
+---
+labels:
+- 'Stage-Alpha'
+summary: 'Anonymous unique occupant identifiers for MUCs'
+...
+
+Introduction
+============
+
+This module implements [XEP-XXXX: Anonymous unique occupant identifiers for
+MUCs](https://dino.im/xeps/occupant-id.html).
+
+Compatibility
+=============
+
+  ------- ------------------
+  trunk   Works
+  0.11    Works
+  ------- ------------------
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_muc_occupant_id/mod_muc_occupant_id.lua	Sun Jul 14 18:45:10 2019 +0200
@@ -0,0 +1,59 @@
+
+-- Implementation of https://dino.im/xeps/occupant-id.html
+-- XEP-XXXX: Anonymous unique occupant identifiers for MUCs
+
+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 edit_occupant(event)
+	local occupant, room = event.occupant, event.room;
+	local bare = occupant.bare_jid;
+
+	-- TODO: Move the salt on the MUC component. Setting the salt on the room
+	-- can be problematic when the room is destroyed. Next time it's recreated
+	-- the salt will be different and so will be the unique_id. Or maybe we want
+	-- this anyway?
+	if room._data.occupant_id_salt == nil then
+		local salt = uuid.generate();
+		room._data.occupant_id_salt = salt;
+	end
+
+	local unique_id = b64encode(hmac_sha256(bare, room._data.occupant_id_salt));
+
+	-- TODO: Store this only once per bare jid and not once per occupant?
+	local stanza = event.stanza;
+	stanza:tag("occupant-id", { xmlns = xmlns_occupant_id })
+		:text(unique_id)
+		:up();
+end
+
+local function handle_stanza(event)
+	local stanza, occupant = event.stanza, event.occupant;
+
+	if stanza.name == "presence" and stanza.attr.type == "unavailable" then -- not required here
+		return;
+	end
+
+	-- strip any existing <occupant-id/> tags to avoid forgery
+	stanza:remove_children("occupant-id", xmlns_occupant_id);
+
+	if not occupant then return; end
+
+	local unique_id = occupant.sessions[stanza.attr.from]
+		:get_child("occupant-id", xmlns_occupant_id)
+		:get_text();
+	stanza:tag("occupant-id", { xmlns = xmlns_occupant_id })
+		:text(unique_id)
+		:up();
+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-occupant-pre-join", edit_occupant);
+module:hook("muc-occupant-groupchat", handle_stanza);