Mercurial > prosody-modules
view mod_remote_roster/mod_remote_roster.lua @ 5298:12f7d8b901e0
mod_audit: Support for adding location (GeoIP) to audit events
This can be more privacy-friendly than logging full IP addresses, and also
more informative to a user - IP addresses don't mean much to the average
person, however if they see activity from outside their expected country, they
can immediately identify suspicious activity.
As with IPs, this field is configurable for deployments that would like to
disable it. Location is also not logged when the geoip library is not
available.
author | Matthew Wild <mwild1@gmail.com> |
---|---|
date | Sat, 01 Apr 2023 13:11:53 +0100 |
parents | 295ae44b8a01 |
children | ad6e9b0fd15b |
line wrap: on
line source
-- -- mod_remote_roster -- -- This is an experimental implementation of http://jkaluza.fedorapeople.org/remote-roster.html -- local st = require "util.stanza"; local jid_split = require "util.jid".split; local jid_prep = require "util.jid".prep; local t_concat = table.concat; local tonumber = tonumber; local pairs, ipairs = pairs, ipairs; local hosts = hosts; local load_roster = require "core.rostermanager".load_roster; local save_roster = require "core.rostermanager".save_roster; local rm_remove_from_roster = require "core.rostermanager".remove_from_roster; local rm_add_to_roster = require "core.rostermanager".add_to_roster; local rm_roster_push = require "core.rostermanager".roster_push; local user_exists = require "core.usermanager".user_exists; local add_task = require "util.timer".add_task; module:hook("iq-get/bare/jabber:iq:roster:query", function(event) local origin, stanza = event.origin, event.stanza; if origin.type == "component" and stanza.attr.from == origin.host then local node, host = jid_split(stanza.attr.to); local roster = load_roster(node, host); local reply = st.reply(stanza):query("jabber:iq:roster"); for jid, item in pairs(roster) do if jid ~= "pending" and jid then local node, host = jid_split(jid); if host == origin.host then -- only include contacts which are on this component reply:tag("item", { jid = jid, subscription = item.subscription, ask = item.ask, name = item.name, }); for group in pairs(item.groups) do reply:tag("group"):text(group):up(); end reply:up(); -- move out from item end end end origin.send(reply); --origin.interested = true; -- resource is interested in roster updates return true; end end); module:hook("iq-set/bare/jabber:iq:roster:query", function(event) local session, stanza = event.origin, event.stanza; if not(session.type == "component" and stanza.attr.from == session.host) then return; end local from_node, from_host = jid_split(stanza.attr.to); if not(user_exists(from_node, from_host)) then return; end local roster = load_roster(from_node, from_host); if not(roster) then return; end local query = stanza.tags[1]; if #query.tags == 1 and query.tags[1].name == "item" and query.tags[1].attr.xmlns == "jabber:iq:roster" and query.tags[1].attr.jid -- Protection against overwriting roster.pending, until we move it and query.tags[1].attr.jid ~= "pending" then local item = query.tags[1]; local jid = jid_prep(item.attr.jid); local node, host, resource = jid_split(jid); if not resource and host == session.host then if jid ~= stanza.attr.to then -- not self-jid if item.attr.subscription == "remove" then local r_item = roster[jid]; if r_item then local to_bare = node and (node.."@"..host) or host; -- bare JID --if r_item.subscription == "both" or r_item.subscription == "from" or (roster.pending and roster.pending[jid]) then -- module:send(st.presence({type="unsubscribed", from=stanza.attr.to, to=to_bare})); --end --if r_item.subscription == "both" or r_item.subscription == "to" or r_item.ask then -- module:send(st.presence({type="unsubscribe", from=stanza.attr.to, to=to_bare})); --end roster[jid] = nil; if save_roster(from_node, from_host, roster) then session.send(st.reply(stanza)); rm_roster_push(from_node, from_host, jid); else roster[jid] = item; session.send(st.error_reply(stanza, "wait", "internal-server-error", "Unable to save roster")); end else session.send(st.error_reply(stanza, "modify", "item-not-found")); end else local subscription = item.attr.subscription; if subscription ~= "both" and subscription ~= "to" and subscription ~= "from" and subscription ~= "none" then -- TODO error on invalid subscription = roster[jid] and roster[jid].subscription or "none"; end local r_item = {name = item.attr.name, groups = {}}; if r_item.name == "" then r_item.name = nil; end r_item.subscription = subscription; if subscription ~= "both" and subscription ~= "to" then r_item.ask = roster[jid] and roster[jid].ask; end for _, child in ipairs(item) do if child.name == "group" then local text = t_concat(child); if text and text ~= "" then r_item.groups[text] = true; end end end local olditem = roster[jid]; roster[jid] = r_item; if save_roster(from_node, from_host, roster) then -- Ok, send success session.send(st.reply(stanza)); -- and push change to all resources rm_roster_push(from_node, from_host, jid); else -- Adding to roster failed roster[jid] = olditem; session.send(st.error_reply(stanza, "wait", "internal-server-error", "Unable to save roster")); end end else -- Trying to add self to roster session.send(st.error_reply(stanza, "cancel", "not-allowed")); end else -- Invalid JID added to roster session.send(st.error_reply(stanza, "modify", "bad-request")); -- FIXME what's the correct error? end else -- Roster set didn't include a single item, or its name wasn't 'item' session.send(st.error_reply(stanza, "modify", "bad-request")); end return true; end); function component_roster_push(node, host, jid) local roster = load_roster(node, host); if roster then local item = roster[jid]; local contact_node, contact_host = jid_split(jid); local stanza = st.iq({ type="set", from=node.."@"..host, to=contact_host }):query("jabber:iq:roster"); if item then stanza:tag("item", { jid = jid, subscription = item.subscription, name = item.name, ask = item.ask }); for group in pairs(item.groups) do stanza:tag("group"):text(group):up(); end else stanza:tag("item", {jid = jid, subscription = "remove"}); end stanza:up(); -- move out from item stanza:up(); -- move out from stanza module:send(stanza); end end module:hook("iq-set/bare/jabber:iq:roster:query", function(event) local origin, stanza = event.origin, event.stanza; local query = stanza.tags[1]; local item = query.tags[1]; local contact_jid = item and item.name == "item" and item.attr.jid ~= "pending" and item.attr.jid; if contact_jid then local contact_node, contact_host = jid_split(contact_jid); if hosts[contact_host] and hosts[contact_host].type == "component" then local node, host = jid_split(stanza.attr.to or origin.full_jid); add_task(0, function() component_roster_push(node, host, contact_jid); end); end end end, 100);