Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog.d/373.bugfix
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Fix incoming messages in DM rooms created after having left an older DM room with the same XMPP user.
34 changes: 27 additions & 7 deletions src/MatrixEventHandler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,33 @@ export class MatrixEventHandler {
return;
}

if (membershipEvent && roomType === MROOM_TYPE_GROUP) {
if (this.bridge.getBot().isRemoteUser(event.sender)) {
return; // Don't really care about remote users
}
if (["join", "leave"].includes(event.content.membership as string)) {
await this.handleJoinLeaveGroup(ctx, membershipEvent);
return;
if (membershipEvent) {
switch (roomType) {
case MROOM_TYPE_GROUP:
if (bridgeBot.isRemoteUser(event.sender)) {
return; // Don't really care about remote users
}
if (["join", "leave", "ban"].includes(membershipEvent.content.membership)) {
await this.handleJoinLeaveGroup(ctx, membershipEvent);
return;
}
break;
case MROOM_TYPE_IM:
if (membershipEvent.content.membership === "leave" && membershipEvent.sender === ctx.remote.get<string>("matrixUser")) {
await this.store.removeRoomByRoomId(membershipEvent.room_id);
const protocol = this.purple.getProtocol(roomProtocol);
if (protocol) {
await this.bridge.getIntent(
protocol.getMxIdForProtocol(
ctx.remote.get<string>("recipient"),
this.config.bridge.domain,
this.config.bridge.userPrefix,
).getId()
).leave(membershipEvent.room_id);
}
log.info(`Left and removed entry for IM room ${membershipEvent.room_id} because the user left`);
return;
}
}
}

Expand Down
61 changes: 60 additions & 1 deletion src/Program.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import { XmppJsInstance } from "./xmppjs/XJSInstance";
import { Metrics } from "./Metrics";
import { AutoRegistration } from "./AutoRegistration";
import { GatewayHandler } from "./GatewayHandler";
import { IRemoteUserAdminData, MROOM_TYPE_UADMIN } from "./store/Types";
import { IRemoteUserAdminData, MROOM_TYPE_IM, MROOM_TYPE_UADMIN } from "./store/Types";

import * as fs from "fs";
import { webcrypto } from "node:crypto";
Expand Down Expand Up @@ -182,6 +182,64 @@ class Program {
}
}

private async dropStaleIMRooms(): Promise<void> {
const rooms = await this.store.getRoomsOfType(MROOM_TYPE_IM);
log.info(`Got ${rooms.length} IM rooms`);
// Errors here aren't fatal, so use Promise.allSettled instead of Promise.all
await Promise.allSettled(rooms.map(async (room) => {
if (!room.matrix) {
log.warn(`Not checking IM room because it has no matrix component`);
return;
}
const roomId = room.matrix.getId();
if (!room.remote) {
log.warn(`Not checking IM room ${roomId} because it has no remote links`);
return;
}
const recipient = room.remote.get<string>("recipient");
if (!recipient) {
log.warn(`Dropping IM room ${roomId} because it has no recipient`);
await this.store.removeRoomByRoomId(roomId);
return;
}
const protocol = this.purple.getProtocol(room.remote.get<string>("protocol_id"));
if (!protocol) {
log.warn(`Dropping IM room ${roomId} because it has no valid protocol`);
await this.store.removeRoomByRoomId(roomId);
return;
}
const remoteIntent = this.bridge.getIntent(
protocol.getMxIdForProtocol(
recipient,
this.config.bridge.domain,
this.config.bridge.userPrefix,
).getId()
);
const matrixUser = room.remote.get<string>("matrixUser");
if (!matrixUser) {
log.warn(`Dropping and leaving IM room ${roomId} because it has no matrix user`);
await this.store.removeRoomByRoomId(roomId);
await remoteIntent.leave(roomId);
return;
}
let content: Record<string, unknown>;
try {
content = await remoteIntent.matrixClient.getRoomStateEventContent(roomId, "m.room.member", matrixUser);
} catch (ex) {
log.warn(`Dropping and leaving IM room ${roomId} because we could not look up room state: ${ex}`);
await this.store.removeRoomByRoomId(roomId);
await remoteIntent.leave(roomId);
return;
}
if (content.membership === "leave") {
log.info(`Dropping and leaving IM room ${roomId} because its matrix user left`);
await this.store.removeRoomByRoomId(roomId);
await remoteIntent.leave(roomId);
return;
}
}));
}

private async runBridge(port: number, config: ConfigValue) {
const checkOnly = process.env.BIFROST_CHECK_ONLY === "true";
this.cfg.ApplyConfig(config);
Expand Down Expand Up @@ -349,6 +407,7 @@ class Program {
log.info("Started appservice listener on port", port);
await this.pingBridge();
await this.registerBot();
await this.dropStaleIMRooms();
log.info("Bridge has started.");
try {
await purple.start();
Expand Down
10 changes: 8 additions & 2 deletions src/store/Types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@ export const MROOM_TYPE_GROUP = "group";
export const MUSER_TYPE_ACCOUNT = "account";
export const MUSER_TYPE_GHOST = "ghost";

export type MROOM_TYPES = "user-admin"|"im"|"group";
export type MUSER_TYPES = "account"|"ghost";
export type MROOM_TYPES = typeof MROOM_TYPE_UADMIN | typeof MROOM_TYPE_IM | typeof MROOM_TYPE_GROUP;
export type MUSER_TYPES = typeof MUSER_TYPE_ACCOUNT | typeof MUSER_TYPE_GHOST;

export interface IRemoteRoomData {
protocol_id?: string;
Expand All @@ -31,6 +31,12 @@ export interface IRemoteUserAdminData extends IRemoteRoomData {
matrixUser?: string;
}

export interface RoomTypeToRemoteRoomData {
[MROOM_TYPE_IM]: IRemoteImData;
[MROOM_TYPE_GROUP]: IRemoteGroupData;
[MROOM_TYPE_UADMIN]: IRemoteUserAdminData;
};

export interface IMatrixUserData {
accounts: {[key: string]: IRemoteUserAccount};
}
Expand Down
Loading
Loading