Software /
code /
prosody-modules
File
mod_groups_muc_bookmarks/mod_groups_muc_bookmarks.lua @ 4651:8231774f5bfd
mod_cloud_notify_encrypted: Ensure body substring remains valid UTF-8
The `body:sub()` call risks splitting the string in the middle of a
multi-byte UTF-8 sequence. This should have been caught by util.stanza
validation, but that would have caused some havoc, at the very least causing
the notification to not be sent.
There have been no reports of this happening. Likely because this module
isn't widely deployed among users with languages that use many longer UTF-8
sequences.
The util.encodings.utf8.valid() function is O(n) where only the last
sequence really needs to be checked, but it's in C and expected to be fast.
author | Kim Alvefur <zash@zash.se> |
---|---|
date | Sun, 22 Aug 2021 13:22:59 +0200 |
parent | 4586:240fa534f586 |
child | 4861:5fadb991003d |
line wrap: on
line source
local jid_split = require "util.jid".split; local st = require "util.stanza"; local mod_groups = module:depends("groups_internal") local mod_pep = module:depends("pep") local PUBSUB_NODE_XEP0048 = "storage:bookmarks"; local XMLNS_XEP0048 = "storage:bookmarks"; local XMLNS_XEP0060 = "http://jabber.org/protocol/pubsub"; local default_options = { ["persist_items"] = true; ["access_model"] = "whitelist"; }; local function get_current_bookmarks(jid, service) local ok, id, item = service:get_last_item(PUBSUB_NODE_XEP0048, jid) if not ok or id == nil then if id == "item-not-found" or id == nil then -- return empty return st.stanza("storage", { xmlns = XMLNS_XEP0048 }); end return nil, result end -- first item is the actual storage element local hit = item:get_child("storage", XMLNS_XEP0048); if not hit then return nil, "internal-server-error" end return hit end local function update_bookmarks(jid, service, storage) local item = st.stanza("item", { xmlns = XMLNS_XEP0060, id = "current" }):add_child(storage) module:log("debug", "updating bookmarks with %q", item) local ok, err = service:publish( PUBSUB_NODE_XEP0048, jid, "current", item, default_options ) if not ok then module:log("error", "failed to update bookmarks: %s", err) end end local function find_matching_bookmark(storage, room) for node in storage:childtags("conference") do if node.attr.jid == room then return node end end return nil end local function inject_bookmark(jid, room, autojoin, name) local pep_service = mod_pep.get_pep_service(jid_split(jid)) autojoin = autojoin or false and true local current = get_current_bookmarks(jid, pep_service) local existing = find_matching_bookmark(current, room) if existing then if autojoin ~= nil then existing.attr.autojoin = autojoin and "true" or "false" end if name ~= nil then -- do not change already configured names if not existing.attr.name then existing.attr.name = name end end done = true module:log("debug", "found existing matching bookmark, updated") else module:log("debug", "no existing bookmark found, adding new") current:tag("conference", { name = name, autojoin = autojoin and "true" or "false", jid = room, xmlns = XMLNS_XEP0048, }) end update_bookmarks(jid, pep_service, current) end local function remove_bookmark(jid, room, autojoin, name) local pep_service = mod_pep.get_pep_service(jid_split(jid)) autojoin = autojoin or false and true local current = get_current_bookmarks(jid, pep_service) if not current then return end current:maptags(function (node) if node.attr.xmlns and node.attr.xmlns ~= XMLNS_XEP0048 then return node end if node.name ~= "conference" then return node end if node.attr.jid == room then -- remove matching bookmark return nil end return node end) update_bookmarks(jid, pep_service, current) end local function handle_user_added(event) if not event.group_info.muc_jid then module:log("debug", "ignoring user added event on group %s because it has no MUC", event.id) return end local jid = event.user .. "@" .. event.host inject_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name) end local function handle_user_removed(event) if not event.group_info.muc_jid then module:log("debug", "ignoring user removed event on group %s because it has no MUC", event.id) return end -- Removing the bookmark is fine as the user just lost any privilege to -- be in the MUC (as group MUCs are members-only). local jid = event.user .. "@" .. event.host remove_bookmark(jid, event.group_info.muc_jid, true, event.group_info.name) end module:hook("group-user-added", handle_user_added) module:hook("group-user-removed", handle_user_removed)