Fix all integrations

This commit is contained in:
2026-03-08 22:08:55 +00:00
parent bca4d6898f
commit acedc01e83
58 changed files with 4120 additions and 960 deletions

View File

@@ -0,0 +1,121 @@
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);

View File

@@ -0,0 +1,138 @@
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_privileged_carbons 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 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 build_sent_carbon(inner, user_bare)
local function rebuild_stanza(node)
if type(node) ~= "table" or not node.name then
return node;
end
local attr = {};
for k, v in pairs(node.attr or {}) do
attr[k] = v;
end
local rebuilt = st.stanza(node.name, attr);
for _, child in ipairs(node) do
if type(child) == "table" and child.name then
rebuilt:add_direct_child(rebuild_stanza(child));
elseif type(child) == "string" then
rebuilt:add_direct_child(child);
end
end
return rebuilt;
end
local copy = rebuild_stanza(inner);
local function normalize_client_ns(node)
if not node then
return;
end
if node.attr then
if node.attr.xmlns == nil or node.attr.xmlns == "jabber:component:accept" then
node.attr.xmlns = "jabber:client";
end
end
if node.tags then
for _, child in ipairs(node.tags) do
normalize_client_ns(child);
end
end
end
normalize_client_ns(copy);
return st.message({ from = user_bare, type = inner.attr.type or "chat", xmlns = "jabber:client" })
:tag("sent", { xmlns = xmlns_carbons })
:tag("forwarded", { xmlns = xmlns_forward })
:add_child(copy):reset();
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", "Privileged carbon skipped for offline user %s", bare_jid);
return true;
end
local carbon = build_sent_carbon(inner, bare_jid);
local delivered = false;
for _, session in iter_sessions(user_sessions) do
if session.full_jid and session.send then
local copy = st.clone(carbon);
copy.attr.xmlns = "jabber:client";
copy.attr.to = session.full_jid;
session.rawsend(tostring(copy));
delivered = true;
end
end
module:log("info", "Privileged 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 inner then
module:log("debug", "Ignoring privileged message without forwarded payload from %s", origin.host or "?");
return nil;
end
local bare_from = jid_bare(inner.attr.from);
if not bare_from or bare_from == "" then
module:log("warn", "Rejected malformed privileged carbon from %s", origin.host or "?");
return true;
end
if bare_from:match("@(.+)$") ~= module.host then
module:log("debug", "Ignoring privileged carbon for remote host %s", bare_from);
return nil;
end
return deliver_carbon_to_user_sessions(bare_from, inner);
end
module:hook("pre-message/host", handle_privileged_carbon, 10);
module:hook("message/host", handle_privileged_carbon, 10);

View File

@@ -1,5 +1,7 @@
local env = os.getenv
local xmpp_secret = env("XMPP_SECRET") or ""
local xmpp_user_domain = env("XMPP_USER_DOMAIN") or "example.com"
local xmpp_upload_base_url = env("XMPP_UPLOAD_BASE_URL") or "https://share.example.com/file_share"
if xmpp_secret == "" then
error("XMPP_SECRET is required for Prosody component authentication")
@@ -19,6 +21,7 @@ modules_enabled = {
"saslauth";
"tls";
"blocklist";
"privileged_carbons";
"carbons";
"dialback";
"limits";
@@ -34,6 +37,7 @@ modules_enabled = {
"admin_adhoc";
"announce";
"http";
"http_file_share";
}
s2s_secure_auth = true
@@ -66,7 +70,10 @@ http_external_url = "https://share.example.com/"
VirtualHost "example.com"
authentication = "gia"
http_host = "share.example.com"
external_auth_command = "/code/utilities/prosody/auth_django.sh"
privileged_entity_jid = env("XMPP_JID") or "jews.example.com"
http_file_share_size_limit = 104857600
ssl = {
key = "/etc/prosody/certs/cert.pem";
certificate = "/etc/prosody/certs/cert.pem";