Mercurial > prosody-modules
view mod_restrict_xmpp/mod_restrict_xmpp.lua @ 5593:6d0574bfbf5d
mod_client_management: Include software version in table (when known)
Showing software versions could be useful for statistical reasons, e.g.
determining how quickly (or not) users upgrade, but most importantly for
revoking vulnerable clients versions in case of a security issue.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Thu, 13 Jul 2023 23:26:02 +0200 |
parents | 825c6fb76c48 |
children | 111e970213a0 |
line wrap: on
line source
local array = require "util.array"; local it = require "util.iterators"; local set = require "util.set"; local st = require "util.stanza"; local normal_user_role = "prosody:registered"; local limited_user_role = "prosody:guest"; local features = require "core.features"; -- COMPAT if not features.available:contains("split-user-roles") then normal_user_role = "prosody:user"; limited_user_role = "prosody:restricted"; end module:default_permission(normal_user_role, "xmpp:federate"); module:hook("route/remote", function (event) if not module:may("xmpp:federate", event) then if event.stanza.attr.type ~= "result" and event.stanza.attr.type ~= "error" then module:log("warn", "Access denied: xmpp:federate for %s -> %s", event.stanza.attr.from, event.stanza.attr.to); local reply = st.error_reply(event.stanza, "auth", "forbidden"); event.origin.send(reply); end return true; end end); local iq_namespaces = { ["jabber:iq:roster"] = "contacts"; ["jabber:iq:private"] = "storage"; ["vcard-temp"] = "profile"; ["urn:xmpp:mam:0"] = "history"; ["urn:xmpp:mam:1"] = "history"; ["urn:xmpp:mam:2"] = "history"; ["urn:xmpp:carbons:0"] = "carbons"; ["urn:xmpp:carbons:1"] = "carbons"; ["urn:xmpp:carbons:2"] = "carbons"; ["urn:xmpp:blocking"] = "blocklist"; ["http://jabber.org/protocol/pubsub"] = "pep"; ["http://jabber.org/protocol/disco#info"] = "disco"; }; local legacy_storage_nodes = { ["storage:bookmarks"] = "bookmarks"; ["storage:rosternotes"] = "contacts"; ["roster:delimiter"] = "contacts"; ["storage:metacontacts"] = "contacts"; }; local pep_nodes = { ["storage:bookmarks"] = "bookmarks"; ["urn:xmpp:bookmarks:1"] = "bookmarks"; ["urn:xmpp:avatar:data"] = "profile"; ["urn:xmpp:avatar:metadata"] = "profile"; ["http://jabber.org/protocol/nick"] = "profile"; ["eu.siacs.conversations.axolotl.devicelist"] = "omemo"; ["urn:xmpp:omemo:1:devices"] = "omemo"; ["urn:xmpp:omemo:1:bundles"] = "omemo"; ["urn:xmpp:omemo:2:devices"] = "omemo"; ["urn:xmpp:omemo:2:bundles"] = "omemo"; }; module:hook("pre-iq/bare", function (event) if not event.to_self then return; end local origin, stanza = event.origin, event.stanza; local typ = stanza.attr.type; if typ ~= "set" and typ ~= "get" then return; end local action = typ == "get" and "read" or "write"; local payload = stanza.tags[1]; local ns = payload and payload.attr.xmlns; local proto = iq_namespaces[ns]; if proto == "pep" then local pubsub = payload:get_child("pubsub", "http://jabber.org/protocol/pubsub"); local node = pubsub and #pubsub.tags == 1 and pubsub.tags[1].attr.node or nil; proto = pep_nodes[node] or "pep"; if proto == "pep" and node and node:match("^eu%.siacs%.conversations%.axolotl%.bundles%.%d+$") then proto = "omemo"; -- COMPAT w/ original OMEMO end elseif proto == "storage" then local data = payload.tags[1]; proto = data and legacy_storage_nodes[data.attr.xmlns] or "legacy-storage"; elseif proto == "carbons" then -- This allows access to live messages proto, action = "messages", "read"; elseif proto == "history" then action = "read"; end local permission_name = "xmpp:account:"..(proto and (proto..":") or "")..action; if not module:may(permission_name, event) then module:log("warn", "Access denied: %s ({%s}%s) for %s", permission_name, ns, payload.name, origin.full_jid or origin.id); origin.send(st.error_reply(stanza, "auth", "forbidden", "You do not have permission to make this request ("..permission_name..")")); return true; end end); --module:default_permission("prosody:restricted", "xmpp:account:read"); --module:default_permission("prosody:restricted", "xmpp:account:write"); module:default_permission(limited_user_role, "xmpp:account:messages:read"); module:default_permission(limited_user_role, "xmpp:account:messages:write"); for _, property_list in ipairs({ iq_namespaces, legacy_storage_nodes, pep_nodes }) do for account_property in set.new(array.collect(it.values(property_list))) do module:default_permission(limited_user_role, "xmpp:account:"..account_property..":read"); module:default_permission(limited_user_role, "xmpp:account:"..account_property..":write"); end end module:default_permission("prosody:restricted", "xmpp:account:presence:write"); module:hook("pre-presence/bare", function (event) if not event.to_self then return; end local stanza = event.stanza; if not module:may("xmpp:account:presence:write", event) then module:log("warn", "Access denied: xmpp:account:presence:write for %s", event.origin.full_jid or event.origin.id); event.origin.send(st.error_reply(stanza, "auth", "forbidden", "You do not have permission to send account presence")); return true; end local priority = stanza:get_child_text("priority"); if priority ~= "-1" then if not module:may("xmpp:account:messages:read", event) then module:log("warn", "Access denied: xmpp:account:messages:read for %s", event.origin.full_jid or event.origin.id); event.origin.send(st.error_reply(stanza, "auth", "forbidden", "You do not have permission to receive messages (use presence priority -1)")); return true; end end end);