Software /
code /
prosody-modules
File
mod_muc_limits/mod_muc_limits.lua @ 4049:78f1de5301fc
mod_adhoc_dataforms_demo: Fix duplicate field prevention
It's supposed to only include each type of form field once per form at
most but it didn't note which fields it had added already. No idea what
the probability was anyways, probably pretty low.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Tue, 23 Jun 2020 19:40:55 +0200 |
parent | 3965:2b10e51d85a6 |
child | 5564:731ba9400c10 |
line wrap: on
line source
local mod_muc = module:depends"muc"; local rooms = rawget(mod_muc, "rooms"); -- Old MUC API local jid_split, jid_bare = require "util.jid".split, require "util.jid".bare; local st = require "util.stanza"; local new_throttle = require "util.throttle".create; local t_insert, t_concat = table.insert, table.concat; local xmlns_muc = "http://jabber.org/protocol/muc"; local period = math.max(module:get_option_number("muc_event_rate", 0.5), 0); local burst = math.max(module:get_option_number("muc_burst_factor", 6), 1); local max_nick_length = module:get_option_number("muc_max_nick_length", 23); -- Default chosen through scientific methods local join_only = module:get_option_boolean("muc_limit_joins_only", false); local dropped_count = 0; local dropped_jids; local function log_dropped() module:log("warn", "Dropped %d stanzas from %d JIDs: %s", dropped_count, #dropped_jids, t_concat(dropped_jids, ", ")); dropped_count = 0; dropped_jids = nil; end local function handle_stanza(event) local origin, stanza = event.origin, event.stanza; if stanza.name == "presence" and stanza.attr.type == "unavailable" then -- Don't limit room leaving return; end local dest_room, dest_host, dest_nick = jid_split(stanza.attr.to); local room = event.room or rooms[dest_room.."@"..dest_host]; if not room then return; end local from_jid = stanza.attr.from; if room:get_affiliation(jid_bare(from_jid)) then module:log("debug", "Skipping stanza from affiliated user..."); return; elseif dest_nick and max_nick_length and stanza.name == "presence" and not room._occupants[stanza.attr.to] and #dest_nick > max_nick_length then module:log("debug", "Forbidding long (%d bytes) nick in %s", #dest_nick, dest_room) origin.send(st.error_reply(stanza, "modify", "policy-violation", "Your nick name is too long, please use a shorter one") :up():tag("x", { xmlns = xmlns_muc })); return true; end local throttle = room.throttle; if not room.throttle then throttle = new_throttle(period*burst, burst); room.throttle = throttle; end if not throttle:poll(1) then module:log("debug", "Dropping stanza for %s@%s from %s, over rate limit", dest_room, dest_host, from_jid); if not dropped_jids then dropped_jids = { [from_jid] = true, from_jid }; module:add_timer(5, log_dropped); elseif not dropped_jids[from_jid] then dropped_jids[from_jid] = true; t_insert(dropped_jids, from_jid); end dropped_count = dropped_count + 1; if stanza.attr.type == "error" then -- We don't want to bounce errors return true; end local reply = st.error_reply(stanza, "wait", "policy-violation", "The room is currently overactive, please try again later"); local body = stanza:get_child_text("body"); if body then reply:up():tag("body"):text(body):up(); end local x = stanza:get_child("x", xmlns_muc); if x then reply:add_child(st.clone(x)); end origin.send(reply); return true; end end if rooms then function module.unload() for room_jid, room in pairs(rooms) do --luacheck: ignore 213/room_jid room.throttle = nil; end end module:hook("presence/full", handle_stanza, 501); if not join_only then module:hook("message/bare", handle_stanza, 501); module:hook("message/full", handle_stanza, 501); module:hook("presence/bare", handle_stanza, 501); end else module:hook("muc-occupant-pre-join", handle_stanza); if not join_only then module:hook("muc-occupant-pre-change", handle_stanza); module:hook("muc-occupant-groupchat", handle_stanza); end end