From e40a63ba9b19d7c436b8a4532b8c6c8ca4e170ab Mon Sep 17 00:00:00 2001 From: Jannis Braun <151788261+TheZwiss@users.noreply.github.com> Date: Wed, 1 Apr 2026 03:57:42 +0200 Subject: [PATCH] fix(federation): assign deterministic federatedId on 1-on-1 DM creation POST /api/dm created channels with federatedId=NULL, so when the S2S reply arrived, processCreateEvent couldn't find the channel and created a duplicate. Now computes the deterministic SHA256 hash at creation time when either participant is federated. --- packages/server/src/routes/dm.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/packages/server/src/routes/dm.ts b/packages/server/src/routes/dm.ts index 1801ad00..236b5fcb 100644 --- a/packages/server/src/routes/dm.ts +++ b/packages/server/src/routes/dm.ts @@ -446,10 +446,27 @@ export async function dmRoutes(app: FastifyInstance): Promise { const dmChannelId = generateSnowflake(); const now = Date.now(); + // Compute deterministic federatedId for federated 1-on-1 DMs so that the + // S2S relay can find this channel when the reply arrives, preventing duplicates. + let federatedId: string | null = null; + if (isFederationRelayEnabled()) { + const callerUser = db.select().from(schema.users).where(eq(schema.users.id, request.userId)).get(); + const callerHomeUserId = callerUser?.homeUserId || request.userId; + const targetHomeUserId = targetUser.homeUserId || targetUser.id; + const callerHomeInstance = callerUser?.homeInstance || null; + const targetHomeInstance = targetUser.homeInstance || null; + + // If either user is federated, this DM needs a federatedId for S2S relay matching + if (callerHomeInstance || targetHomeInstance) { + federatedId = computeFederatedId(callerHomeUserId, targetHomeUserId); + } + } + db.transaction((tx) => { tx.insert(schema.dmChannels).values({ id: dmChannelId, ownerId: null, + federatedId, createdAt: now, }).run();