comparison mod_push2/mod_push2.lua @ 6181:811bd0872682

mod_push2: Do not push MUC reflections Messages from myself to a MUC come back and should not get pushed. MUC subjects don't have a body so seperately checking for those is not needed.
author Stephen Paul Weber <singpolyma@singpolyma.net>
date Mon, 24 Mar 2025 08:53:36 -0500
parents 051974b4c900
children fe9f2c618e8a
comparison
equal deleted inserted replaced
6180:051974b4c900 6181:811bd0872682
6 local watchdog = require "util.watchdog"; 6 local watchdog = require "util.watchdog";
7 local uuid = require "util.uuid"; 7 local uuid = require "util.uuid";
8 local base64 = require "util.encodings".base64; 8 local base64 = require "util.encodings".base64;
9 local crypto = require "util.crypto"; 9 local crypto = require "util.crypto";
10 local jwt = require "util.jwt"; 10 local jwt = require "util.jwt";
11
12 pcall(function() module:depends("track_muc_joins") end)
11 13
12 local xmlns_push = "urn:xmpp:push2:0"; 14 local xmlns_push = "urn:xmpp:push2:0";
13 15
14 -- configuration 16 -- configuration
15 local contact_uri = module:get_option_string("contact_uri", "xmpp:" .. module.host) 17 local contact_uri = module:get_option_string("contact_uri", "xmpp:" .. module.host)
154 156
155 return body ~= nil and body ~= "" 157 return body ~= nil and body ~= ""
156 end 158 end
157 159
158 -- is this push a high priority one 160 -- is this push a high priority one
159 local function is_important(stanza) 161 local function is_important(stanza, session)
160 local is_voip_stanza, urgent_reason = is_voip(stanza) 162 local is_voip_stanza, urgent_reason = is_voip(stanza)
161 if is_voip_stanza then return true; end 163 if is_voip_stanza then return true; end
162 164
163 local st_name = stanza and stanza.name or nil 165 local st_name = stanza and stanza.name or nil
164 if not st_name then return false; end -- nonzas are never important here 166 if not st_name then return false; end -- nonzas are never important here
175 if st_type == "headline" then return false; end 177 if st_type == "headline" then return false; end
176 178
177 -- carbon copied outgoing messages are not important 179 -- carbon copied outgoing messages are not important
178 if carbon and stanza_direction == "out" then return false; end 180 if carbon and stanza_direction == "out" then return false; end
179 181
180 -- groupchat subjects are not important here 182 -- groupchat reflections are not important here
181 if st_type == "groupchat" and stanza:get_child_text("subject") then 183 if st_type == "groupchat" and session and session.rooms_joined then
182 return false 184 local muc = jid.bare(stanza.attr.from)
185 local from_nick = jid.resource(stanza.attr.from)
186 if from_nick == session.rooms_joined[muc] then
187 return false
188 end
183 end 189 end
184 190
185 -- empty bodies are not important 191 -- empty bodies are not important
186 return has_body(stanza) 192 return has_body(stanza)
187 end 193 end
293 end 299 end
294 payload.sub = contact_uri 300 payload.sub = contact_uri
295 push_notification_payload:text_tag("jwt", signer(payload), { key = base64.encode(public_key) }) 301 push_notification_payload:text_tag("jwt", signer(payload), { key = base64.encode(public_key) })
296 end 302 end
297 303
298 local function handle_notify_request(stanza, node, user_push_services, log_push_decline) 304 local function handle_notify_request(stanza, node, user_push_services, session, log_push_decline)
299 local pushes = 0; 305 local pushes = 0;
300 if not #user_push_services then return pushes end 306 if not #user_push_services then return pushes end
301 307
302 local notify_push_services = {}; 308 local notify_push_services = {};
303 if is_important(stanza) then 309 if is_important(stanza, session) then
304 notify_push_services = user_push_services 310 notify_push_services = user_push_services
305 else 311 else
306 for identifier, push_info in pairs(user_push_services) do 312 for identifier, push_info in pairs(user_push_services) do
307 for _, match in ipairs(push_info.matches) do 313 for _, match in ipairs(push_info.matches) do
308 if match.match == "urn:xmpp:push2:match:important" then 314 if match.match == "urn:xmpp:push2:match:important" then
328 end 334 end
329 335
330 if send_push then 336 if send_push then
331 local push_notification_payload = st.stanza("notification", { xmlns = xmlns_push }) 337 local push_notification_payload = st.stanza("notification", { xmlns = xmlns_push })
332 push_notification_payload:text_tag("client", push_info.client) 338 push_notification_payload:text_tag("client", push_info.client)
333 push_notification_payload:text_tag("priority", is_voip(stanza) and "high" or (is_important(stanza) and "normal" or "low")) 339 push_notification_payload:text_tag("priority", is_voip(stanza) and "high" or (is_important(stanza, session) and "normal" or "low"))
334 if is_voip(stanza) then 340 if is_voip(stanza) then
335 push_notification_payload:tag("voip"):up() 341 push_notification_payload:tag("voip"):up()
336 end 342 end
337 343
338 local sends_added = {}; 344 local sends_added = {};
339 for _, match in ipairs(push_info.matches) do 345 for _, match in ipairs(push_info.matches) do
340 local does_match = false; 346 local does_match = false;
341 if match.match == "urn:xmpp:push2:match:all" then 347 if match.match == "urn:xmpp:push2:match:all" then
342 does_match = true 348 does_match = true
343 elseif match.match == "urn:xmpp:push2:match:important" then 349 elseif match.match == "urn:xmpp:push2:match:important" then
344 does_match = is_important(stanza) 350 does_match = is_important(stanza, session)
345 elseif match.match == "urn:xmpp:push2:match:archived" then 351 elseif match.match == "urn:xmpp:push2:match:archived" then
346 does_match = stanza:get_child("stana-id", "urn:xmpp:sid:0") 352 does_match = stanza:get_child("stana-id", "urn:xmpp:sid:0")
347 elseif match.match == "urn:xmpp:push2:match:archived-with-body" then 353 elseif match.match == "urn:xmpp:push2:match:archived-with-body" then
348 does_match = stanza:get_child("stana-id", "urn:xmpp:sid:0") and has_body(stanza) 354 does_match = stanza:get_child("stana-id", "urn:xmpp:sid:0") and has_body(stanza)
349 end 355 end
383 389
384 -- publish on offline message 390 -- publish on offline message
385 module:hook("message/offline/handle", function(event) 391 module:hook("message/offline/handle", function(event)
386 local node, user_push_services = get_push_settings(event.stanza, event.origin); 392 local node, user_push_services = get_push_settings(event.stanza, event.origin);
387 module:log("debug", "Invoking handle_notify_request() for offline stanza"); 393 module:log("debug", "Invoking handle_notify_request() for offline stanza");
388 handle_notify_request(event.stanza, node, user_push_services, true); 394 handle_notify_request(event.stanza, node, user_push_services, event.origin, true);
389 end, 1); 395 end, 1);
390 396
391 -- publish on bare groupchat 397 -- publish on bare groupchat
392 -- this picks up MUC messages when there are no devices connected 398 -- this picks up MUC messages when there are no devices connected
393 module:hook("message/bare/groupchat", function(event) 399 module:hook("message/bare/groupchat", function(event)
401 notify_push_services[identifier] = push_info; 407 notify_push_services[identifier] = push_info;
402 end 408 end
403 end 409 end
404 end 410 end
405 411
406 handle_notify_request(event.stanza, node, notify_push_services, true); 412 handle_notify_request(event.stanza, node, notify_push_services, event.origin, true);
407 end, 1); 413 end, 1);
408 414
409 local function process_stanza_queue(queue, session, queue_type) 415 local function process_stanza_queue(queue, session, queue_type)
410 if not session.push_registration_id then return; end 416 if not session.push_registration_id then return; end
411 local notified = { unimportant = false; important = false } 417 local notified = { unimportant = false; important = false }
414 -- fast ignore of already pushed stanzas 420 -- fast ignore of already pushed stanzas
415 if stanza and not (stanza._push_notify2 and stanza._push_notify2[session.push_registration_id]) then 421 if stanza and not (stanza._push_notify2 and stanza._push_notify2[session.push_registration_id]) then
416 local node, all_push_services = get_push_settings(stanza, session) 422 local node, all_push_services = get_push_settings(stanza, session)
417 local user_push_services = {[session.push_registration_id] = all_push_services[session.push_registration_id]} 423 local user_push_services = {[session.push_registration_id] = all_push_services[session.push_registration_id]}
418 local stanza_type = "unimportant"; 424 local stanza_type = "unimportant";
419 if is_important(stanza) then stanza_type = "important"; end 425 if is_important(stanza, session) then stanza_type = "important"; end
420 if not notified[stanza_type] then -- only notify if we didn't try to push for this stanza type already 426 if not notified[stanza_type] then -- only notify if we didn't try to push for this stanza type already
421 if handle_notify_request(stanza, node, user_push_services, false) ~= 0 then 427 if handle_notify_request(stanza, node, user_push_services, session, false) ~= 0 then
422 if session.hibernating and not session.first_hibernated_push then 428 if session.hibernating and not session.first_hibernated_push then
423 -- if the message was important 429 -- if the message was important
424 -- then record the time of first push in the session for the smack module which will extend its hibernation 430 -- then record the time of first push in the session for the smack module which will extend its hibernation
425 -- timeout based on the value of session.first_hibernated_push 431 -- timeout based on the value of session.first_hibernated_push
426 if is_important(stanza) then 432 if is_important(stanza, session) then
427 session.first_hibernated_push = os_time(); 433 session.first_hibernated_push = os_time();
428 -- check for prosody 0.12 mod_smacks 434 -- check for prosody 0.12 mod_smacks
429 if session.hibernating_watchdog and session.original_smacks_callback and session.original_smacks_timeout then 435 if session.hibernating_watchdog and session.original_smacks_callback and session.original_smacks_timeout then
430 -- restore old smacks watchdog (--> the start of our original timeout will be delayed until first push) 436 -- restore old smacks watchdog (--> the start of our original timeout will be delayed until first push)
431 session.hibernating_watchdog:cancel(); 437 session.hibernating_watchdog:cancel();
566 notify_push_services[identifier] = push_info 572 notify_push_services[identifier] = push_info
567 end 573 end
568 end 574 end
569 end 575 end
570 576
571 handle_notify_request(stanza, to_user, notify_push_services, true); 577 handle_notify_request(stanza, to_user, notify_push_services, event.origin, true);
572 end 578 end
573 end 579 end
574 580
575 module:hook("smacks-hibernation-start", hibernate_session); 581 module:hook("smacks-hibernation-start", hibernate_session);
576 module:hook("smacks-hibernation-end", restore_session); 582 module:hook("smacks-hibernation-end", restore_session);