diff options
Diffstat (limited to 'plugins/muc')
-rw-r--r-- | plugins/muc/hats.lib.lua | 19 | ||||
-rw-r--r-- | plugins/muc/hidden.lib.lua | 8 | ||||
-rw-r--r-- | plugins/muc/history.lib.lua | 6 | ||||
-rw-r--r-- | plugins/muc/lock.lib.lua | 4 | ||||
-rw-r--r-- | plugins/muc/members_only.lib.lua | 2 | ||||
-rw-r--r-- | plugins/muc/mod_muc.lua | 98 | ||||
-rw-r--r-- | plugins/muc/muc.lib.lua | 39 | ||||
-rw-r--r-- | plugins/muc/occupant.lib.lua | 2 | ||||
-rw-r--r-- | plugins/muc/occupant_id.lib.lua | 6 | ||||
-rw-r--r-- | plugins/muc/password.lib.lua | 2 | ||||
-rw-r--r-- | plugins/muc/persistent.lib.lua | 11 | ||||
-rw-r--r-- | plugins/muc/presence_broadcast.lib.lua | 2 | ||||
-rw-r--r-- | plugins/muc/register.lib.lua | 12 | ||||
-rw-r--r-- | plugins/muc/request.lib.lua | 6 | ||||
-rw-r--r-- | plugins/muc/restrict_pm.lib.lua | 119 | ||||
-rw-r--r-- | plugins/muc/subject.lib.lua | 4 |
16 files changed, 245 insertions, 95 deletions
diff --git a/plugins/muc/hats.lib.lua b/plugins/muc/hats.lib.lua index 358e5100..7eb71eb4 100644 --- a/plugins/muc/hats.lib.lua +++ b/plugins/muc/hats.lib.lua @@ -1,7 +1,10 @@ -local st = require "util.stanza"; +local st = require "prosody.util.stanza"; local muc_util = module:require "muc/util"; -local xmlns_hats = "xmpp:prosody.im/protocol/hats:1"; +local hats_compat = module:get_option_boolean("muc_hats_compat", true); -- COMPAT for pre-XEP namespace, TODO reconsider default for next release + +local xmlns_hats_legacy = "xmpp:prosody.im/protocol/hats:1"; +local xmlns_hats = "urn:xmpp:hats:0"; -- Strip any hats claimed by the client (to prevent spoofing) muc_util.add_filtered_namespace(xmlns_hats); @@ -13,14 +16,26 @@ module:hook("muc-build-occupant-presence", function (event) local hats = aff_data and aff_data.hats; if not hats then return; end local hats_el; + local legacy_hats_el; for hat_id, hat_data in pairs(hats) do if hat_data.active then if not hats_el then hats_el = st.stanza("hats", { xmlns = xmlns_hats }); end hats_el:tag("hat", { uri = hat_id, title = hat_data.title }):up(); + + if hats_compat then + if not legacy_hats_el then + legacy_hats_el = st.stanza("hats", { xmlns = xmlns_hats_legacy }); + end + legacy_hats_el:tag("hat", { uri = hat_id, title = hat_data.title }):up(); + end end end if not hats_el then return; end event.stanza:add_direct_child(hats_el); + + if legacy_hats_el then + event.stanza:add_direct_child(legacy_hats_el); + end end); diff --git a/plugins/muc/hidden.lib.lua b/plugins/muc/hidden.lib.lua index 153df21a..d24fa47e 100644 --- a/plugins/muc/hidden.lib.lua +++ b/plugins/muc/hidden.lib.lua @@ -8,7 +8,7 @@ -- local restrict_public = not module:get_option_boolean("muc_room_allow_public", true); -local um_is_admin = require "core.usermanager".is_admin; +module:default_permission(restrict_public and "prosody:admin" or "prosody:registered", ":create-public-room"); local function get_hidden(room) return room._data.hidden; @@ -22,8 +22,8 @@ local function set_hidden(room, hidden) end module:hook("muc-config-form", function(event) - if restrict_public and not um_is_admin(event.actor, module.host) then - -- Don't show option if public rooms are restricted and user is not admin of this host + if not module:may(":create-public-room", event.actor) then + -- Hide config option if this user is not allowed to create public rooms return; end table.insert(event.form, { @@ -36,7 +36,7 @@ module:hook("muc-config-form", function(event) end, 100-9); module:hook("muc-config-submitted/muc#roomconfig_publicroom", function(event) - if restrict_public and not um_is_admin(event.actor, module.host) then + if not module:may(":create-public-room", event.actor) then return; -- Not allowed end if set_hidden(event.room, not event.value) then diff --git a/plugins/muc/history.lib.lua b/plugins/muc/history.lib.lua index 075b1890..005bd1d8 100644 --- a/plugins/muc/history.lib.lua +++ b/plugins/muc/history.lib.lua @@ -8,11 +8,11 @@ -- local gettime = os.time; -local datetime = require "util.datetime"; -local st = require "util.stanza"; +local datetime = require "prosody.util.datetime"; +local st = require "prosody.util.stanza"; local default_history_length = 20; -local max_history_length = module:get_option_number("max_history_messages", math.huge); +local max_history_length = module:get_option_integer("max_history_messages", math.huge, 0); local function set_max_history_length(_max_history_length) max_history_length = _max_history_length or math.huge; diff --git a/plugins/muc/lock.lib.lua b/plugins/muc/lock.lib.lua index 32f2647b..bb5bf82b 100644 --- a/plugins/muc/lock.lib.lua +++ b/plugins/muc/lock.lib.lua @@ -7,10 +7,10 @@ -- COPYING file in the source package for more information. -- -local st = require "util.stanza"; +local st = require "prosody.util.stanza"; local lock_rooms = module:get_option_boolean("muc_room_locking", true); -local lock_room_timeout = module:get_option_number("muc_room_lock_timeout", 300); +local lock_room_timeout = module:get_option_period("muc_room_lock_timeout", "5 minutes"); local function lock(room) module:fire_event("muc-room-locked", {room = room;}); diff --git a/plugins/muc/members_only.lib.lua b/plugins/muc/members_only.lib.lua index b10dc120..4f4e88fa 100644 --- a/plugins/muc/members_only.lib.lua +++ b/plugins/muc/members_only.lib.lua @@ -7,7 +7,7 @@ -- COPYING file in the source package for more information. -- -local st = require "util.stanza"; +local st = require "prosody.util.stanza"; local muc_util = module:require "muc/util"; local valid_affiliations = muc_util.valid_affiliations; diff --git a/plugins/muc/mod_muc.lua b/plugins/muc/mod_muc.lua index 5873b1a2..1dc99f07 100644 --- a/plugins/muc/mod_muc.lua +++ b/plugins/muc/mod_muc.lua @@ -86,21 +86,26 @@ room_mt.get_registered_nick = register.get_registered_nick; room_mt.get_registered_jid = register.get_registered_jid; room_mt.handle_register_iq = register.handle_register_iq; +local restrict_pm = module:require "muc/restrict_pm"; +room_mt.get_allow_pm = restrict_pm.get_allow_pm; +room_mt.set_allow_pm = restrict_pm.set_allow_pm; +room_mt.get_allow_modpm = restrict_pm.get_allow_modpm; +room_mt.set_allow_modpm = restrict_pm.set_allow_modpm; + local presence_broadcast = module:require "muc/presence_broadcast"; room_mt.get_presence_broadcast = presence_broadcast.get; room_mt.set_presence_broadcast = presence_broadcast.set; -room_mt.get_valid_broadcast_roles = presence_broadcast.get_valid_broadcast_roles; +room_mt.get_valid_broadcast_roles = presence_broadcast.get_valid_broadcast_roles; -- FIXME doesn't exist in the library local occupant_id = module:require "muc/occupant_id"; room_mt.get_salt = occupant_id.get_room_salt; room_mt.get_occupant_id = occupant_id.get_occupant_id; -local jid_split = require "util.jid".split; -local jid_prep = require "util.jid".prep; -local jid_bare = require "util.jid".bare; -local st = require "util.stanza"; -local cache = require "util.cache"; -local um_is_admin = require "core.usermanager".is_admin; +local jid_split = require "prosody.util.jid".split; +local jid_prep = require "prosody.util.jid".prep; +local jid_bare = require "prosody.util.jid".bare; +local st = require "prosody.util.stanza"; +local cache = require "prosody.util.cache"; module:require "muc/config_form_sections"; @@ -111,21 +116,26 @@ module:depends "muc_unique" module:require "muc/hats"; module:require "muc/lock"; -local function is_admin(jid) - return um_is_admin(jid, module.host); -end +module:default_permissions("prosody:admin", { + ":automatic-ownership"; + ":create-room"; + ":recreate-destroyed-room"; +}); +module:default_permissions("prosody:guest", { + ":list-rooms"; +}); -if module:get_option_boolean("component_admins_as_room_owners", true) then +if module:get_option_boolean("component_admins_as_room_owners", false) then -- Monkey patch to make server admins room owners local _get_affiliation = room_mt.get_affiliation; function room_mt:get_affiliation(jid) - if is_admin(jid) then return "owner"; end + if module:could(":automatic-ownership", jid) then return "owner"; end return _get_affiliation(self, jid); end local _set_affiliation = room_mt.set_affiliation; function room_mt:set_affiliation(actor, jid, affiliation, reason, data) - if affiliation ~= "owner" and is_admin(jid) then return nil, "modify", "not-acceptable"; end + if affiliation ~= "owner" and module:could(":automatic-ownership", jid) then return nil, "modify", "not-acceptable"; end return _set_affiliation(self, actor, jid, affiliation, reason, data); end end @@ -158,8 +168,8 @@ local function room_save(room, forced, savestate) end end -local max_rooms = module:get_option_number("muc_max_rooms"); -local max_live_rooms = module:get_option_number("muc_room_cache_size", 100); +local max_rooms = module:get_option_integer("muc_max_rooms", nil, 0); +local max_live_rooms = module:get_option_integer("muc_room_cache_size", 100, 1); local room_hit = module:measure("room_hit", "rate"); local room_miss = module:measure("room_miss", "rate") @@ -281,15 +291,16 @@ local function set_room_defaults(room, lang) room:set_public(module:get_option_boolean("muc_room_default_public", false)); room:set_persistent(module:get_option_boolean("muc_room_default_persistent", room:get_persistent())); room:set_members_only(module:get_option_boolean("muc_room_default_members_only", room:get_members_only())); - room:set_allow_member_invites(module:get_option_boolean("muc_room_default_allow_member_invites", - room:get_allow_member_invites())); + room:set_allow_member_invites(module:get_option_boolean("muc_room_default_allow_member_invites", room:get_allow_member_invites())); room:set_moderated(module:get_option_boolean("muc_room_default_moderated", room:get_moderated())); - room:set_whois(module:get_option_boolean("muc_room_default_public_jids", - room:get_whois() == "anyone") and "anyone" or "moderators"); + room:set_whois(module:get_option_boolean("muc_room_default_public_jids", room:get_whois() == "anyone") and "anyone" or "moderators"); room:set_changesubject(module:get_option_boolean("muc_room_default_change_subject", room:get_changesubject())); - room:set_historylength(module:get_option_number("muc_room_default_history_length", room:get_historylength())); + room:set_historylength(module:get_option_integer("muc_room_default_history_length", room:get_historylength(), 0)); room:set_language(lang or module:get_option_string("muc_room_default_language")); - room:set_presence_broadcast(module:get_option("muc_room_default_presence_broadcast", room:get_presence_broadcast())); + room:set_presence_broadcast(module:get_option_enum("muc_room_default_presence_broadcast", room:get_presence_broadcast(), "visitor", "participant", + "moderator")); + room:set_allow_pm(module:get_option_enum("muc_room_default_allow_pm", room:get_allow_pm(), "visitor", "participant", "moderator")); + room:set_allow_modpm(module:get_option_boolean("muc_room_default_always_allow_moderator_pms", room:get_allow_modpm())); end function create_room(room_jid, config) @@ -350,8 +361,12 @@ function each_room(live_only) end module:hook("host-disco-items", function(event) - local reply = event.reply; module:log("debug", "host-disco-items called"); + if not module:could(":list-rooms", event) then + module:log("debug", "Returning empty room list to unauthorized request"); + return; + end + local reply = event.reply; if next(room_items_cache) ~= nil then for jid, room_name in pairs(room_items_cache) do if room_name == "" then room_name = nil; end @@ -388,7 +403,7 @@ end); if module:get_option_boolean("muc_tombstones", true) then - local ttl = module:get_option_number("muc_tombstone_expiry", 86400 * 31); + local ttl = module:get_option_period("muc_tombstone_expiry", "31 days"); module:hook("muc-room-destroyed",function(event) local room = event.room; @@ -412,26 +427,15 @@ if module:get_option_boolean("muc_tombstones", true) then end, -10); end -do - local restrict_room_creation = module:get_option("restrict_room_creation"); - if restrict_room_creation == true then - restrict_room_creation = "admin"; - end - if restrict_room_creation then - local host_suffix = module.host:gsub("^[^%.]+%.", ""); - module:hook("muc-room-pre-create", function(event) - local origin, stanza = event.origin, event.stanza; - local user_jid = stanza.attr.from; - if not is_admin(user_jid) and not ( - restrict_room_creation == "local" and - select(2, jid_split(user_jid)) == host_suffix - ) then - origin.send(st.error_reply(stanza, "cancel", "not-allowed", "Room creation is restricted", module.host)); - return true; - end - end); +local restrict_room_creation = module:get_option_enum("restrict_room_creation", false, true, "local"); +module:default_permission(restrict_room_creation == true and "prosody:admin" or "prosody:registered", ":create-room"); +module:hook("muc-room-pre-create", function(event) + local origin, stanza = event.origin, event.stanza; + if restrict_room_creation ~= false and not module:may(":create-room", event) then + origin.send(st.error_reply(stanza, "cancel", "not-allowed", "Room creation is restricted", module.host)); + return true; end -end +end); for event_name, method in pairs { -- Normal room interactions @@ -465,7 +469,7 @@ for event_name, method in pairs { if room and room._data.destroyed then if room._data.locked < os.time() - or (is_admin(stanza.attr.from) and stanza.name == "presence" and stanza.attr.type == nil) then + or (module:may(":recreate-destroyed-room", event) and stanza.name == "presence" and stanza.attr.type == nil) then -- Allow the room to be recreated by admin or after time has passed delete_room(room); room = nil; @@ -516,10 +520,10 @@ do -- Ad-hoc commands module:depends "adhoc"; local t_concat = table.concat; local adhoc_new = module:require "adhoc".new; - local adhoc_initial = require "util.adhoc".new_initial_data_form; - local adhoc_simple = require "util.adhoc".new_simple_form; - local array = require "util.array"; - local dataforms_new = require "util.dataforms".new; + local adhoc_initial = require "prosody.util.adhoc".new_initial_data_form; + local adhoc_simple = require "prosody.util.adhoc".new_simple_form; + local array = require "prosody.util.array"; + local dataforms_new = require "prosody.util.dataforms".new; local destroy_rooms_layout = dataforms_new { title = "Destroy rooms"; diff --git a/plugins/muc/muc.lib.lua b/plugins/muc/muc.lib.lua index 01427dbe..b8f276cf 100644 --- a/plugins/muc/muc.lib.lua +++ b/plugins/muc/muc.lib.lua @@ -12,18 +12,18 @@ local pairs = pairs; local next = next; local setmetatable = setmetatable; -local dataform = require "util.dataforms"; -local iterators = require "util.iterators"; -local jid_split = require "util.jid".split; -local jid_bare = require "util.jid".bare; -local jid_prep = require "util.jid".prep; -local jid_join = require "util.jid".join; -local jid_resource = require "util.jid".resource; -local resourceprep = require "util.encodings".stringprep.resourceprep; -local st = require "util.stanza"; -local base64 = require "util.encodings".base64; -local hmac_sha256 = require "util.hashes".hmac_sha256; -local new_id = require "util.id".medium; +local dataform = require "prosody.util.dataforms"; +local iterators = require "prosody.util.iterators"; +local jid_split = require "prosody.util.jid".split; +local jid_bare = require "prosody.util.jid".bare; +local jid_prep = require "prosody.util.jid".prep; +local jid_join = require "prosody.util.jid".join; +local jid_resource = require "prosody.util.jid".resource; +local resourceprep = require "prosody.util.encodings".stringprep.resourceprep; +local st = require "prosody.util.stanza"; +local base64 = require "prosody.util.encodings".base64; +local hmac_sha256 = require "prosody.util.hashes".hmac_sha256; +local new_id = require "prosody.util.id".medium; local log = module._log; @@ -1079,7 +1079,10 @@ function room_mt:handle_admin_query_set_command(origin, stanza) local reason = item:get_child_text("reason"); local success, errtype, err if item.attr.affiliation and item.attr.jid and not item.attr.role then - local registration_data; + local registration_data = self:get_affiliation_data(item.attr.jid) or {}; + if reason then + registration_data.reason = reason; + end if item.attr.nick then local room_nick = self.jid.."/"..item.attr.nick; local existing_occupant = self:get_occupant_by_nick(room_nick); @@ -1088,7 +1091,7 @@ function room_mt:handle_admin_query_set_command(origin, stanza) self:set_role(true, room_nick, nil, "This nickname is reserved"); end module:log("debug", "Reserving %s for %s (%s)", item.attr.nick, item.attr.jid, item.attr.affiliation); - registration_data = { reserved_nickname = item.attr.nick }; + registration_data.reserved_nickname = item.attr.nick; end success, errtype, err = self:set_affiliation(actor, item.attr.jid, item.attr.affiliation, reason, registration_data); elseif item.attr.role and item.attr.nick and not item.attr.affiliation then @@ -1119,9 +1122,13 @@ function room_mt:handle_admin_query_get_command(origin, stanza) if (affiliation_rank >= valid_affiliations.admin and affiliation_rank >= _aff_rank) or (self:get_members_only() and self:get_whois() == "anyone" and affiliation_rank >= valid_affiliations.member) then local reply = st.reply(stanza):query("http://jabber.org/protocol/muc#admin"); - for jid in self:each_affiliation(_aff or "none") do + for jid, _, data in self:each_affiliation(_aff or "none") do local nick = self:get_registered_nick(jid); - reply:tag("item", {affiliation = _aff, jid = jid, nick = nick }):up(); + reply:tag("item", {affiliation = _aff, jid = jid, nick = nick }); + if data and data.reason then + reply:text_tag("reason", data.reason); + end + reply:up(); end origin.send(reply:up()); return true; diff --git a/plugins/muc/occupant.lib.lua b/plugins/muc/occupant.lib.lua index 8fe4bbdf..a7d9cef7 100644 --- a/plugins/muc/occupant.lib.lua +++ b/plugins/muc/occupant.lib.lua @@ -1,6 +1,6 @@ local pairs = pairs; local setmetatable = setmetatable; -local st = require "util.stanza"; +local st = require "prosody.util.stanza"; local util = module:require "muc/util"; local function get_filtered_presence(stanza) diff --git a/plugins/muc/occupant_id.lib.lua b/plugins/muc/occupant_id.lib.lua index 1d310b3d..b1081c9b 100644 --- a/plugins/muc/occupant_id.lib.lua +++ b/plugins/muc/occupant_id.lib.lua @@ -4,9 +4,9 @@ -- (C) 2020 Maxime “pep” Buquet <pep@bouah.net> -- (C) 2020 Matthew Wild <mwild1@gmail.com> -local uuid = require "util.uuid"; -local hmac_sha256 = require "util.hashes".hmac_sha256; -local b64encode = require "util.encodings".base64.encode; +local uuid = require "prosody.util.uuid"; +local hmac_sha256 = require "prosody.util.hashes".hmac_sha256; +local b64encode = require "prosody.util.encodings".base64.encode; local xmlns_occupant_id = "urn:xmpp:occupant-id:0"; diff --git a/plugins/muc/password.lib.lua b/plugins/muc/password.lib.lua index dd3cb658..9d3c0cca 100644 --- a/plugins/muc/password.lib.lua +++ b/plugins/muc/password.lib.lua @@ -7,7 +7,7 @@ -- COPYING file in the source package for more information. -- -local st = require "util.stanza"; +local st = require "prosody.util.stanza"; local function get_password(room) return room._data.password; diff --git a/plugins/muc/persistent.lib.lua b/plugins/muc/persistent.lib.lua index c3b16ea4..29ed7784 100644 --- a/plugins/muc/persistent.lib.lua +++ b/plugins/muc/persistent.lib.lua @@ -8,7 +8,10 @@ -- local restrict_persistent = not module:get_option_boolean("muc_room_allow_persistent", true); -local um_is_admin = require "core.usermanager".is_admin; +module:default_permission( + restrict_persistent and "prosody:admin" or "prosody:registered", + ":create-persistent-room" +); local function get_persistent(room) return room._data.persistent; @@ -22,8 +25,8 @@ local function set_persistent(room, persistent) end module:hook("muc-config-form", function(event) - if restrict_persistent and not um_is_admin(event.actor, module.host) then - -- Don't show option if hidden rooms are restricted and user is not admin of this host + if not module:may(":create-persistent-room", event.actor) then + -- Hide config option if this user is not allowed to create persistent rooms return; end table.insert(event.form, { @@ -36,7 +39,7 @@ module:hook("muc-config-form", function(event) end, 100-5); module:hook("muc-config-submitted/muc#roomconfig_persistentroom", function(event) - if restrict_persistent and not um_is_admin(event.actor, module.host) then + if not module:may(":create-persistent-room", event.actor) then return; -- Not allowed end if set_persistent(event.room, event.value) then diff --git a/plugins/muc/presence_broadcast.lib.lua b/plugins/muc/presence_broadcast.lib.lua index 82a89fee..721c47aa 100644 --- a/plugins/muc/presence_broadcast.lib.lua +++ b/plugins/muc/presence_broadcast.lib.lua @@ -7,7 +7,7 @@ -- COPYING file in the source package for more information. -- -local st = require "util.stanza"; +local st = require "prosody.util.stanza"; local valid_roles = { "none", "visitor", "participant", "moderator" }; local default_broadcast = { diff --git a/plugins/muc/register.lib.lua b/plugins/muc/register.lib.lua index 84045f33..82ccb8ea 100644 --- a/plugins/muc/register.lib.lua +++ b/plugins/muc/register.lib.lua @@ -1,8 +1,8 @@ -local jid_bare = require "util.jid".bare; -local jid_resource = require "util.jid".resource; -local resourceprep = require "util.encodings".stringprep.resourceprep; -local st = require "util.stanza"; -local dataforms = require "util.dataforms"; +local jid_bare = require "prosody.util.jid".bare; +local jid_resource = require "prosody.util.jid".resource; +local resourceprep = require "prosody.util.encodings".stringprep.resourceprep; +local st = require "prosody.util.stanza"; +local dataforms = require "prosody.util.dataforms"; local allow_unaffiliated = module:get_option_boolean("allow_unaffiliated_register", false); @@ -94,8 +94,10 @@ local function enforce_nick_policy(event) local nick = get_registered_nick(room, jid_bare(stanza.attr.from)); if nick then if event.occupant then + -- someone is joining, force their nickname to the registered one event.occupant.nick = jid_bare(event.occupant.nick) .. "/" .. nick; elseif event.dest_occupant.nick ~= jid_bare(event.dest_occupant.nick) .. "/" .. nick then + -- someone is trying to change nickname to something other than their registered nickname, can't have that module:log("debug", "Attempt by %s to join as %s, but their reserved nick is %s", stanza.attr.from, requested_nick, nick); local reply = st.error_reply(stanza, "cancel", "not-acceptable", nil, room.jid):up(); origin.send(reply); diff --git a/plugins/muc/request.lib.lua b/plugins/muc/request.lib.lua index 4e95fdc3..f3786595 100644 --- a/plugins/muc/request.lib.lua +++ b/plugins/muc/request.lib.lua @@ -7,14 +7,14 @@ -- COPYING file in the source package for more information. -- -local st = require "util.stanza"; -local jid_resource = require "util.jid".resource; +local st = require "prosody.util.stanza"; +local jid_resource = require "prosody.util.jid".resource; module:hook("muc-disco#info", function(event) event.reply:tag("feature", {var = "http://jabber.org/protocol/muc#request"}):up(); end); -local voice_request_form = require "util.dataforms".new({ +local voice_request_form = require "prosody.util.dataforms".new({ title = "Voice Request"; { name = "FORM_TYPE"; diff --git a/plugins/muc/restrict_pm.lib.lua b/plugins/muc/restrict_pm.lib.lua new file mode 100644 index 00000000..e0b25cc8 --- /dev/null +++ b/plugins/muc/restrict_pm.lib.lua @@ -0,0 +1,119 @@ +-- Based on code from mod_muc_restrict_pm in prosody-modules@d82c0383106a +-- by Nicholas George <wirlaburla@worlio.com> + +local st = require "util.stanza"; +local muc_util = module:require "muc/util"; +local valid_roles = muc_util.valid_roles; + +-- COMPAT w/ prosody-modules allow_pm +local compat_map = { + everyone = "visitor"; + participants = "participant"; + moderators = "moderator"; + members = "affiliated"; +}; + +local function get_allow_pm(room) + local val = room._data.allow_pm; + return compat_map[val] or val or "visitor"; +end + +local function set_allow_pm(room, val) + if get_allow_pm(room) == val then return false; end + room._data.allow_pm = val; + return true; +end + +local function get_allow_modpm(room) + return room._data.allow_modpm or false; +end + +local function set_allow_modpm(room, val) + if get_allow_modpm(room) == val then return false; end + room._data.allow_modpm = val; + return true; +end + +module:hook("muc-config-form", function(event) + local pmval = get_allow_pm(event.room); + table.insert(event.form, { + name = 'muc#roomconfig_allowpm'; + type = 'list-single'; + label = 'Allow private messages from'; + options = { + { value = 'visitor', label = 'Everyone', default = pmval == 'visitor' }; + { value = 'participant', label = 'Participants', default = pmval == 'participant' }; + { value = 'moderator', label = 'Moderators', default = pmval == 'moderator' }; + { value = 'affiliated', label = "Members", default = pmval == "affiliated" }; + { value = 'none', label = 'No one', default = pmval == 'none' }; + } + }); + table.insert(event.form, { + name = '{xmpp:prosody.im}muc#allow_modpm'; + type = 'boolean'; + label = 'Always allow private messages to moderators'; + value = get_allow_modpm(event.room) + }); +end); + +module:hook("muc-config-submitted/muc#roomconfig_allowpm", function(event) + if set_allow_pm(event.room, event.value) then + event.status_codes["104"] = true; + end +end); + +module:hook("muc-config-submitted/{xmpp:prosody.im}muc#allow_modpm", function(event) + if set_allow_modpm(event.room, event.value) then + event.status_codes["104"] = true; + end +end); + +local who_restricted = { + none = "in this group"; + participant = "from guests"; + moderator = "from non-moderators"; + affiliated = "from non-members"; +}; + +module:hook("muc-private-message", function(event) + local stanza, room = event.stanza, event.room; + local from_occupant = room:get_occupant_by_nick(stanza.attr.from); + local to_occupant = room:get_occupant_by_nick(stanza.attr.to); + + -- To self is always okay + if to_occupant.bare_jid == from_occupant.bare_jid then return; end + + if get_allow_modpm(room) then + if to_occupant and to_occupant.role == 'moderator' + or from_occupant and from_occupant.role == "moderator" then + return; -- Allow to/from moderators + end + end + + local pmval = get_allow_pm(room); + + if pmval ~= "none" then + if pmval == "affiliated" and room:get_affiliation(from_occupant.bare_jid) then + return; -- Allow from affiliated users + elseif valid_roles[from_occupant.role] >= valid_roles[pmval] then + module:log("debug", "Allowing PM: %s(%d) >= %s(%d)", from_occupant.role, valid_roles[from_occupant.role], pmval, valid_roles[pmval]); + return; -- Allow from a permitted role + end + end + + local msg = ("Private messages are restricted %s"):format(who_restricted[pmval]); + module:log("debug", "Blocking PM from %s %s: %s", from_occupant.role, stanza.attr.from, msg); + + room:route_to_occupant( + from_occupant, + st.error_reply(stanza, "cancel", "policy-violation", msg, room.jid) + ); + return false; +end, 1); + +return { + get_allow_pm = get_allow_pm; + set_allow_pm = set_allow_pm; + get_allow_modpm = get_allow_modpm; + set_allow_modpm = set_allow_modpm; +}; diff --git a/plugins/muc/subject.lib.lua b/plugins/muc/subject.lib.lua index 3230817c..047ea2df 100644 --- a/plugins/muc/subject.lib.lua +++ b/plugins/muc/subject.lib.lua @@ -7,8 +7,8 @@ -- COPYING file in the source package for more information. -- -local st = require "util.stanza"; -local dt = require "util.datetime"; +local st = require "prosody.util.stanza"; +local dt = require "prosody.util.datetime"; local muc_util = module:require "muc/util"; local valid_roles = muc_util.valid_roles; |