diff mod_muc_rtbl/mod_muc_rtbl.lua @ 4808:8a63a0daf129

mod_muc_rtbl: Sync existing list entries when first loaded
author Matthew Wild <mwild1@gmail.com>
date Mon, 06 Dec 2021 10:36:02 +0000
parents 62a65c52c3f5
children 9e9ec0f0b128
line wrap: on
line diff
--- a/mod_muc_rtbl/mod_muc_rtbl.lua	Sun Dec 05 18:22:47 2021 +0000
+++ b/mod_muc_rtbl/mod_muc_rtbl.lua	Mon Dec 06 10:36:02 2021 +0000
@@ -1,5 +1,8 @@
+local array = require "util.array";
+local it = require "util.iterators";
 local jid = require "util.jid";
 local sha256 = require "util.hashes".sha256;
+local set = require "util.set";
 local st = require "util.stanza";
 
 local rtbl_service_jid = assert(module:get_option_string("muc_rtbl_jid"), "No RTBL JID supplied");
@@ -26,7 +29,7 @@
 		local hash = event.item.attr.id;
 		if not hash then return; end
 		module:log("debug", "Received new hash: %s", hash);
-		banned_hashes[hash] = hash;
+		banned_hashes[hash] = true;
 	end;
 
 	on_retract = function (event)
@@ -37,6 +40,57 @@
 	end;
 });
 
+function request_list()
+	local items_request = st.iq({ to = rtbl_service_jid, from = module.host, type = "get", id = "rtbl-request" })
+		:tag("pubsub", { xmlns = "http://jabber.org/protocol/pubsub" })
+			:tag("items", { node = rtbl_node }):up()
+		:up();
+
+	module:send(items_request);
+end
+
+function update_list(event)
+	local from_jid = event.stanza.attr.from;
+	if from_jid ~= rtbl_service_jid then
+		module:log("debug", "Ignoring RTBL response from unknown sender");
+		return;
+	end
+	local items_el = event.stanza:find("{http://jabber.org/protocol/pubsub}pubsub/items");
+	if not items_el then
+		module:log("warn", "Invalid items response from RTBL service");
+		return;
+	end
+
+	local old_entries = set.new(array.collect(it.keys(banned_hashes)));
+
+	local n_added, n_removed, n_total = 0, 0, 0;
+	for item in items_el:childtags("item") do
+		local hash = item.attr.id;
+		if hash then
+			n_total = n_total + 1;
+			if not old_entries:contains(hash) then
+				-- New entry
+				n_added = n_added + 1;
+				banned_hashes[hash] = true;
+			else
+				-- Entry already existed
+				old_entries:remove(hash);
+			end
+		end
+	end
+
+	-- Remove old entries that weren't in the received list
+	for hash in old_entries do
+		n_removed = n_removed + 1;
+		banned_hashes[hash] = nil;
+	end
+
+	module:log("info", "%d RTBL entries received from %s (%d added, %d removed)", n_total, from_jid, n_added, n_removed);
+	return true;
+end
+
+module:hook("iq-result/host/rtbl-request", update_list);
+
 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);
@@ -47,3 +101,9 @@
 		return true;
 	end
 end);
+
+if prosody.start_time then
+	request_list();
+else
+	module:hook("server-started", request_list);
+end