# HG changeset patch # User Matthew Wild # Date 1638728567 0 # Node ID 62a65c52c3f53b63475157c1cc00326c7d1c7c89 # Parent 80f871bedcdf0909869c0f4b60a0a9979094d533 mod_muc_rtbl: Real-time blocklist checks for MUC services diff -r 80f871bedcdf -r 62a65c52c3f5 mod_muc_rtbl/README.md --- /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. diff -r 80f871bedcdf -r 62a65c52c3f5 mod_muc_rtbl/mod_muc_rtbl.lua --- /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);