- Add AGENTS.md with repo-specific conventions, build steps, and quirks - Add PATCHES_AND_MODULES.md documenting every upstream deviation - Add tests/ with pytest/slixmpp integration suite for core, MUC, vnctalk extensions, and infrastructure verification - Include pytest.ini and .gitignore Part-of: <http://gitlab.vnc.biz/uxf/vnctalk-prosody/-/merge_requests/3>
14 KiB
VNCtalk Prosody Patches & Custom Modules Analysis
This document describes how the VNCtalk Prosody distribution deviates from upstream Prosody 0.11.6. The deviations are delivered as:
patches/— direct replacements for upstream core filesvnctalk/— additional custom modules
Note:
patches.listis stale and unused. The Dockerfile hard-copies each patch in aRUN cp …block.
1. Core Patches (patches/)
1.1 mod_mam.lua → modules/mod_mam/mod_mam.lua
Purpose: Message Archive Management (XEP-0313) for 1:1 chats.
Key deviations from upstream:
vnc-rest-messagehook support: Addedvnc_message_handler(event)hooked onvnc-rest-message(priority 0). This allows the REST injection module (mod_http_rest) to archive messages that are injected via HTTP.- Store-user logic for REST: When
vnc_restis true,store_useris derived fromorig_frominstead oforig_to, so injected stanzas are archived under the sender's archive. shall_storealways returns true: The functionshall_store(user, who)unconditionally returnstrue, bypassing any roster-based archive filtering.- Archives normal messages with body: The condition
orig_type == "chat" or (orig_type == "normal" and stanza:get_child("body"))is kept but the implementation now also processesvnc-rest-messageevents.
Behavioural contract:
- Any message injected via
/rest(seemod_http_rest) must be archived under the sender's MAM archive. - MAM queries must return
stanza-idelements and support RSM pagination.
1.2 mod_muc.lua → modules/muc/mod_muc.lua
Purpose: MUC component loader and room lifecycle management.
Key deviations from upstream:
- Custom unregister IQ hook: Added
iq-set/bare/xmpp:vnctalk:unregister:query→handle_unregister_iq. This exposes a VNCtalk-specific room-unregistration endpoint. - Debug helper: Added
dumpTable(t, depth)utility function. - Room defaults:
muc_room_default_publicdefaults tofalse(rooms are hidden by default).
1.3 mod_muc_mam.lua → modules/mod_muc_mam.lua
Purpose: MUC Message Archive Management.
Key deviations from upstream:
withfilter hardcoded tomessage<groupchat: The archive query and history loader both setwith = "message<groupchat", meaning only groupchat messages are stored/retrieved; presence stanzas are ignored unlessmuc_log_presencesis enabled.- Presence archiving option: If
muc_log_presencesis true, join/leave presences are archived with syntheticwithvalues (presence/presence<unavailable). - MUC history from archive: The
muc-get-historyhook loads history from the archive backend when the in-memory_historybuffer is insufficient, respectingmax_history_messages. - Stanza-id stripping before broadcast: A
muc-broadcast-messagehook (priority 1) strips anystanza-idtags that claim to be from the room JID before the stanza is broadcast. - Occupant affiliation injection: When
whois == "anyone", archived messages include an<x xmlns="http://jabber.org/protocol/muc#user">item with the sender's affiliation and role.
1.4 mod_muc_unique.lua → modules/mod_muc_unique.lua
Purpose: XEP-0307 Unique Room Names.
Key deviations from upstream:
- Bare-JID request returns error: Added
handle_iq_tobarethat replies withitem-not-foundfor IQ-get requests sent to a bare JID, rather than generating a unique name. Unique names are only served for host-targeted requests.
1.5 moduleapi.lua → core/moduleapi.lua
Purpose: Module API base.
Key deviations from upstream:
- Added
open_host_store: New methodapi:open_host_store(host, name, store_type)allows a module to open a data store on behalf of a different host. This is heavily used by MUC FCM modules to read user private data / vCards from the main virtual host while running inside the MUC component.
1.6 muc.lib.lua → modules/muc/muc.lib.lua
Purpose: MUC room implementation (the largest patch).
Key deviations from upstream:
- Offline-affiliate broadcast (
broadcastmethod): After broadcasting to all online occupants, the method iterates over_affiliationsand sends the stanza to any affiliated JIDs that are not currently in the room, provided their domain is not hosted locally. This enables federation/remote-user delivery. publicise_occupant_statusskip for unavailable: When an occupant's role becomesnil(they left), the code logs"skipping unavailable presence"and does not route an unavailable presence to the leaving user themselves. This changes the standard XEP-0045 self-presence delivery.- Debug helpers: Added
dumpTableandtable_clone.
1.7 hidden.lib.lua → modules/muc/hidden.lib.lua
Purpose: Room visibility (public/hidden).
Key deviations from upstream:
- Restricted public rooms: If
muc_room_allow_publicisfalse(default in VNCtalk config), the public-room config option is hidden from non-admins, and only admins may create public rooms.
1.8 register.lib.lua → modules/muc/register.lib.lua
Purpose: MUC room nickname registration.
Key deviations from upstream:
- VNCtalk unregister handler (
handle_unregister_iq): Firesvnc-muc-kickevent and unconditionally removes the user's affiliation from_affiliations, bypassing normal affiliation-change logic. This is used for VNCtalk-specific account deletion/room cleanup.
1.9 mod_carbons.lua → modules/mod_carbons.lua
Purpose: XEP-0280 Message Carbons.
Key deviations from upstream:
vnc-rest-messagehook: Addedmodule:hook("vnc-rest-message", c2s_message_handler, -0.5). Messages injected via the REST endpoint are carbon-copied to the user's other resources just like locally-sent messages.
1.10 mod_admin_telnet.lua → modules/mod_admin_telnet.lua
Purpose: Admin telnet console.
Key deviations from upstream:
- Listens on all interfaces: Changed
interfacefrom"127.0.0.1"to"*". The healthcheck script (healthcheck.sh) relies on connecting to127.0.0.1:5582, but the console is now bound to0.0.0.0.
1.11 portmanager.lua → core/portmanager.lua
Purpose: Network port management.
Key deviations from upstream:
- Respects
network_default_read_sizefor socket mode:local default_mode = config.get("*", "network_default_read_size") or 4096;instead of a hardcoded4096. The VNCtalk config sets this to8192to support larger stanzas (Jitsi/file transfers).
2. Custom Modules (vnctalk/)
2.1 Authentication
mod_auth_http_async
- HTTP-based authentication. Replaces Prosody's internal password database with an async HTTP call to
http_auth_url. - Sends a
Basicauth header withbase64(username@host:password). - If
util.asyncis unavailable, falls back to synchronoussocket.http/ssl.https. user_existsalways returnstrue;set_password/create_user/delete_userare no-ops.
2.2 Push Notifications (FCM)
mod_vnc_fcm
- FCM push for 1:1 messages. Hooks on
message/bare,pre-message/bare/full, andvnc-rest-message. - Reads FCM tokens from private storage (
documents:stanza:io:json→fcmelement) and from a map store (fcmtoken). - Supports iOS and Android tokens; iOS gets a notification payload with sound, Android gets data-only.
- Handles VNCtalk-specific extensions:
vncTalkConference,whiteboard,attachment,readsignals, Jitsi URL/room. - Removes invalid FCM tokens (
NotRegistered,InvalidRegistration, etc.) from user private data automatically. - Inactive-device tracking: Uses
csi-client-active/inactivehooks to avoid pushing to devices that are online but inactive.
mod_vnc_fcm_hin
- Variant of
mod_vnc_fcmwith HIN (German health network) specific modifications.
mod_vnc_muc_fcm / mod_vnc_muc_fcm_hin
- FCM push for MUC messages. Loaded on the MUC component.
- Opens stores against
storage_host(the main virtual host) usingmodule:open_host_store. - On each groupchat message, iterates over room affiliations and pushes to offline/non-occupant members.
2.3 MUC Extensions
mod_vnc_muc_automember
- Automatically grants
memberaffiliation to anyone who receives a MUC invite, if they were previously unaffiliated.
mod_vnc_muc_hook
- Sends a XMPP message notification (with
http://vnc.biz/xmpp/muc#hooknamespace) to online users who are affiliated with a room but not currently joined, when an "important" message (has non-empty body) is broadcast. - Optionally sends a mediated invite instead of a plain notification (
muc_notification_invite).
mod_vnc_muc_data
- Adds a
muc#roomconfig_vdataconfig field andmuc#roominfo_vdatadisco info field. - On config change, broadcasts a groupchat message with
<x xmlns='xmpp:vnctalk:update'/>containing JSON-encoded affiliations and room data.
mod_vnc_e2ehints
- Adds a
muc#roomconfig_e2eboolean field andmuc#roominfo_e2edisco info field for end-to-end encryption hints.
mod_vnc_remotemucstore
- Archives groupchat messages from remote MUCs (federation) into a local archive (
muc_remote) so users can query history even for rooms not hosted locally. - Stores MUC presence metadata (real JID mapping, subject, nick) in a map store.
- Prevents further processing of messages addressed to bare JIDs from remote MUCs (so they don't create offline message spam).
mod_vnc_remotemucinvite
- Archives mediated MUC invitations sent to remote users in a store (
muc_remote_inv).
mod_vnc_track_kicks
- Tracks kick/ban events in MUC rooms (lightweight event logger).
2.4 vCard & Avatar
mod_vnc_vcard_avatar
- On vCard update (IQ-set to self), extracts the PHOTO binval, decodes it, and uploads it via HTTP PUT to
avatar_upload_url. - Uses Basic auth if
avatar_upload_user/avatar_upload_passare configured. - Stores an
avatarupdatetimestamp in a map store.
mod_vnc_vcard_fallback
- Intercepts vCard IQ-get requests.
- If the user has no vCard on file, auto-generates one from the username (dot-separated usernames become
FIRSTNAME LASTNAME). - Adds
ORGNAMEifdefault_vcard_orgnameis configured.
2.5 Messaging Extensions
mod_vnc_timestamp
- Adds a custom
<stamp xmlns='xmpp:vnctalk:stamp'/>tag to incoming chat/groupchat messages that have a body. - Sends an IQ-result back to the sender containing the timestamp and original stanza ID.
mod_vnc_receipts
- Archives XEP-0184 delivery receipts (
<received xmlns='urn:xmpp:receipts'/>) in an archive store (receipts).
mod_vnc_lastactivity
- Extends XEP-0012 last activity with avatar hash caching.
- Caches SHA1 of the user's vCard PHOTO in memory (
avt_hash_table). - Stores/retrieves remote user activity and avatar updates in map stores.
mod_vnc_broadcast
- Implements a
vnc_broadcastcomponent. - Accepts messages with
<vncTalkBroadcast xmlns='xmpp:vnctalk'>and fans them out to:- Explicit
toJIDs - Roster groups (via
roster_manager.load_roster) - MUC room affiliations (if a
toJID is a MUC)
- Explicit
2.6 HTTP / REST
mod_http_rest
- Exposes
POST /reston the HTTP server. - Accepts
Content-Type: text/xmlbodies, parses them as XMPP stanzas, and injects them into the server viamodule:fire_event("vnc-rest-message", …). - Returns
201on success,415for wrong content type,422for unparseable body.
mod_http_upload_external
- Delegates HTTP file upload to an external PHP endpoint (
share.php). - Generates signed URLs using
http_upload_external_secret.
2.7 Utility Modules
| Module | Purpose |
|---|---|
mod_alias |
Allows users to have alias JIDs |
mod_roster_command |
Ad-hoc commands for roster management |
mod_s2s_keepalive |
Keepalive pings for S2S connections (Jitsi compatibility) |
mod_smacks / mod_smacks_offline |
Stream Management (XEP-0198) with offline queue support |
mod_carbons_copies |
Helper for carbons routing |
mod_log_slow_events |
Logs events exceeding log_slow_events_threshold |
mod_discoitems |
Manual override of disco items for a host |
mod_filter_chatstates |
Drops chat-state notifications under certain conditions |
mod_idlecompat |
Compatibility shim for idle detection |
mod_http_altconnect |
Alternative connection methods discovery |
mod_http_index |
Static HTTP index page |
mod_webpresence |
Publish presence as web images/icons |
mod_auto_accept_subscriptions |
Auto-accept presence subscriptions |
mod_vcard_muc |
vCard support for MUC rooms |
mod_vnc_delfile |
File deletion command via XMPP |
3. Configuration-Driven Behaviour
Several behaviours are not hard-coded in Lua but emerge from config/prosody.cfg.lua.template:
| Config Option | Effect |
|---|---|
authentication = "http_async" |
All client auth goes to hybridaAuthUrl |
default_archive_policy = "roster" |
MAM archives only roster contacts by default |
muc_log_by_default = true / muc_log_all_rooms = true |
All MUC messages archived |
c2s_require_encryption = true |
Plaintext C2S rejected |
keepalive_servers = { "${DEFAULT_JITSI_CONFERENCE}" } |
S2S keepalive pings sent to Jitsi |
component_secret = "…" |
Fixed MUC component secret (not randomly generated) |
4. Healthcheck & Runtime Quirks
healthcheck.shexits 2 (not 1) when the TLS cert in/etc/tls-update/tls.crtdiffers from the loaded one. Orchestrators must treat exit code 2 as a restart signal.startup-sidecar.shruns a Nodehttp-serveron port 8080 for static files; this is not the XMPP server.startup.shgenerates fallback certs from base64 defaults ifprosodySSLkey/certenv vars are missing.