Skip to content

Conversation

@sampaiodiego
Copy link
Member

@sampaiodiego sampaiodiego commented Dec 23, 2025

FB-162
FB-165

Summary by CodeRabbit

  • New Features

    • New direct-message creation flow that handles local and remote participants more robustly.
    • Room creation utilities now accept an optional room-version by default.
  • Deprecated

    • Older direct-message room creation API is deprecated; migrate to the new flow.
  • Bug Fixes / Reliability

    • Invite processing now emits membership events and join logic better distinguishes local vs remote joins.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Dec 23, 2025

Caution

Review failed

The pull request is closed.

Note

Other AI code review bot(s) detected

CodeRabbit has detected other AI code review bot(s) in this pull request and will avoid duplicating their findings in the review comments. This may lead to a less comprehensive review.

Walkthrough

Adds a new federation-aware direct-message creation path (SDK + RoomService), changes RoomService.joinUser signature to derive residency from the roomId, emits homeserver.matrix.membership events during invite handling, and makes PersistentEventFactory.newCreateEvent's roomVersion optional.

Changes

Cohort / File(s) Summary
SDK surface
packages/federation-sdk/src/sdk.ts
Import UserID; add public createDirectMessage({ creatorUserId, members }) delegating to roomService.createDirectMessage; keep createDirectMessageRoom (deprecated JSDoc); remove public joinUser wrapper.
Room service (DM, join, invite)
packages/federation-sdk/src/services/room.service.ts, packages/federation-sdk/src/services/invite.service.ts
RoomService.joinUser signature changed to (roomId, userId) and resident-server is derived from roomId; acceptInvite updated accordingly. Added createDirectMessage({ creatorUserId, members }) building/singing create & state events, persisting state, and inviting/adding members (local vs remote). createDirectMessageRoom now returns Promise<RoomID> and marked deprecated. invite.service.ts now emits homeserver.matrix.membership events after invite processing.
Event factory
packages/room/src/manager/factory.ts
PersistentEventFactory.newCreateEvent now accepts optional roomVersion: RoomVersion = PersistentEventFactory.defaultRoomVersion.
Tests
packages/federation-sdk/src/services/room.service.spec.ts
Updated tests to match joinUser(roomId, userId) signature (call sites adjusted).

Sequence Diagram(s)

sequenceDiagram
    participant Client
    participant SDK as FederationSDK
    participant RoomSvc as RoomService
    participant Factory as PersistentEventFactory
    participant FedSvc as FederationService
    participant Store as Storage/DB

    Client->>SDK: createDirectMessage(creatorUserId, members)
    SDK->>RoomSvc: createDirectMessage(creator, members)
    RoomSvc->>Factory: newCreateEvent(creator[, roomVersion])
    Factory-->>RoomSvc: signed m.room.create
    RoomSvc->>Store: persist create & state events (power_levels, join_rules, etc.)
    loop each member
        alt member is remote
            RoomSvc->>FedSvc: send invite (signed)
            FedSvc-->>RoomSvc: ack
            RoomSvc->>Store: persist outbound invite
        else member is local
            RoomSvc->>Store: persist local membership
        end
    end
    RoomSvc-->>SDK: return roomId
    SDK-->>Client: return roomId
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • ggazzo
  • ricardogarim

Poem

🐰 I stitched a DM with careful hops and code,
Signed events, soft thumps down the federation road,
Local friends welcomed, distant ones invited,
Old wrappers faded while new paths ignited,
A tiny rabbit cheers — the network's glowed! 🥕

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title 'feat: new method to create DMs' directly and clearly summarizes the main change: addition of a new createDirectMessage method for creating direct messages.
Linked Issues check ✅ Passed The PR adds the createDirectMessage method with proper power levels and room state events (FB-165), and handles DM creation with support for multiple members and proper naming (FB-162).
Out of Scope Changes check ✅ Passed All changes are scoped to DM creation improvements: SDK wrapper method, service implementation with state events, invite event emission, and optional roomVersion parameter for event factory.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

📜 Recent review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 16d8787 and 8ed8ac8.

📒 Files selected for processing (2)
  • packages/federation-sdk/src/services/room.service.spec.ts
  • packages/federation-sdk/src/services/room.service.ts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@codecov-commenter
