Skip to content

Commit

Permalink
refactor to handle queued redactions
Browse files Browse the repository at this point in the history
  • Loading branch information
H-Shay committed Oct 5, 2024
1 parent ff98e77 commit 0d5f6d3
Show file tree
Hide file tree
Showing 5 changed files with 33 additions and 22 deletions.
2 changes: 2 additions & 0 deletions src/Mjolnir.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,8 @@ export class Mjolnir {

this.currentState = STATE_RUNNING;
await this.managementRoomOutput.logMessage(LogLevel.INFO, "Mjolnir@startup", "Startup complete. Now monitoring rooms.");
// update protected rooms set
this.protectedRoomsTracker.isAdmin = await this.isSynapseAdmin()
} catch (err) {
try {
LogService.error("Mjolnir", "Error during startup:");
Expand Down
7 changes: 6 additions & 1 deletion src/ProtectedRoomsSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ export class ProtectedRoomsSet {
*/
private readonly listRevisions = new Map<PolicyList, /** The last revision we used to sync protected rooms. */ Revision>();

/**
* whether the mjolnir instance is server admin
*/
public isAdmin = false

constructor(
private readonly client: MatrixSendClient,
private readonly clientUserId: string,
Expand All @@ -124,7 +129,7 @@ export class ProtectedRoomsSet {
* @param roomId The room we want to redact them in.
*/
public redactUser(userId: string, roomId: string) {
this.eventRedactionQueue.add(new RedactUserInRoom(userId, roomId));
this.eventRedactionQueue.add(new RedactUserInRoom(userId, roomId, this.isAdmin));
}

/**
Expand Down
3 changes: 2 additions & 1 deletion src/commands/RedactCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,8 @@ export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjo
}

const targetRoomIds = targetRoom ? [targetRoom] : mjolnir.protectedRoomsTracker.getProtectedRooms();
await redactUserMessagesIn(mjolnir, userId, targetRoomIds, limit);
const isAdmin = await mjolnir.isSynapseAdmin();
await redactUserMessagesIn(mjolnir.client, mjolnir.managementRoomOutput, userId, targetRoomIds, isAdmin, limit);

await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
await mjolnir.client.redactEvent(roomId, processingReactionId, 'done processing');
Expand Down
6 changes: 4 additions & 2 deletions src/queues/EventRedactionQueue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,15 +42,17 @@ export interface QueuedRedaction {
export class RedactUserInRoom implements QueuedRedaction {
userId: string;
roomId: string;
isAdmin: boolean;

constructor(userId: string, roomId: string) {
constructor(userId: string, roomId: string, isAdmin: boolean) {
this.userId = userId;
this.roomId = roomId;
this.isAdmin = isAdmin;
}

public async redact(client: MatrixClient, managementRoom: ManagementRoomOutput) {
await managementRoom.logMessage(LogLevel.DEBUG, "Mjolnir", `Redacting events from ${this.userId} in room ${this.roomId}.`);
await redactUserMessagesIn(client, managementRoom, this.userId, [this.roomId]);
await redactUserMessagesIn(client, managementRoom, this.userId, [this.roomId], this.isAdmin);
}

public redactionEqual(redaction: QueuedRedaction): boolean {
Expand Down
37 changes: 19 additions & 18 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { collectDefaultMetrics, Counter, Histogram, register } from "prom-client

import { IHealthConfig } from "./config";
import { MatrixSendClient } from "./MatrixEmitter";
import {Mjolnir} from "./Mjolnir";
import ManagementRoomOutput from "./ManagementRoomOutput";

// Define a few aliases to simplify parsing durations.

Expand Down Expand Up @@ -74,59 +74,60 @@ export function isTrueJoinEvent(event: any): boolean {
* Redact a user's messages in a set of rooms.
* See `getMessagesByUserIn`.
*
* @param mjolnir Current mjolnir instance
* @param client Client to redact the messages with.
* @param managementRoom Management room to log messages back to.
* @param userIdOrGlob A mxid or a glob which is applied to the whole sender field of events in the room, which will be redacted if they match.
* See `MatrixGlob` in matrix-bot-sdk.
* @param targetRoomIds Rooms to redact the messages from.
* @param isAdmin whether the bot is server admin
* @param limit The number of messages to redact from most recent first. If the limit is reached then no further messages will be redacted.
* @param noop Whether to operate in noop mode.
*/
export async function redactUserMessagesIn(mjolnir: Mjolnir, userIdOrGlob: string, targetRoomIds: string[], limit = 1000, noop = false) {
const isAdmin = await mjolnir.isSynapseAdmin();
export async function redactUserMessagesIn(client: MatrixSendClient, managementRoom: ManagementRoomOutput, userIdOrGlob: string, targetRoomIds: string[], isAdmin: boolean, limit = 1000, noop = false) {
const usingGlob = userIdOrGlob.includes("*");

async function adminRedaction(m: Mjolnir, userId: string, targetRooms: string[], lim = 1000) {
async function adminRedaction(c: MatrixSendClient, mr: ManagementRoomOutput, userId: string, targetRooms: string[], lim = 1000) {
let redactID: string;
const body = {"limit": lim, "rooms": targetRooms};
const redactEndpoint = `/_synapse/admin/v1/user/${userId}/redact`;
const response = await m.client.doRequest("GET", redactEndpoint, null, body);
const response = await c.doRequest("GET", redactEndpoint, null, body);
redactID = response["redact_id"];
await m.managementRoomOutput.logMessage(LogLevel.INFO, "utils#redactUserMessagesIn", `Successfully requested redaction, ID for task is ${redactID}`);
await mr.logMessage(LogLevel.INFO, "utils#redactUserMessagesIn", `Successfully requested redaction, ID for task is ${redactID}`);
}

async function redaction(m: Mjolnir, uIdOrGlob: string, targetRooms: string [], lim = 1000) {
async function redaction(c: MatrixSendClient, mr: ManagementRoomOutput, uIdOrGlob: string, targetRooms: string [], lim = 1000) {
for (const targetRoomId of targetRooms) {
await m.managementRoomOutput.logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Fetching sent messages for ${uIdOrGlob} in ${targetRoomId} to redact...`, targetRoomId);
await mr.logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Fetching sent messages for ${uIdOrGlob} in ${targetRoomId} to redact...`, targetRoomId);

try {
await getMessagesByUserIn(m.client, uIdOrGlob, targetRoomId, lim, async (eventsToRedact) => {
await getMessagesByUserIn(c, uIdOrGlob, targetRoomId, lim, async (eventsToRedact) => {
for (const targetEvent of eventsToRedact) {
await m.managementRoomOutput.logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Redacting ${targetEvent['event_id']} in ${targetRoomId}`, targetRoomId);
await mr.logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Redacting ${targetEvent['event_id']} in ${targetRoomId}`, targetRoomId);
if (!noop) {
await m.client.redactEvent(targetRoomId, targetEvent['event_id']);
await c.redactEvent(targetRoomId, targetEvent['event_id']);
} else {
await m.managementRoomOutput.logMessage(LogLevel.WARN, "utils#redactUserMessagesIn", `Tried to redact ${targetEvent['event_id']} in ${targetRoomId} but Mjolnir is running in no-op mode`, targetRoomId);
await mr.logMessage(LogLevel.WARN, "utils#redactUserMessagesIn", `Tried to redact ${targetEvent['event_id']} in ${targetRoomId} but Mjolnir is running in no-op mode`, targetRoomId);
}
}
});
} catch (error) {
await m.managementRoomOutput.logMessage(LogLevel.ERROR, "utils#redactUserMessagesIn", `Caught an error while trying to redact messages for ${userIdOrGlob} in ${targetRoomId}: ${error}`, targetRoomId);
await mr.logMessage(LogLevel.ERROR, "utils#redactUserMessagesIn", `Caught an error while trying to redact messages for ${userIdOrGlob} in ${targetRoomId}: ${error}`, targetRoomId);
}
}
}

// if admin use the Admin API, but admin endpoint does not support globs
if (isAdmin && !usingGlob) {
try {
await adminRedaction(mjolnir, userIdOrGlob, targetRoomIds, limit)
await adminRedaction(client, managementRoom, userIdOrGlob, targetRoomIds, limit)
} catch (e) {
LogService.error("utils#redactUserMessagesIn", `Error using admin API to redact messages: ${extractRequestError(e)}`);
await mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "utils#redactUserMessagesIn", `Error using admin API to redact messages for user ${userIdOrGlob}, please check logs for more info - falling
await managementRoom.logMessage(LogLevel.ERROR, "utils#redactUserMessagesIn", `Error using admin API to redact messages for user ${userIdOrGlob}, please check logs for more info - falling
back to non-admin redaction process.`);
await redaction(mjolnir, userIdOrGlob, targetRoomIds, limit);
await redaction(client, managementRoom, userIdOrGlob, targetRoomIds, limit);
}
} else {
await redaction(mjolnir, userIdOrGlob, targetRoomIds, limit);
await redaction(client, managementRoom, userIdOrGlob, targetRoomIds, limit);
}
}

Expand Down

0 comments on commit 0d5f6d3

Please sign in to comment.