changeset 4807:62a65c52c3f5

mod_muc_rtbl: Real-time blocklist checks for MUC services
author Matthew Wild <mwild1@gmail.com>
date Sun, 05 Dec 2021 18:22:47 +0000
parents 80f871bedcdf
children 8a63a0daf129
files mod_muc_rtbl/README.md mod_muc_rtbl/mod_muc_rtbl.lua
diffstat 2 files changed, 94 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_muc_rtbl/README.md	Sun Dec 05 18:22:47 2021 +0000
@@ -0,0 +1,45 @@
+---
+summary: 
+rockspec:
+  dependencies:
+  - mod_pubsub_subscription
+labels:
+- Stage-Alpha
+...
+
+This module subscribes to a real-time blocklist using pubsub (XEP-0060). As
+entries are added and removed from the blocklist, it immediately updates a
+local service-wide ban list.
+
+# Configuring
+
+Load this module on your existing MUC component like so:
+
+```lua
+Component "channels.example.com" "muc"
+modules_enabled = {
+	-- other modules etc
+	"muc_rtbl";
+}
+```
+
+Then there are two options, which must be set under the component or in the
+global section of your config:
+
+```
+muc_rtbl_jid = "rtbl.example"
+muc_rtbl_node = "muc_bans_sha256"
+```
+
+# Compatibility
+
+Should work with Prosody >= 0.11.x
+
+# Developers
+
+## Protocol
+
+This version of mod_muc_rtbl assumes that the pubsub node contains one item
+per blocked JID. The item id should be the SHA256 hash of the JID to block.
+The payload is not currently used, but it is recommend to use a XEP-0377
+report element as the payload.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_muc_rtbl/mod_muc_rtbl.lua	Sun Dec 05 18:22:47 2021 +0000
@@ -0,0 +1,49 @@
+local jid = require "util.jid";
+local sha256 = require "util.hashes".sha256;
+local st = require "util.stanza";
+
+local rtbl_service_jid = assert(module:get_option_string("muc_rtbl_jid"), "No RTBL JID supplied");
+local rtbl_node = module:get_option_string("muc_rtbl_node", "muc_bans_sha256");
+
+local banned_hashes = module:shared("banned_hashes");
+
+module:depends("pubsub_subscription");
+
+module:add_item("pubsub-subscription", {
+	service = rtbl_service_jid;
+	node = rtbl_node;
+
+	-- Callbacks:
+	on_subscribed = function()
+		module:log("info", "RTBL active");
+	end;
+
+	on_error = function(err)
+		module:log("error", "Failed to subscribe to RTBL: %s::%s:  %s", err.type, err.condition, err.text);
+	end;
+
+	on_item = function(event)
+		local hash = event.item.attr.id;
+		if not hash then return; end
+		module:log("debug", "Received new hash: %s", hash);
+		banned_hashes[hash] = hash;
+	end;
+
+	on_retract = function (event)
+		local hash = event.item.attr.id;
+		if not hash then return; end
+		module:log("debug", "Retracted hash: %s", hash);
+		banned_hashes[hash] = nil;
+	end;
+});
+
+module:hook("muc-occupant-pre-join", function (event)
+	local from_bare = jid.bare(event.stanza.attr.from);
+	local hash = sha256(jid.bare(event.stanza.attr.from), true);
+	if banned_hashes[hash] then
+		module:log("info", "Blocked user <%s> from room <%s> due to RTBL match", from_bare, event.stanza.attr.to);
+		local error_reply = st.error_reply(event.stanza, "cancel", "forbidden", "You are banned from this service", event.room.jid);
+		event.origin.send(error_reply);
+		return true;
+	end
+end);