muc, bookmarks: a destroyed room is recreated by autojoin at the next sign-in #26

Open
opened 2026-11-08 00:12:43 +00:00 by asxpi · 1 comment
Member

Summary

When a room is destroyed, its XEP-0402 bookmark keeps autojoin='true', and
the next sign-in creates the room again. muc destroy_room and the
<destroy/> presence (muc <Destroyed>) never touch bookmarks. At sign-in,
autojoin asks the room's disco#info, gets item-not-found, and sends the
join presence anyway. The server treats that as a create: status 201,
110, affiliation owner. So the owner's own client brings back a room that
was destroyed on purpose, on every sign-in. The new room is empty, has the
server's default configuration, and has the same address, so anyone who
knew the address can join it.

Spec

XEP-0045 §10.9 (destroying a room; <destroy/> with an optional alternate
venue) and §10.1.1 (a join to a room that does not exist creates it).
XEP-0402 (autojoin).

Steps to reproduce

  1. As the owner: muc join a new room, create_instant, then bookmarks item -autojoin 1.

  2. muc destroy_room. The server confirms:

    <presence from='room@conference.example/me' type='unavailable'><x xmlns='http://jabber.org/protocol/muc#user'><destroy/><item affiliation='none' role='none'/></x></presence>
    
  3. Sign in again on the same store.

Expected

The bookmark is gone after step 2. At step 3, no join is sent to a room
whose disco#info says it does not exist.

Actual

The bookmark fetch still has <conference autojoin='true'>. Then:

<presence to='room@conference.example/me'><x xmlns='http://jabber.org/protocol/muc'>…</x></presence>
<iq from='room@conference.example' type='error'>…<error type='cancel'><text>Conference room does not exist</text><item-not-found/></error></iq>
<presence from='room@conference.example/me'>…<item affiliation='owner' role='moderator'/><status code='201'/><status code='110'/></x></presence>

Root cause

  • tacky/xmpp/modules/muc.tcl destroy_room (:2353 at 8919dc12) only
    sends the iq. The <Destroyed> paths (:3123, and :4006 for MUC/Sub)
    only drop the room's state.
  • bookmarks AutojoinAll, AutojoinOne and Join call muc join. That
    sends the disco#info and the join presence together, so the disco#info
    answer cannot stop the join. HANDBOOK's XEP-0410 row already treats a room
    whose disco#info says it is gone as out, but autojoin does not apply that
    rule.

Affected versions

v1.2.0 (1dae0a6c) and v1.2.1 (8919dc12). Found in anotherim-js 009c9884
with libtacky develop 56d29734.

Interop runs

Host side

What a destroyed room's row shows is the host's decision, filed separately for anotherim-js: another-im/anotherim-js#95. It does not stop the room being recreated; only libtacky can, since libtacky runs autojoin.

## Summary When a room is destroyed, its XEP-0402 bookmark keeps `autojoin='true'`, and the next sign-in creates the room again. `muc destroy_room` and the `<destroy/>` presence (`muc <Destroyed>`) never touch bookmarks. At sign-in, autojoin asks the room's disco#info, gets `item-not-found`, and sends the join presence anyway. The server treats that as a create: status `201`, `110`, affiliation `owner`. So the owner's own client brings back a room that was destroyed on purpose, on every sign-in. The new room is empty, has the server's default configuration, and has the same address, so anyone who knew the address can join it. ## Spec XEP-0045 §10.9 (destroying a room; `<destroy/>` with an optional alternate venue) and §10.1.1 (a join to a room that does not exist creates it). XEP-0402 (autojoin). ## Steps to reproduce 1. As the owner: `muc join` a new room, `create_instant`, then `bookmarks item -autojoin 1`. 2. `muc destroy_room`. The server confirms: ```xml <presence from='room@conference.example/me' type='unavailable'><x xmlns='http://jabber.org/protocol/muc#user'><destroy/><item affiliation='none' role='none'/></x></presence> ``` 3. Sign in again on the same store. ## Expected The bookmark is gone after step 2. At step 3, no join is sent to a room whose disco#info says it does not exist. ## Actual The bookmark fetch still has `<conference autojoin='true'>`. Then: ```xml <presence to='room@conference.example/me'><x xmlns='http://jabber.org/protocol/muc'>…</x></presence> <iq from='room@conference.example' type='error'>…<error type='cancel'><text>Conference room does not exist</text><item-not-found/></error></iq> <presence from='room@conference.example/me'>…<item affiliation='owner' role='moderator'/><status code='201'/><status code='110'/></x></presence> ``` ## Root cause - `tacky/xmpp/modules/muc.tcl` `destroy_room` (`:2353` at 8919dc12) only sends the iq. The `<Destroyed>` paths (`:3123`, and `:4006` for MUC/Sub) only drop the room's state. - `bookmarks AutojoinAll`, `AutojoinOne` and `Join` call `muc join`. That sends the disco#info and the join presence together, so the disco#info answer cannot stop the join. HANDBOOK's XEP-0410 row already treats a room whose disco#info says it is gone as out, but autojoin does not apply that rule. ## Affected versions v1.2.0 (1dae0a6c) and v1.2.1 (8919dc12). Found in anotherim-js 009c9884 with libtacky `develop` 56d29734. ## Interop runs - v1.2.1, fail (R1 the bookmark is kept; R2 and R3 status 201 at sign-in): https://dev.another.im/another-im/interop/src/branch/ai-runs-2026-11-07/runs/20261107-234000-XEP-0402-slixmpp-anotherim-server - Found by hand: interop issue 1, comment "New: C34". ## Host side What a destroyed room's row shows is the host's decision, filed separately for anotherim-js: https://dev.another.im/another-im/anotherim-js/issues/95. It does not stop the room being recreated; only libtacky can, since libtacky runs autojoin.
Owner

Fixed in libtacky 1.2.2: https://dev.another.im/another-im/libtacky/releases/tag/v1.2.2

Autojoin now asks the room's disco#info before sending the join presence. A room that answers item-not-found or gone is not joined (new event muc , then ), and the bookmark is left as is. A destroy, ours or another owner's, clears the bookmark's autojoin and keeps the bookmark, so autojoin can no longer bring the room back. The host's own explicit joins still create a room.

This is C34 from interop issue 1, comment 1015.

Fixed in libtacky 1.2.2: https://dev.another.im/another-im/libtacky/releases/tag/v1.2.2 Autojoin now asks the room's disco#info before sending the join presence. A room that answers item-not-found or gone is not joined (new event muc <Gone>, then <Error>), and the bookmark is left as is. A destroy, ours or another owner's, clears the bookmark's autojoin and keeps the bookmark, so autojoin can no longer bring the room back. The host's own explicit joins still create a room. This is C34 from interop issue 1, comment 1015.
Sign in to join this conversation.
No milestone
No project
No assignees
2 participants
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
another-im/libtacky#26
No description provided.