fix: gate all client DM events on active S2S peer status

The client's direct WS connection to remote instances (via Connections)
delivered DM events independently of S2S peering. Added activePeerOrigins
allowlist to ready payload — all DM event handlers now silently drop
events from non-home origins without an active peer. This prevents
notifications, sounds, previews, typing indicators, calls, and channel
updates from instances where peering was revoked or never established.
This commit is contained in:
Jannis Braun
2026-04-20 17:05:57 +02:00
parent 83b682d501
commit 0aec716d4c
3 changed files with 50 additions and 2 deletions
+10 -1
View File
@@ -937,6 +937,7 @@ function buildReadyPayload(userId: string): {
userActivities: Record<string, Activity[]>;
rejectedPeerOrigins: string[];
awaitingApprovalPeerOrigins: string[];
activePeerOrigins: string[];
pendingApprovalCount: number;
} {
const db = getDb();
@@ -1482,6 +1483,14 @@ function buildReadyPayload(userId: string): {
.all();
const awaitingApprovalPeerOrigins = awaitingApprovalPeers.map(p => p.origin);
// Active peer origins — client uses this allowlist to gate DM events from remote instances
const activePeers = db
.select({ origin: schema.federationPeers.origin })
.from(schema.federationPeers)
.where(eq(schema.federationPeers.status, 'active'))
.all();
const activePeerOrigins = activePeers.map(p => p.origin);
// Pending approval count for admin notification
let pendingApprovalCount = 0;
if (userRow?.isAdmin === 1) {
@@ -1492,7 +1501,7 @@ function buildReadyPayload(userId: string): {
pendingApprovalCount = countResult?.count ?? 0;
}
return { user, spaces, dmChannels, folders, spaceLayout, layoutUpdatedAt, voiceStates, voiceUserStates, spaceVoiceStates, readStates, activeCalls, userActivities, rejectedPeerOrigins, awaitingApprovalPeerOrigins, pendingApprovalCount };
return { user, spaces, dmChannels, folders, spaceLayout, layoutUpdatedAt, voiceStates, voiceUserStates, spaceVoiceStates, readStates, activeCalls, userActivities, rejectedPeerOrigins, awaitingApprovalPeerOrigins, activePeerOrigins, pendingApprovalCount };
}
export async function registerWebSocket(app: FastifyInstance): Promise<void> {