feat(server): add WS federation gating for DM events and shared handlers
This commit is contained in:
@@ -141,9 +141,19 @@ export function handleClientEvent(
|
|||||||
userId: string,
|
userId: string,
|
||||||
username: string,
|
username: string,
|
||||||
ws: WebSocket,
|
ws: WebSocket,
|
||||||
|
isFederated: boolean,
|
||||||
): void {
|
): void {
|
||||||
const type = event.type as string;
|
const type = event.type as string;
|
||||||
|
|
||||||
|
// Federation gating: federated users must use their home instance for DM operations
|
||||||
|
if (isFederated && type.startsWith('dm_')) {
|
||||||
|
connectionManager.sendToUser(userId, {
|
||||||
|
type: 'error',
|
||||||
|
message: 'Federated users must use their home instance for DM operations',
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 'message_create':
|
case 'message_create':
|
||||||
handleMessageCreate(event, userId);
|
handleMessageCreate(event, userId);
|
||||||
@@ -179,16 +189,16 @@ export function handleClientEvent(
|
|||||||
handleDmMessageDelete(event, userId);
|
handleDmMessageDelete(event, userId);
|
||||||
break;
|
break;
|
||||||
case 'reaction_add':
|
case 'reaction_add':
|
||||||
handleReactionAdd(event, userId);
|
handleReactionAdd(event, userId, isFederated);
|
||||||
break;
|
break;
|
||||||
case 'reaction_remove':
|
case 'reaction_remove':
|
||||||
handleReactionRemove(event, userId);
|
handleReactionRemove(event, userId, isFederated);
|
||||||
break;
|
break;
|
||||||
case 'channel_ack':
|
case 'channel_ack':
|
||||||
handleChannelAck(event, userId);
|
handleChannelAck(event, userId, isFederated);
|
||||||
break;
|
break;
|
||||||
case 'mark_unread':
|
case 'mark_unread':
|
||||||
handleMarkUnread(event, userId);
|
handleMarkUnread(event, userId, isFederated);
|
||||||
break;
|
break;
|
||||||
case 'dm_call_start':
|
case 'dm_call_start':
|
||||||
handleDmCallStart(event, userId, username, ws);
|
handleDmCallStart(event, userId, username, ws);
|
||||||
@@ -1072,7 +1082,7 @@ function handleDmMessageDelete(event: Record<string, unknown>, userId: string):
|
|||||||
|
|
||||||
// ─── Reaction Handlers ─────────────────────────────────────────────────────
|
// ─── Reaction Handlers ─────────────────────────────────────────────────────
|
||||||
|
|
||||||
function handleReactionAdd(event: Record<string, unknown>, userId: string): void {
|
function handleReactionAdd(event: Record<string, unknown>, userId: string, isFederated: boolean): void {
|
||||||
const messageId = event.messageId as string;
|
const messageId = event.messageId as string;
|
||||||
const emoji = event.emoji as string;
|
const emoji = event.emoji as string;
|
||||||
|
|
||||||
@@ -1118,6 +1128,7 @@ function handleReactionAdd(event: Record<string, unknown>, userId: string): void
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fall through to DM message
|
// Fall through to DM message
|
||||||
|
if (isFederated) return;
|
||||||
const dmMsg = db.select().from(schema.dmMessages).where(eq(schema.dmMessages.id, messageId)).get();
|
const dmMsg = db.select().from(schema.dmMessages).where(eq(schema.dmMessages.id, messageId)).get();
|
||||||
if (!dmMsg || !isDmMember(dmMsg.dmChannelId, userId)) return;
|
if (!dmMsg || !isDmMember(dmMsg.dmChannelId, userId)) return;
|
||||||
|
|
||||||
@@ -1169,7 +1180,7 @@ function handleReactionAdd(event: Record<string, unknown>, userId: string): void
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleReactionRemove(event: Record<string, unknown>, userId: string): void {
|
function handleReactionRemove(event: Record<string, unknown>, userId: string, isFederated: boolean): void {
|
||||||
const messageId = event.messageId as string;
|
const messageId = event.messageId as string;
|
||||||
const emoji = event.emoji as string;
|
const emoji = event.emoji as string;
|
||||||
|
|
||||||
@@ -1203,6 +1214,7 @@ function handleReactionRemove(event: Record<string, unknown>, userId: string): v
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Fall through to DM message
|
// Fall through to DM message
|
||||||
|
if (isFederated) return;
|
||||||
const dmMsg = db.select().from(schema.dmMessages).where(eq(schema.dmMessages.id, messageId)).get();
|
const dmMsg = db.select().from(schema.dmMessages).where(eq(schema.dmMessages.id, messageId)).get();
|
||||||
if (!dmMsg || !isDmMember(dmMsg.dmChannelId, userId)) return;
|
if (!dmMsg || !isDmMember(dmMsg.dmChannelId, userId)) return;
|
||||||
|
|
||||||
@@ -1254,7 +1266,7 @@ function handleReactionRemove(event: Record<string, unknown>, userId: string): v
|
|||||||
|
|
||||||
// ─── Read State Handler ────────────────────────────────────────────────────
|
// ─── Read State Handler ────────────────────────────────────────────────────
|
||||||
|
|
||||||
function handleChannelAck(event: Record<string, unknown>, userId: string): void {
|
function handleChannelAck(event: Record<string, unknown>, userId: string, isFederated: boolean): void {
|
||||||
const channelId = event.channelId as string;
|
const channelId = event.channelId as string;
|
||||||
const messageId = event.messageId as string;
|
const messageId = event.messageId as string;
|
||||||
if (!channelId || !messageId) return;
|
if (!channelId || !messageId) return;
|
||||||
@@ -1266,6 +1278,7 @@ function handleChannelAck(event: Record<string, unknown>, userId: string): void
|
|||||||
if (spaceId) {
|
if (spaceId) {
|
||||||
if (!isMember(spaceId, userId)) return;
|
if (!isMember(spaceId, userId)) return;
|
||||||
} else {
|
} else {
|
||||||
|
if (isFederated) return;
|
||||||
if (!isDmMember(channelId, userId)) return;
|
if (!isDmMember(channelId, userId)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1309,7 +1322,7 @@ function handleChannelAck(event: Record<string, unknown>, userId: string): void
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMarkUnread(event: Record<string, unknown>, userId: string): void {
|
function handleMarkUnread(event: Record<string, unknown>, userId: string, isFederated: boolean): void {
|
||||||
const channelId = event.channelId as string;
|
const channelId = event.channelId as string;
|
||||||
const messageId = event.messageId as string;
|
const messageId = event.messageId as string;
|
||||||
if (!channelId || !messageId) return;
|
if (!channelId || !messageId) return;
|
||||||
@@ -1320,6 +1333,7 @@ function handleMarkUnread(event: Record<string, unknown>, userId: string): void
|
|||||||
if (spaceId) {
|
if (spaceId) {
|
||||||
if (!isMember(spaceId, userId)) return;
|
if (!isMember(spaceId, userId)) return;
|
||||||
} else {
|
} else {
|
||||||
|
if (isFederated) return;
|
||||||
if (!isDmMember(channelId, userId)) return;
|
if (!isDmMember(channelId, userId)) return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user