Changeset

2082:163d55777ad5

mod_throttle_unsolicited: Limit rate of unsolicited messages sent to non-contacts
author Kim Alvefur <zash@zash.se>
date Mon, 14 Mar 2016 13:36:50 +0100
parents 2081:73096d8d924c
children 2083:fed0a71a5e68
files mod_throttle_unsolicited/README.markdown mod_throttle_unsolicited/mod_throttle_unsolicited.lua
diffstat 2 files changed, 71 insertions(+), 0 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_throttle_unsolicited/README.markdown	Mon Mar 14 13:36:50 2016 +0100
@@ -0,0 +1,22 @@
+---
+depends:
+- 'mod\_track\_muc\_joins'
+summary: Limit rate of outgoing unsolicited messages
+...
+
+Introduction
+============
+
+This module limits the rate of outgoing unsolicited messages. A message
+counts as "unsolicited" if the receiving user hasn't added the sending
+user to their roster.
+
+The module depends on [mod\_track\_muc\_joins] in order to allow sent
+messages to joined MUC rooms.
+
+Configuration
+=============
+
+``` {.lua}
+unsolicited_messages_per_minute = 10
+```
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mod_throttle_unsolicited/mod_throttle_unsolicited.lua	Mon Mar 14 13:36:50 2016 +0100
@@ -0,0 +1,49 @@
+local st = require"util.stanza";
+local jid_split = require "util.jid".split;
+local jid_bare = require "util.jid".bare;
+local is_contact_subscribed = require "core.rostermanager".is_contact_subscribed;
+local throttle = require "util.throttle";
+
+local sessions = prosody.full_sessions;
+
+local max = module:get_option_number("unsolicited_messages_per_minute", 10);
+local multiplier = module:get_option_number("throttle_unsolicited_burst", 1);
+
+function check_subscribed(event)
+	local stanza, origin = event.stanza, event.origin;
+	local log = origin.log or module._log;
+	log("debug", "check_subscribed(%s)", stanza:top_tag());
+	if stanza.attr.type == "error" then return end
+
+	-- Check if it's a message to a joined room
+	local to_bare = jid_bare(stanza.attr.to);
+	local rooms = origin.rooms_joined;
+	if rooms and rooms[to_bare] then
+		log("debug", "Message to joined room, no limit");
+		return
+	end
+
+	-- Retrieve or create throttle object
+	local lim = origin.throttle_unsolicited;
+	if not lim then
+		log("debug", "New throttle");
+		lim = throttle.create(max * multiplier, 60 * multiplier);
+		origin.throttle_unsolicited = lim;
+	end
+
+	local to_user, to_host = jid_split(stanza.attr.to);
+	local from_jid = jid_bare(stanza.attr.from);
+	if to_user and not is_contact_subscribed(to_user, to_host, from_jid) then
+		log("debug", "%s is not subscribed to %s@%s", from_jid, to_user, to_host);
+		if not lim:poll(1) then
+			log("warn", "Sent too many messages to non-contacts, bouncing message");
+			event.origin.send(st.error_reply(stanza, "cancel", "service-unavailable"));
+			return true;
+		end
+	end
+end
+
+module:hook("pre-message/bare", check_subscribed, 200);
+module:hook("pre-message/full", check_subscribed, 200);
+
+module:depends("track_muc_joins");