view mod_throttle_unsolicited/mod_throttle_unsolicited.lua @ 5466:398d936e77fb

mod_http_oauth2: Add support for the OpenID 'login_hint' parameter This allows the client to suggest to the authorization screen which user is trying to login, so they don't have to fill that in twice if they already did so at the client.
author Kim Alvefur <zash@zash.se>
date Wed, 17 May 2023 18:49:22 +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");