122 lines
3.9 KiB
Lua
122 lines
3.9 KiB
Lua
local st = require "prosody.util.stanza";
|
|
local jid_bare = require "prosody.util.jid".bare;
|
|
|
|
local xmlns_privilege = "urn:xmpp:privilege:2";
|
|
local xmlns_forward = "urn:xmpp:forward:0";
|
|
local xmlns_carbons = "urn:xmpp:carbons:2";
|
|
local bare_sessions = prosody.bare_sessions;
|
|
|
|
local allowed_component_jid = module:get_option_string("privileged_entity_jid");
|
|
|
|
module:log("info", "mod_privilege loaded for host=%s privileged_entity_jid=%s", module.host or "?", allowed_component_jid or "");
|
|
|
|
local function iter_sessions(user_sessions)
|
|
if not user_sessions or not user_sessions.sessions then
|
|
return function() return nil end;
|
|
end
|
|
return pairs(user_sessions.sessions);
|
|
end
|
|
|
|
local function send_privilege_advertisement(session)
|
|
if not allowed_component_jid or allowed_component_jid == "" then
|
|
module:log("debug", "Privilege advertisement skipped: no privileged_entity_jid configured");
|
|
return;
|
|
end
|
|
if session.host ~= allowed_component_jid then
|
|
module:log("debug", "Privilege advertisement skipped: session host %s != %s", session.host or "?", allowed_component_jid);
|
|
return;
|
|
end
|
|
local msg = st.message({
|
|
from = module.host;
|
|
to = session.host;
|
|
type = "normal";
|
|
});
|
|
msg:tag("privilege", { xmlns = xmlns_privilege })
|
|
:tag("perm", { access = "message", type = "outgoing" }):up()
|
|
:up();
|
|
session.send(msg);
|
|
module:log("info", "Advertised outgoing message privilege to %s", session.host);
|
|
end
|
|
|
|
local function unwrap_forwarded_message(stanza)
|
|
local privilege = stanza:get_child("privilege", xmlns_privilege);
|
|
if not privilege then
|
|
return nil;
|
|
end
|
|
local forwarded = privilege:get_child("forwarded", xmlns_forward);
|
|
if not forwarded then
|
|
return nil;
|
|
end
|
|
for _, tag in ipairs(forwarded.tags or {}) do
|
|
if tag.name == "message" then
|
|
return tag;
|
|
end
|
|
end
|
|
return nil;
|
|
end
|
|
|
|
local function is_carbon_delivery(inner)
|
|
if not inner then
|
|
return false;
|
|
end
|
|
return inner:get_child("sent", xmlns_carbons) ~= nil
|
|
or inner:get_child("received", xmlns_carbons) ~= nil;
|
|
end
|
|
|
|
local function deliver_carbon_to_user_sessions(bare_jid, inner)
|
|
local user_sessions = bare_sessions[bare_jid];
|
|
if not user_sessions then
|
|
module:log("debug", "Privilege carbon skipped for offline user %s", bare_jid);
|
|
return true;
|
|
end
|
|
local delivered = false;
|
|
for _, session in iter_sessions(user_sessions) do
|
|
if session.full_jid and session.send then
|
|
local copy = st.clone(inner);
|
|
copy.attr.to = session.full_jid;
|
|
session.send(copy);
|
|
delivered = true;
|
|
end
|
|
end
|
|
module:log("debug", "Privilege carbon delivered user=%s delivered=%s", bare_jid, tostring(delivered));
|
|
return true;
|
|
end
|
|
|
|
local function handle_privileged_carbon(event)
|
|
local origin, stanza = event.origin, event.stanza;
|
|
if not origin or origin.type ~= "component" then
|
|
return nil;
|
|
end
|
|
if allowed_component_jid and allowed_component_jid ~= "" and origin.host ~= allowed_component_jid then
|
|
module:log("debug", "Ignoring privileged message from unexpected component %s", origin.host or "?");
|
|
return nil;
|
|
end
|
|
|
|
local inner = unwrap_forwarded_message(stanza);
|
|
if not is_carbon_delivery(inner) then
|
|
module:log("debug", "Ignoring privileged message without carbon payload from %s", origin.host or "?");
|
|
return nil;
|
|
end
|
|
|
|
local bare_to = jid_bare(inner.attr.to);
|
|
local bare_from = jid_bare(inner.attr.from);
|
|
if not bare_to or bare_to == "" or bare_to ~= bare_from then
|
|
module:log("warn", "Rejected malformed privileged carbon from %s", origin.host or "?");
|
|
return true;
|
|
end
|
|
if bare_to:match("@(.+)$") ~= module.host then
|
|
module:log("debug", "Ignoring privileged carbon for remote host %s", bare_to);
|
|
return nil;
|
|
end
|
|
|
|
return deliver_carbon_to_user_sessions(bare_to, inner);
|
|
end
|
|
|
|
module:hook_global("component-authenticated", function(event)
|
|
module:log("info", "component-authenticated for %s", event.session and event.session.host or "?");
|
|
send_privilege_advertisement(event.session);
|
|
end);
|
|
|
|
module:hook("pre-message/host", handle_privileged_carbon, 10);
|
|
module:hook("message/host", handle_privileged_carbon, 10);
|