Copy link

codecov-commenter commented Dec 23, 2025

Codecov Report

❌ Patch coverage is 1.86047% with 211 lines in your changes missing coverage. Please review.
✅ Project coverage is 52.04%. Comparing base (79e9ebf) to head (8ed8ac8).

Files with missing lines Patch % Lines
...ckages/federation-sdk/src/services/room.service.ts 1.53% 192 Missing ⚠️
packages/federation-sdk/src/sdk.ts 9.09% 10 Missing ⚠️
...ages/federation-sdk/src/services/invite.service.ts 0.00% 5 Missing ⚠️
packages/room/src/manager/factory.ts 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #321      +/-   ##
==========================================
- Coverage   53.15%   52.04%   -1.12%     
==========================================
  Files          97       97              
  Lines       12942    13153     +211     
==========================================
- Hits         6879     6845      -34     
- Misses       6063     6308     +245     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/room.service.ts (1)

1636-1687: Consider error handling for partial invite failures.

If one member invite fails (especially for remote federation), the room is left in an inconsistent state with some invites sent but the method throwing an error. Consider whether to:

  1. Continue with remaining members and collect failures, or
  2. Document this as expected behavior (fail-fast).

For group DMs, partial failure handling might provide a better UX.

📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 79e9ebf and 898b05b.

📒 Files selected for processing (3)
  • packages/federation-sdk/src/sdk.ts
  • packages/federation-sdk/src/services/room.service.ts
  • packages/room/src/manager/factory.ts
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/services/room.service.ts
  • packages/federation-sdk/src/sdk.ts
🧬 Code graph analysis (2)
packages/room/src/manager/factory.ts (2)
packages/room/src/types/_common.ts (1)
  • UserID (20-20)
packages/room/src/manager/type.ts (1)
  • RoomVersion (14-14)
packages/federation-sdk/src/sdk.ts (1)
packages/federation-sdk/src/index.ts (1)
  • UserID (33-33)
🔇 Additional comments (5)
packages/room/src/manager/factory.ts (1)

85-88: LGTM!

The optional roomVersion parameter with a sensible default simplifies the API for callers while maintaining type safety. The default aligns with Synapse's room version.

packages/federation-sdk/src/services/room.service.ts (2)

1681-1683: Clarify the commented-out broadcast.

The commented sendEventToAllServersInRoom call may be needed for group DMs involving multiple remote servers. If server A creates a room and invites users from servers B and C, server B should receive the invite event for the user on server C (and vice versa) to maintain consistent room state.


1692-1694: LGTM!

Proper deprecation annotation that preserves backward compatibility while guiding users to the new API.

packages/federation-sdk/src/sdk.ts (2)

2-2: LGTM!

Import correctly added for the UserID type used in the new method signature.


46-66: LGTM!

Clean SDK facade implementation with proper deprecation annotation and typed delegation to the new RoomService.createDirectMessage method.

