Skip to content

Commit e46e46a

Browse files
authored
User correct Matrix accounts when redacting events (#780)
* Use correct Slack ghosts to redact messages sent from Slack This makes us the original sender's intent to redact messages, so that we do not require an elevated PL to handle message deletion. * Use our Matrix bot to redact Matrix messages deleted on Slack * Don't delete all bot message with our main account * Refactor message deletion; fallback to using our bot if we can't determine a more fitting user * Changelog
1 parent 0b553be commit e46e46a

File tree

4 files changed

+50
-5
lines changed

4 files changed

+50
-5
lines changed

changelog.d/766.bugfix

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
User correct Matrix accounts when redacting events.

src/BaseSlackHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ export interface ISlackEventMessageAttachment {
5050
}
5151

5252
export interface ISlackMessageEvent extends ISlackEvent {
53+
team?: string;
5354
team_domain?: string;
5455
team_id?: string;
5556
user?: string;

src/SlackEventHandler.ts

Lines changed: 41 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { BaseSlackHandler, ISlackEvent, ISlackMessageEvent, ISlackUser } from ".
1818
import { BridgedRoom } from "./BridgedRoom";
1919
import { Main, METRIC_RECEIVED_MESSAGE } from "./Main";
2020
import { Logger } from "matrix-appservice-bridge";
21+
import { TeamEntry } from "./datastore/Models";
2122
const log = new Logger("SlackEventHandler");
2223

2324
/**
@@ -289,11 +290,10 @@ export class SlackEventHandler extends BaseSlackHandler {
289290
}
290291
}
291292
} else if (msg.subtype === "message_deleted" && msg.deleted_ts) {
292-
const originalEvent = await this.main.datastore.getEventBySlackId(msg.channel, msg.deleted_ts);
293-
if (originalEvent) {
294-
const botClient = this.main.botIntent.matrixClient;
295-
await botClient.redactEvent(originalEvent.roomId, originalEvent.eventId);
296-
return;
293+
try {
294+
await this.deleteMessage(msg, team);
295+
} catch (err) {
296+
log.error(err);
297297
}
298298
// If we don't have the event
299299
throw Error("unknown_message");
@@ -315,6 +315,42 @@ export class SlackEventHandler extends BaseSlackHandler {
315315
return room.onSlackMessage(msg);
316316
}
317317

318+
private async deleteMessage(msg: ISlackMessageEvent, team: TeamEntry): Promise<void> {
319+
const originalEvent = await this.main.datastore.getEventBySlackId(msg.channel, msg.deleted_ts!);
320+
if (originalEvent) {
321+
const previousMessage = msg.previous_message;
322+
if (!previousMessage) {
323+
throw new Error(`Cannot delete message with no previous_message: ${JSON.stringify(msg)}`);
324+
}
325+
326+
// Try to determine the Matrix user responsible for deleting the message, fallback to our main bot if all else fails
327+
if (!previousMessage.user) {
328+
log.warn("We don't know the original sender of", previousMessage, "will try to remove with our bot");
329+
}
330+
331+
const isOurMessage = previousMessage.subtype === 'bot_message' && (previousMessage.bot_id === team.bot_id);
332+
333+
if (previousMessage.user && !isOurMessage) {
334+
try {
335+
const ghost = await this.main.ghostStore.get(previousMessage.user, previousMessage.team_domain, previousMessage.team);
336+
await ghost.redactEvent(originalEvent.roomId, originalEvent.eventId);
337+
return;
338+
} catch (err) {
339+
log.warn(`Failed to remove message on behalf of ${previousMessage.user}, falling back to our bot`);
340+
}
341+
}
342+
343+
try {
344+
const botClient = this.main.botIntent.matrixClient;
345+
await botClient.redactEvent(originalEvent.roomId, originalEvent.eventId, "Deleted on Slack");
346+
} catch (err) {
347+
throw new Error(
348+
`Failed to remove message ${JSON.stringify(previousMessage)} with our Matrix bot. insufficient power level? Error: ${err}`
349+
);
350+
}
351+
}
352+
}
353+
318354
private async handleReaction(event: ISlackEventReaction, teamId: string) {
319355
// Reactions store the channel in the item
320356
const channel = event.item.channel;

src/SlackGhost.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,13 @@ export class SlackGhost {
321321
return Slackdown.parse(body);
322322
}
323323

324+
public async redactEvent(roomId: string, eventId: string) {
325+
if (!this._intent) {
326+
throw Error('No intent associated with ghost');
327+
}
328+
await this._intent.matrixClient.redactEvent(roomId, eventId);
329+
}
330+
324331
public async sendInThread(roomId: string, text: string, slackRoomId: string,
325332
slackEventTs: string, replyEvent: IMatrixReplyEvent): Promise<void> {
326333
const content = {

0 commit comments

Comments
 (0)