diff --git a/src/actions/ApplyBan.ts b/src/actions/ApplyBan.ts
index 28d26594..efdf343b 100644
--- a/src/actions/ApplyBan.ts
+++ b/src/actions/ApplyBan.ts
@@ -68,12 +68,10 @@ export async function applyUserBans(lists: BanList[], roomIds: string[], mjolnir
await logMessage(LogLevel.INFO, "ApplyBan", `Banning ${member.userId} in ${roomId} for: ${userRule.reason}`, roomId);
if (!config.noop) {
- // Always prioritize redactions above bans
+ await mjolnir.client.banUser(member.userId, roomId, userRule.reason);
if (mjolnir.automaticRedactGlobs.find(g => g.test(userRule.reason.toLowerCase()))) {
await redactUserMessagesIn(mjolnir.client, member.userId, [roomId]);
}
-
- await mjolnir.client.banUser(member.userId, roomId, userRule.reason);
} else {
await logMessage(LogLevel.WARN, "ApplyBan", `Tried to ban ${member.userId} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
}
diff --git a/src/protections/BasicFlooding.ts b/src/protections/BasicFlooding.ts
index 7012b707..92d6a86c 100644
--- a/src/protections/BasicFlooding.ts
+++ b/src/protections/BasicFlooding.ts
@@ -57,7 +57,12 @@ export class BasicFlooding implements IProtection {
}
if (messageCount >= MAX_PER_MINUTE) {
- // Prioritize redaction over ban - we can always keep redacting what the user said.
+ await logMessage(LogLevel.WARN, "BasicFlooding", `Banning ${event['sender']} in ${roomId} for flooding (${messageCount} messages in the last minute)`, roomId);
+ if (!config.noop) {
+ await mjolnir.client.banUser(event['sender'], roomId, "spam");
+ } else {
+ await logMessage(LogLevel.WARN, "BasicFlooding", `Tried to ban ${event['sender']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
+ }
if (this.recentlyBanned.includes(event['sender'])) return; // already handled (will be redacted)
mjolnir.redactionHandler.addUser(event['sender']);
@@ -72,13 +77,6 @@ export class BasicFlooding implements IProtection {
await logMessage(LogLevel.WARN, "BasicFlooding", `Tried to redact messages for ${event['sender']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
}
- await logMessage(LogLevel.WARN, "BasicFlooding", `Banning ${event['sender']} in ${roomId} for flooding (${messageCount} messages in the last minute)`, roomId);
- if (!config.noop) {
- await mjolnir.client.banUser(event['sender'], roomId, "spam");
- } else {
- await logMessage(LogLevel.WARN, "BasicFlooding", `Tried to ban ${event['sender']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
- }
-
// Free up some memory now that we're ready to handle it elsewhere
forUser = forRoom[event['sender']] = []; // reset the user's list
}
diff --git a/src/protections/FirstMessageIsImage.ts b/src/protections/FirstMessageIsImage.ts
index 7a381fdb..c42a63cc 100644
--- a/src/protections/FirstMessageIsImage.ts
+++ b/src/protections/FirstMessageIsImage.ts
@@ -51,7 +51,12 @@ export class FirstMessageIsImage implements IProtection {
const formattedBody = content['formatted_body'] || '';
const isMedia = msgtype === 'm.image' || msgtype === 'm.video' || formattedBody.toLowerCase().includes('
{
+ for (const victimEvent of eventsToRedact) {
+ await logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Redacting ${victimEvent['event_id']} in ${targetRoomId}`, targetRoomId);
+ if (!config.noop) {
+ await client.redactEvent(targetRoomId, victimEvent['event_id']);
+ } else {
+ await logMessage(LogLevel.WARN, "utils#redactUserMessagesIn", `Tried to redact ${victimEvent['event_id']} in ${targetRoomId} but Mjolnir is running in no-op mode`, targetRoomId);
+ }
}
- }
+ });
}
}
@@ -70,9 +71,10 @@ export async function redactUserMessagesIn(client: MatrixClient, userIdOrGlob: s
* @param {string} sender The sender. Can include wildcards to match multiple people.
* @param {string} roomId The room ID to search in.
* @param {number} limit The maximum number of messages to search. Defaults to 1000.
- * @returns {Promise} Resolves to the events sent by the user(s) prior to join.
+ * @param {function} cb Callback function to handle the events as they are received.
+ * @returns {Promise} Resolves when complete.
*/
-export async function getMessagesByUserIn(client: MatrixClient, sender: string, roomId: string, limit: number): Promise {
+export async function getMessagesByUserIn(client: MatrixClient, sender: string, roomId: string, limit: number, cb: (events: any[]) => void): Promise {
const filter = {
room: {
rooms: [roomId],
@@ -140,7 +142,6 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string,
const response = await initialSync();
if (!response) return [];
- const messages = [];
let processed = 0;
const timeline = (((response['rooms'] || {})['join'] || {})[roomId] || {})['timeline'] || {};
@@ -148,8 +149,9 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string,
let token = timeline['prev_batch'] || response['next_batch'];
let bfMessages = {chunk: syncedMessages, end: token};
do {
+ const messages = [];
for (const event of (bfMessages['chunk'] || [])) {
- if (processed >= limit) return messages; // we're done even if we don't want to be
+ if (processed >= limit) return; // we're done even if we don't want to be
processed++;
if (testUser(event['sender'])) messages.push(event);
@@ -161,12 +163,13 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string,
token = bfMessages['end'];
if (lastToken === token) {
LogService.warn("utils", "Backfill returned same end token - returning");
- return messages;
+ cb(messages);
+ return;
}
}
- } while (token);
- return messages;
+ cb(messages);
+ } while (token);
}
export async function replaceRoomIdsWithPills(client: MatrixClient, text: string, roomIds: string[] | string, msgtype: MessageType = "m.text"): Promise {