Comment on lines +1503 to +1511
async createDirectMessage({
creatorUserId,
members,
}: {
creatorUserId: UserID;
members: UserID[];
}) {
const roomCreateEvent =
PersistentEventFactory.newCreateEvent(creatorUserId);
Copy link
Contributor

@coderabbitai coderabbitai bot Dec 23, 2025

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Missing check for existing DM room.

Unlike createDirectMessageRoom (lines 1703-1710), this method doesn't check for existing direct message rooms before creating a new one. This could lead to duplicate DM rooms between the same participants.

Consider adding a similar check using findExistingDirectMessageRoom or a variation that supports multiple members, or document that callers are responsible for this check.

🤖 Prompt for AI Agents
In packages/federation-sdk/src/services/room.service.ts around lines 1503 to
1511, this createDirectMessage function lacks the existing-DM check and may
create duplicate DM rooms; before constructing a new create event call the same
existing-room lookup used by createDirectMessageRoom (e.g.,
findExistingDirectMessageRoom) or implement a variant that accepts the creator
and members array to detect an existing room for the same participants, and if
found return that room (or its ID) instead of creating a new one; alternatively,
explicitly document that callers must ensure no existing DM exists if you choose
not to perform the check.

Copy link
Member

Choose a reason for hiding this comment

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

this validation can be done on the application or UI side, but if the backend decides to do it differently, it shouldn't be prohibited.

Copy link
Contributor

Choose a reason for hiding this comment

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

@ggazzo, understood! That's a reasonable architectural decision. Allowing the backend flexibility to create DMs without enforcing duplicate checks gives you more control at different layers of your application. The application or UI can implement the duplicate prevention logic as needed for specific use cases.

Thank you for clarifying! 👍


🧠 Learnings used
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

@sampaiodiego
Copy link
Member Author

@cubic-dev-ai

@cubic-dev-ai
Copy link

cubic-dev-ai bot commented Dec 23, 2025

@cubic-dev-ai

@sampaiodiego Hi! I'm cubic. Here's how I can help with your PR:

Ask questions

  • @cubic why did you suggest this change?

Request reviews

  • @cubic review this - Run a code review

Give feedback

  • @cubic this suggestion doesn't work for our use case

Request fixes

  • @cubic fix this - Ask me to fix an issue. I can push commits to this PR or open a new PR; tell me which you want.

@sampaiodiego
Copy link
Member Author

@cubic review this

@cubic-dev-ai
Copy link

cubic-dev-ai bot commented Dec 23, 2025

@cubic review this

@sampaiodiego I have started the AI code review. It will take a few minutes to complete.

Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 3 files

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/federation-sdk/src/services/room.service.ts">

<violation number="1" location="packages/federation-sdk/src/services/room.service.ts:1510">
P1: Missing check for existing DM room before creation. The deprecated `createDirectMessageRoom` method checks for existing direct message rooms before creating a new one, but this new method creates a room immediately without verifying if a DM already exists between these participants. This could lead to duplicate DM rooms between the same users. Consider adding a lookup using `findExistingDirectMessageRoom` or a variant that supports multiple members before creating the room.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

creatorUserId: UserID;
members: UserID[];
}) {
const roomCreateEvent =
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P1: Missing check for existing DM room before creation. The deprecated createDirectMessageRoom method checks for existing direct message rooms before creating a new one, but this new method creates a room immediately without verifying if a DM already exists between these participants. This could lead to duplicate DM rooms between the same users. Consider adding a lookup using findExistingDirectMessageRoom or a variant that supports multiple members before creating the room.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/federation-sdk/src/services/room.service.ts, line 1510:

<comment>Missing check for existing DM room before creation. The deprecated `createDirectMessageRoom` method checks for existing direct message rooms before creating a new one, but this new method creates a room immediately without verifying if a DM already exists between these participants. This could lead to duplicate DM rooms between the same users. Consider adding a lookup using `findExistingDirectMessageRoom` or a variant that supports multiple members before creating the room.</comment>

<file context>
@@ -1500,6 +1500,198 @@ export class RoomService {
+		creatorUserId: UserID;
+		members: UserID[];
+	}) {
+		const roomCreateEvent =
+			PersistentEventFactory.newCreateEvent(creatorUserId);
+
</file context>
Fix with Cubic

Copy link
Member

Choose a reason for hiding this comment

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

This validation can be done on the application or UI side, but if the backend decides to do it differently, it shouldn't be prohibited.

ggazzo
ggazzo previously approved these changes Dec 23, 2025
ggazzo
ggazzo previously approved these changes Dec 23, 2025
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
packages/federation-sdk/src/services/room.service.ts (1)

1510-1511: Pass explicit roomVersion parameter for consistency.

While the default room version ('10') is correct, other calls in this file explicitly pass PersistentEventFactory.defaultRoomVersion to newCreateEvent(). Align this call with the established pattern in the same file for consistency.

const roomCreateEvent =
    PersistentEventFactory.newCreateEvent(creatorUserId, PersistentEventFactory.defaultRoomVersion);
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Jira integration is disabled by default for public repositories

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 898b05b and 16d8787.

📒 Files selected for processing (3)
  • packages/federation-sdk/src/sdk.ts
  • packages/federation-sdk/src/services/invite.service.ts
  • packages/federation-sdk/src/services/room.service.ts
🧰 Additional context used
🧠 Learnings (2)
📚 Learning: 2025-10-10T22:18:31.655Z
Learnt from: sampaiodiego
Repo: RocketChat/homeserver PR: 224
File: packages/federation-sdk/src/services/event-authorization.service.ts:261-268
Timestamp: 2025-10-10T22:18:31.655Z
Learning: In packages/federation-sdk/src/services/state.service.ts, the method `StateService.getLatestRoomState(roomId: string)` has return type `Promise<State>` and never returns undefined. If the state is not found, it throws an error with message "No state found for room ${roomId}" instead of returning undefined.

Applied to files:

  • packages/federation-sdk/src/sdk.ts
  • packages/federation-sdk/src/services/room.service.ts
📚 Learning: 2025-09-14T13:30:07.786Z
Learnt from: ricardogarim
Repo: RocketChat/homeserver PR: 184
File: packages/core/src/utils/fetch.ts:12-47
Timestamp: 2025-09-14T13:30:07.786Z
Learning: In the RocketChat/homeserver codebase, the team prefers to keep implementations simple and functional rather than adding complex optimizations prematurely. Performance improvements are deferred to future work when there's clear evidence they're needed.

Applied to files:

  • packages/federation-sdk/src/services/room.service.ts
🧬 Code graph analysis (2)
packages/federation-sdk/src/sdk.ts (1)
packages/federation-sdk/src/index.ts (1)
  • UserID (33-33)
packages/federation-sdk/src/services/room.service.ts (2)
packages/room/src/manager/event-wrapper.ts (2)
  • residentServer (129-135)
  • extractDomainFromId (23-29)
packages/room/src/types/_common.ts (2)
  • RoomID (16-16)
  • UserID (20-20)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: cubic · AI code reviewer
🔇 Additional comments (11)
packages/federation-sdk/src/sdk.ts (3)

2-2: LGTM!

The UserID type import is correctly added to support the new createDirectMessage method signature.


46-53: LGTM!

The deprecation notice is clear and provides a migration path to the new createDirectMessage method while maintaining backward compatibility.


55-66: LGTM!

The new createDirectMessage method provides a clean API for creating direct messages with multiple members, which aligns with the PR objectives for improved group DM handling.

packages/federation-sdk/src/services/room.service.ts (8)

913-919: LGTM! Correctness fix for resident server derivation.

The change to derive the resident server from roomId (line 919) instead of the sender is correct. The room's resident server is determined by the domain in the room ID, not the sender. Making joinUser private is also appropriate as it's an internal implementation detail.


1133-1133: LGTM!

The call to joinUser is correctly updated to match the refactored signature.


1545-1568: Power levels configuration addresses FB-165.

The power levels are configured differently for 1:1 DMs vs group DMs:

  • 1:1 DMs: both users get level 100 (line 1548)
  • Group DMs: only creator gets 100
  • Detailed event-specific permissions are set (lines 1552-1568)

This aligns with the PR objective FB-165 to match Element's DM power level structure. The configuration looks comprehensive and appropriate.


1681-1683: Commented-out federation broadcast.

Lines 1681-1683 contain a commented-out call to sendEventToAllServersInRoom. This suggests uncertainty about whether remote servers should be notified of member invites during DM creation.

According to the Matrix federation specification, invite events are typically sent directly to the invited user's server via the /invite endpoint (as done on lines 1667-1670), not broadcast to all servers in the room. The commented code is likely correct to remain disabled, but please confirm this is intentional.


1692-1694: LGTM!

The deprecation notice clearly indicates the migration path to createDirectMessage.


1636-1687: LGTM! Proper handling of local vs remote member invitations.

The loop correctly distinguishes between local and remote members, performing federation validation and using the appropriate invitation flow for each. The displayname extraction for invitees (line 1645) should help address PR objective FB-162 regarding invitee name display.


1644-1646: is_direct flag is correctly limited to 1:1 DMs.

The implementation correctly sets is_direct: true only for 1:1 DMs (members.length === 1). This matches Synapse's behavior per the Matrix specification, which treats is_direct as a signalling hint that should be set in invite events for rooms created as direct chats. Group DMs with more than one recipient should not include the is_direct flag, and the code implements this correctly. The comment accurately reflects this behavior.


1521-1533: buildEvent automatically handles auth_events, prev_events, and depth calculation—the hardcoded initial values are correct.

The buildEvent method (state.service.ts:289-290) auto-populates auth_events and prev_events when empty via addAuthEvents and addPrevEvents. The addPrevEvents method (event-wrapper.ts:476-480) automatically recalculates depth based on previous events: depth = max(prev_events.depth) + 1. The hardcoded sequential depths (2, 3, 4, 5, 6, 7+) in room.service.ts are intentional initial placeholders that are overwritten during event construction.

Comment on lines +220 to +224
await this.emitterService.emit('homeserver.matrix.membership', {
event_id: inviteEvent.eventId,
event: inviteEvent.event,
});

Copy link
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Duplicate membership event emission for locally resident invites.

Lines 220-224 emit a homeserver.matrix.membership event after processing a locally resident invite. However, lines 263-266 unconditionally emit the same event after the if/else block completes. This causes locally resident invites to emit the membership event twice.

🔎 Proposed fix to remove the duplicate emission

Remove the emission at lines 220-224 since the emission at lines 263-266 already handles all cases:

 		if (residentServer === this.configService.serverName) {
 			await this.eventAuthorizationService.checkAclForInvite(
 				event.room_id,
 				residentServer,
 			);
 
 			await this.stateService.handlePdu(inviteEvent);
 
-			await this.emitterService.emit('homeserver.matrix.membership', {
-				event_id: inviteEvent.eventId,
-				event: inviteEvent.event,
-			});
-
 			return inviteEvent;
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
await this.emitterService.emit('homeserver.matrix.membership', {
event_id: inviteEvent.eventId,
event: inviteEvent.event,
});
if (residentServer === this.configService.serverName) {
await this.eventAuthorizationService.checkAclForInvite(
event.room_id,
residentServer,
);
await this.stateService.handlePdu(inviteEvent);
return inviteEvent;
}
🤖 Prompt for AI Agents
In packages/federation-sdk/src/services/invite.service.ts around lines 220 to
224 and 263 to 266, a homeserver.matrix.membership event is emitted twice for
locally resident invites (once inside the local-invite branch and again
unconditionally afterward); remove the first emission at lines 220-224 so the
single, unconditional emitter at lines 263-266 handles all cases, ensuring the
membership event is emitted only once.

@sampaiodiego sampaiodiego merged commit 015d352 into main Dec 23, 2025
3 of 4 checks passed
@sampaiodiego sampaiodiego deleted the feat-new-method-to-create-dms branch December 23, 2025 21:49
Copy link

@cubic-dev-ai cubic-dev-ai bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 2 files (changes from recent commits).

Prompt for AI agents (all issues)

Check if these issues are valid — if so, understand the root cause of each and fix them.


<file name="packages/federation-sdk/src/services/room.service.ts">

<violation number="1" location="packages/federation-sdk/src/services/room.service.ts:913">
P2: Changing `joinUser` from private to public allows external callers to bypass the invite validation in `acceptInvite`. For invite-only rooms (like DMs created by this PR), external code could attempt to join users without validating they have a proper invite first.</violation>
</file>

Reply to cubic to teach it or ask questions. Re-run a review with @cubic-dev-ai review this PR

// if local room, add the user to the room if allowed.
// if remote room, run through the join process
async joinUser(roomId: RoomID, sender: UserID, userId: UserID) {
async joinUser(roomId: RoomID, userId: UserID) {
Copy link

@cubic-dev-ai cubic-dev-ai bot Dec 23, 2025

Choose a reason for hiding this comment

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

P2: Changing joinUser from private to public allows external callers to bypass the invite validation in acceptInvite. For invite-only rooms (like DMs created by this PR), external code could attempt to join users without validating they have a proper invite first.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/federation-sdk/src/services/room.service.ts, line 913:

<comment>Changing `joinUser` from private to public allows external callers to bypass the invite validation in `acceptInvite`. For invite-only rooms (like DMs created by this PR), external code could attempt to join users without validating they have a proper invite first.</comment>

<file context>
@@ -910,7 +910,7 @@ export class RoomService {
 	// if local room, add the user to the room if allowed.
 	// if remote room, run through the join process
-	private async joinUser(roomId: RoomID, userId: UserID) {
+	async joinUser(roomId: RoomID, userId: UserID) {
 		const configService = this.configService;
 		const stateService = this.stateService;
</file context>
Fix with Cubic

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.

4 participants