Skip to content

OF-3222: Improve XEP-0359 stanza-id handling for one-on-one routing and archiving#3234

Open
guusdk wants to merge 1 commit intoigniterealtime:mainfrom
guusdk:OF-3222_StanzaID-on-one-on-one-messages
Open

OF-3222: Improve XEP-0359 stanza-id handling for one-on-one routing and archiving#3234
guusdk wants to merge 1 commit intoigniterealtime:mainfrom
guusdk:OF-3222_StanzaID-on-one-on-one-messages

Conversation

@guusdk
Copy link
Copy Markdown
Member

@guusdk guusdk commented Mar 27, 2026

Add stanza-id generation for direct messages delivered to local bare and full JIDs using recipient bare JID ownership.

Add sender-owned stanza-id for local-to-remote messages only after routing completes so outbound wire stanzas are not modified while post-processing interceptors can archive IDs.

Exclude local component subdomains from sender-owned stanza-id injection so existing MUC stanza-id handling in MultiUserChatServiceImpl remains authoritative and is not duplicated.

…nd archiving

Add stanza-id generation for direct messages delivered to local bare and full JIDs using recipient bare JID ownership.

Add sender-owned stanza-id for local-to-remote messages only after routing completes so outbound wire stanzas are not modified while post-processing interceptors can archive IDs.

Exclude local component subdomains from sender-owned stanza-id injection so existing MUC stanza-id handling in MultiUserChatServiceImpl remains authoritative and is not duplicated.
Copilot AI review requested due to automatic review settings March 27, 2026 16:42
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Improves XEP-0359 stanza-id generation/injection for one-on-one messaging flows to better support routing and archiving behavior without altering outbound S2S wire stanzas.

Changes:

  • Add recipient-owned stanza-id generation when routing direct messages to local bare JIDs and full JIDs.
  • Add sender-owned stanza-id generation for locally-originated messages to remote domains after routing completes (to avoid modifying S2S wire traffic), while still allowing post-processing interceptors to archive stanza-ids.
  • Exclude subdomains of the local server domain from sender-owned stanza-id injection to avoid duplicating component-managed stanza-id behavior.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
xmppserver/src/main/java/org/jivesoftware/openfire/spi/RoutingTableImpl.java Adds recipient-owned stanza-id generation during local bare/full JID routing.
xmppserver/src/main/java/org/jivesoftware/openfire/MessageRouter.java Adds post-routing sender-owned stanza-id injection for local-to-remote messages (with subdomain exclusion).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +368 to +371
// Add stanza ID for one-on-one messages sent to full JIDs as per XEP-0359
if (packet instanceof Message message) {
StanzaIDUtil.ensureUniqueAndStableStanzaID(message, jid.asBareJID());
}
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The stanza-id is added for every Message routed to a local full JID. That includes non one-on-one traffic like MUC groupchat messages (which are typically routed to local users as full JIDs), causing an extra recipient-owned stanza-id with by=<user@domain> to be added in addition to any MUC-assigned stanza-id. If the intent is “direct messages” only (as per PR description), restrict this to appropriate message types (eg chat/normal) and/or explicitly exclude groupchat (and possibly error).

Copilot uses AI. Check for mistakes.
Comment on lines 632 to +636
private boolean routeToBareJID(JID recipientJID, Message packet) {
// Add stanza ID for one-on-one messages as per XEP-0359
// The assigning entity for one-on-one messages is the receiving user's bare JID
StanzaIDUtil.ensureUniqueAndStableStanzaID(packet, recipientJID.asBareJID());

Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ensureUniqueAndStableStanzaID is invoked before early-return cases that discard/don't route certain message types (eg error and groupchat). Consider moving stanza-id generation to after those checks so dropped stanzas aren’t mutated and to avoid unnecessary UUID generation/work.

Copilot uses AI. Check for mistakes.
Comment on lines +141 to +145
// exclude those too by checking that the recipient domain is not a subdomain of this server. OF-3222
if (packet.getFrom() != null
&& serverName.equals(packet.getFrom().getDomain())
&& !serverName.equals(recipientJID.getDomain())
&& !recipientJID.getDomain().endsWith("." + serverName)) {
Copy link

Copilot AI Mar 27, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The condition !recipientJID.getDomain().endsWith("." + serverName) treats any subdomain of the local domain as a local component. That can incorrectly skip sender-owned stanza-id injection for legitimate remote domains that happen to be subdomains (e.g. user@chat.example.com when serverName is example.com). Instead of a string suffix check, use an explicit local-component test (e.g. XMPPServer.getInstance().matchesComponent(recipientJID) and/or routingTable.hasComponentRoute(recipientJID)) to exclude only domains that are actually hosted components.

Suggested change
// exclude those too by checking that the recipient domain is not a subdomain of this server. OF-3222
if (packet.getFrom() != null
&& serverName.equals(packet.getFrom().getDomain())
&& !serverName.equals(recipientJID.getDomain())
&& !recipientJID.getDomain().endsWith("." + serverName)) {
// exclude those too by only excluding recipients that are actually hosted as local components. OF-3222
if (packet.getFrom() != null
&& serverName.equals(packet.getFrom().getDomain())
&& !serverName.equals(recipientJID.getDomain())
&& !XMPPServer.getInstance().matchesComponent(recipientJID)
&& !routingTable.hasComponentRoute(recipientJID)) {

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants