view mod_throttle_unsolicited/mod_throttle_unsolicited.lua @ 4688:05725276fac0

mod_bookmarks2: Use same default as mod_pep for max_items Should fix the issue with max items until the proper "max" can be used, by following the configured max. While "max" is already in trunk, it's not easily usable in 0.11.x This limit and option was added to mod_pep in Prosody rev aefb96a52f5f
author Kim Alvefur <zash@zash.se>
date Wed, 15 Sep 2021 17:39:37 +0200
parents 4d8a68557941
children
line wrap: on
line source

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 gettime = require "socket".gettime;

local max = module:get_option_number("unsolicited_messages_per_minute", 10);
local s2s_max = module:get_option_number("unsolicited_s2s_messages_per_minute");
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;
	if stanza.attr.type == "error" then return end

	local to_orig = stanza.attr.to;
	if to_orig == nil or to_orig == origin.full_jid then return end -- to self

	local to_bare = jid_bare(to_orig);
	local from_jid = jid_bare(stanza.attr.from);
	if to_bare == from_jid then return end -- to own resource

	-- Check if it's a message to a joined room
	local rooms = origin.rooms_joined;
	if rooms and rooms[to_bare] then
		return
	end

	-- Retrieve or create throttle object
	local lim = origin.throttle_unsolicited;
	if not lim then
		lim = throttle.create(max * multiplier, 60 * multiplier);
		origin.throttle_unsolicited = lim;
	end

	local to_user, to_host = jid_split(to_orig);
	if to_user and not is_contact_subscribed(to_user, to_host, from_jid) then
		log("debug", "[unsolicited] %s is not subscribed to %s@%s", from_jid, to_user, to_host);
		if not lim:poll(1) then
			log("warn", "[unsolicited] Sent too many messages to non-contacts, bouncing message");
			origin.firewall_mark_unsolicited = gettime();
			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);

local full_sessions = prosody.full_sessions;

-- Rooms and throttle creation will differ for s2s
function check_subscribed_s2s(event)
	local stanza, origin = event.stanza, event.origin;
	local log = origin.log or module._log;

	if origin.type ~= "s2sin" then return end

	local to_orig = stanza.attr.to;
	local from_orig = stanza.attr.from;
	local from_bare = jid_bare(from_orig);

	local target = full_sessions[to_orig];
	if target then
		local rooms = target.rooms_joined;
		if rooms and rooms[from_bare] then
			log("debug", "Message to joined room, no limit");
			return
		end
	end

	-- Retrieve or create throttle object
	local lim = origin.throttle_unsolicited;
	if not lim then
		log("debug", "New s2s throttle");
		lim = throttle.create(s2s_max * multiplier, 60 * multiplier);
		origin.throttle_unsolicited = lim;
	end

	return check_subscribed(event);
end

if s2s_max then
	module:hook("message/bare", check_subscribed_s2s, 200);
	module:hook("message/full", check_subscribed_s2s, 200);
end

module:depends("track_muc_joins");