2024-06-25 07:59:46 +00:00
-- mod_muc_peertubelivechat_terms
--
-- SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
-- SPDX-License-Identifier: AGPL-3.0-only
--
-- This file is AGPL-v3 licensed.
-- Please see the Peertube livechat plugin copyright information.
-- https://livingston.frama.io/peertube-plugin-livechat/credits/
--
2024-06-25 09:28:46 +00:00
-- Exposed functions:
-- get_muc_terms
-- set_muc_terms
2024-06-25 07:59:46 +00:00
local jid_escape = require " util.jid " . escape ;
local jid_resource = require " util.jid " . resource ;
local st = require " util.stanza " ;
local id = require " util.id " ;
2024-06-25 10:54:15 +00:00
local datetime = require " util.datetime " ;
2024-06-25 07:59:46 +00:00
local service_nickname = module : get_option_string ( " muc_terms_service_nickname " , " Service " ) ;
2024-06-25 09:28:46 +00:00
local global_terms = module : get_option_string ( " muc_terms_global " , " " ) ;
local function create_terms_message ( room , type , terms )
2024-06-25 10:54:15 +00:00
-- Note: we can't send the message from "room.jid": XMPP clients such as Gajim would ignore them.
-- So we use a service_nickname.
2024-06-25 09:28:46 +00:00
local from = room.jid .. ' / ' .. jid_escape ( service_nickname ) ;
module : log ( " debug " , " Creating %s terms message from %s (room %s) " , type , from , room ) ;
local msg = st.message ( {
type = " groupchat " ,
from = from ,
id = id.medium ( )
} , terms )
2024-06-25 10:54:15 +00:00
: tag ( ' x-livechat-terms ' , { type = type } ) : up ( ) -- adding a custom tag to specify that it is a "terms" message, so that frontend can display it with a special template.
2024-07-05 12:57:59 +00:00
: tag ( " delay " , { xmlns = " urn:xmpp:delay " , from = from , stamp = datetime.datetime ( ) } ) : up ( ) -- adding a delay to trick the moderation bot (see below)
: tag ( " no-copy " , { xmlns = " urn:xmpp:hints " } ) : up ( )
: tag ( " no-store " , { xmlns = " urn:xmpp:hints " } ) : up ( )
: tag ( " no-permanent-store " , { xmlns = " urn:xmpp:hints " } ) : up ( ) ;
2024-06-25 10:54:15 +00:00
-- concerning the delay tag:
-- We are sending message to rooms from non-existant occupants.
-- If the message contains something that should be moderated by the livechat moderation bot,
-- it could generate some error logs (the bot will not find the user in the occupant list).
-- At time of writing, the xmppjs-chat-bot ignore delayed message... so we use this hack to trick the bot.
2024-06-25 09:28:46 +00:00
return msg ;
end
-- MUC Getter/Setter
function get_muc_terms ( room )
return room._data . livechat_muc_terms or nil ;
end
function set_muc_terms ( room , terms )
2024-06-25 10:40:00 +00:00
if terms == " " then
terms = nil ;
end
2024-06-25 09:28:46 +00:00
if get_muc_terms ( room ) == terms then return false ; end
room._data . livechat_muc_terms = terms ;
if terms ~= nil then
-- we must send new terms to all occupants.
local msg = create_terms_message ( room , " muc " , terms ) ;
module : log ( " debug " , " Broadcasting terms message to room %s " , room ) ;
room : broadcast_message ( msg ) ;
end
return true ;
end
2024-06-25 07:59:46 +00:00
-- send the terms when joining:
2024-06-25 09:28:46 +00:00
local function send_terms ( event )
2024-06-25 07:59:46 +00:00
local origin = event.origin ;
local room = event.room ;
local occupant = event.occupant ;
if global_terms then
2024-06-25 09:28:46 +00:00
module : log ( " debug " , " Sending global terms to %s " , occupant.jid ) ;
local msg = create_terms_message ( room , " global " , global_terms ) ;
msg.attr . to = occupant.jid ;
origin.send ( msg ) ;
end
local muc_terms = get_muc_terms ( room ) ;
if muc_terms then
2024-06-25 07:59:46 +00:00
local from = room.jid .. ' / ' .. jid_escape ( service_nickname ) ;
2024-06-25 09:28:46 +00:00
module : log ( " debug " , " Sending muc terms to %s " , occupant.jid ) ;
local msg = create_terms_message ( room , " muc " , muc_terms ) ;
msg.attr . to = occupant.jid ;
origin.send ( msg ) ;
2024-06-25 07:59:46 +00:00
end
end
-- Note: we could do that on muc-occupant-joined or muc-occupant-session-new.
-- The first will not send it to multiple clients, the second will.
-- After some reflexion, i will try muc-occupant-session-new, and see if it works as expected.
module : hook ( " muc-occupant-session-new " , send_terms ) ;
-- reserve the service_nickname:
2024-06-25 09:28:46 +00:00
local function enforce_nick_policy ( event )
2024-06-25 07:59:46 +00:00
local origin , stanza = event.origin , event.stanza ;
local requested_nick = jid_resource ( stanza.attr . to ) ;
local room = event.room ;
if not room then return ; end
if requested_nick == service_nickname then
module : log ( " debug " , " Occupant tried to use the %s reserved nickname, blocking it. " , service_nickname ) ;
local reply = st.error_reply ( stanza , " cancel " , " conflict " , nil , room.jid ) : up ( ) ;
origin.send ( reply ) ;
return true ;
end
end
module : hook ( " muc-occupant-pre-join " , enforce_nick_policy ) ;
module : hook ( " muc-occupant-pre-change " , enforce_nick_policy ) ;
-- security check: we must remove all "x-livechat-terms" tag, to be sure nobody tries to spoof terms!
module : hook ( " muc-occupant-groupchat " , function ( event )
event.stanza : maptags ( function ( child )
if child.name == ' x-livechat-terms ' then
return nil ;
end
return child ;
end ) ;
end , 100 ) ;
2024-06-27 13:14:49 +00:00
-- don't save terms messages in history
module : hook ( " muc-message-is-historic " , function ( event )
local stanza = event.stanza ;
if ( stanza : get_child ( " x-livechat-terms " ) ) then
return false , " hint " ;
end
end , 1 ) ;