Files
upstream-jitsi-meet/resources/prosody-plugins/mod_muc_limit_messages.lua
upstream-mirror 1d2bfcac0c
Some checks failed
Prosody Plugin Tests / test (push) Failing after 10m11s
Close stale issues and PRs / stale (push) Failing after 1s
snapshot of https://github.com/jitsi/jitsi-meet.git @ fd1749dd28f4138aa80234fc7f311b19aaffa0e7 (2026-09-15)
2026-09-15 15:56:32 +05:00

110 lines
4.1 KiB
Lua

-- Enforces a per-room message count cap (muc_limit_messages_count). Once the cap
-- is reached the triggering message is rejected with <not-allowed/>, a broadcast
-- is sent to the room, and all further messages are rejected. Messages from
-- sessions without room context (no jitsi_web_query_room) are passed through.
-- Body-less non-groupchat messages and answer-poll json-messages are exempt from
-- counting. With muc_limit_messages_check_token = true an authenticated sender
-- permanently lifts the cap for that room.
-- Needs to be activated under the muc component where the limit needs to be applied
-- Copyright (C) 2023-present 8x8, Inc.
local id = require 'util.id';
local st = require 'util.stanza';
local get_room_by_name_and_subdomain = module:require 'util'.get_room_by_name_and_subdomain;
local count;
local check_token;
local function load_config()
count = module:get_option_number('muc_limit_messages_count');
check_token = module:get_option_boolean('muc_limit_messages_check_token', false);
end
load_config();
if not count then
module:log('warn', "No 'muc_limit_messages_count' option set, disabling module");
return
end
module:log('info', 'Loaded muc limits for %s, limit:%s, will check for authenticated users:%s',
module.host, count, check_token);
local error_text = 'The message limit for the room has been reached. Messaging is now disabled.';
function on_message(event)
local stanza = event.stanza;
local body = stanza:get_child('body');
-- we ignore any non groupchat message without a body
if not body then
if stanza.attr.type ~= 'groupchat' then -- lobby messages
return;
else
-- we want to pass through only polls answers
local json_data = stanza:get_child_text('json-message', 'http://jitsi.org/jitmeet');
if json_data and string.find(json_data, 'answer-poll', 1, true) then
return;
end
end
end
local session = event.origin;
if not session or not session.jitsi_web_query_room then
-- No room context: cannot apply limits, pass through.
-- (Visitor messages from s2sin are also passed through — limits enforced at visitor node.)
return;
end
-- get room name with tenant and find room
local room = get_room_by_name_and_subdomain(session.jitsi_web_query_room, session.jitsi_web_query_prefix);
if not room then
module:log('warn', 'No room found for %s/%s',
session.jitsi_web_query_prefix, session.jitsi_web_query_room);
return;
end
if check_token and session.auth_token then
-- there is an authenticated participant drop all limits
room._muc_messages_limit = false;
end
if room._muc_messages_limit == false then
-- no limits for this room, just skip
return;
end
if not room._muc_messages_limit_count then
room._muc_messages_limit_count = 0;
end
room._muc_messages_limit_count = room._muc_messages_limit_count + 1;
-- on the first message above the limit we set the limit and we send an announcement to the room
if room._muc_messages_limit_count == count + 1 then
module:log('warn', 'Room message limit reached: %s', room.jid);
-- send a message to the room
local announcement = st.message({ from = room.jid, type = 'groupchat', id = id.medium(), })
:tag('body'):text(error_text);
room:broadcast_message(announcement);
room._muc_messages_limit = true;
end
if room._muc_messages_limit == true then
-- return error to the sender of this message
event.origin.send(st.error_reply(stanza, 'cancel', 'not-allowed', error_text));
return true;
end
end
-- handle messages sent in the component
-- 'message/host' is used for breakout rooms
-- Priority -1 ensures modules at the default priority (0) — notably
-- filter_messages — run first. Messages they block (return true) never reach
-- this handler and do not consume cap slots.
module:hook('message/full', on_message, -1); -- private messages
module:hook('message/bare', on_message, -1); -- room messages
module:hook_global('config-reloaded', load_config);