mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-06-28 07:32:30 +00:00
Support automatically redacting users for certain ban reasons
This commit is contained in:
parent
6753e7f780
commit
959162c4a3
|
@ -57,6 +57,14 @@ noop: false
|
|||
# server struggles with /state requests then set this to true.
|
||||
fasterMembershipChecks: false
|
||||
|
||||
# A case-insensitive list of ban reasons to automatically redact a user's
|
||||
# messages for. Typically this is useful to avoid having to type two commands
|
||||
# to the bot. Use asterisks to represent globs (ie: "spam*testing" would match
|
||||
# "spam for testing" as well as "spamtesting").
|
||||
automaticallyRedactForReasons:
|
||||
- "spam"
|
||||
- "advertising"
|
||||
|
||||
# A list of rooms to protect (matrix.to URLs)
|
||||
protectedRooms:
|
||||
- "https://matrix.to/#/#yourroom:example.org"
|
||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { LogLevel, LogService, MatrixClient, Permalinks } from "matrix-bot-sdk";
|
||||
import { LogLevel, LogService, MatrixClient, MatrixGlob, Permalinks } from "matrix-bot-sdk";
|
||||
import BanList, { ALL_RULE_TYPES } from "./models/BanList";
|
||||
import { applyServerAcls } from "./actions/ApplyAcl";
|
||||
import { RoomUpdateError } from "./models/RoomUpdateError";
|
||||
|
@ -42,12 +42,17 @@ export class Mjolnir {
|
|||
private currentState: string = STATE_NOT_STARTED;
|
||||
private protections: IProtection[] = [];
|
||||
private redactionQueue = new AutomaticRedactionQueue();
|
||||
private automaticRedactionReasons: MatrixGlob[] = [];
|
||||
|
||||
constructor(
|
||||
public readonly client: MatrixClient,
|
||||
public readonly protectedRooms: { [roomId: string]: string },
|
||||
private banLists: BanList[],
|
||||
) {
|
||||
for (const reason of config.automaticallyRedactForReasons) {
|
||||
this.automaticRedactionReasons.push(new MatrixGlob(reason.toLowerCase()));
|
||||
}
|
||||
|
||||
client.on("room.event", this.handleEvent.bind(this));
|
||||
|
||||
client.on("room.message", async (roomId, event) => {
|
||||
|
@ -95,6 +100,10 @@ export class Mjolnir {
|
|||
return this.redactionQueue;
|
||||
}
|
||||
|
||||
public get automaticRedactGlobs(): MatrixGlob[] {
|
||||
return this.automaticRedactionReasons;
|
||||
}
|
||||
|
||||
public start() {
|
||||
return this.client.start().then(async () => {
|
||||
this.currentState = STATE_CHECKING_PERMISSIONS;
|
||||
|
|
|
@ -21,6 +21,7 @@ import config from "../config";
|
|||
import { logMessage } from "../LogProxy";
|
||||
import { LogLevel } from "matrix-bot-sdk";
|
||||
import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache";
|
||||
import { redactUserMessagesIn } from "../utils";
|
||||
|
||||
/**
|
||||
* Applies the member bans represented by the ban lists to the provided rooms, returning the
|
||||
|
@ -67,6 +68,11 @@ export async function applyUserBans(lists: BanList[], roomIds: string[], mjolnir
|
|||
await logMessage(LogLevel.DEBUG, "ApplyBan", `Banning ${member.userId} in ${roomId} for: ${userRule.reason}`);
|
||||
|
||||
if (!config.noop) {
|
||||
// Always prioritize redactions above bans
|
||||
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`);
|
||||
|
|
|
@ -15,10 +15,7 @@ limitations under the License.
|
|||
*/
|
||||
|
||||
import { Mjolnir } from "../Mjolnir";
|
||||
import { getMessagesByUserSinceLastJoin } from "../utils";
|
||||
import config from "../config";
|
||||
import { logMessage } from "../LogProxy";
|
||||
import { LogLevel } from "matrix-bot-sdk";
|
||||
import { redactUserMessagesIn } from "../utils";
|
||||
|
||||
// !mjolnir redact <user ID> [room alias]
|
||||
export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
|
@ -29,19 +26,7 @@ export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjo
|
|||
}
|
||||
|
||||
const targetRoomIds = roomAlias ? [roomAlias] : Object.keys(mjolnir.protectedRooms);
|
||||
for (const targetRoomId of targetRoomIds) {
|
||||
await logMessage(LogLevel.DEBUG, "RedactCommand", `Fetching sent messages for ${userId} in ${targetRoomId} to redact...`);
|
||||
|
||||
const eventsToRedact = await getMessagesByUserSinceLastJoin(mjolnir.client, userId, targetRoomId);
|
||||
for (const victimEvent of eventsToRedact) {
|
||||
await logMessage(LogLevel.DEBUG, "RedactCommand", `Redacting ${victimEvent['event_id']} in ${targetRoomId}`);
|
||||
if (!config.noop) {
|
||||
await mjolnir.client.redactEvent(targetRoomId, victimEvent['event_id']);
|
||||
} else {
|
||||
await logMessage(LogLevel.WARN, "RedactCommand", `Tried to redact ${victimEvent['event_id']} in ${targetRoomId} but Mjolnir is running in no-op mode`);
|
||||
}
|
||||
}
|
||||
}
|
||||
await redactUserMessagesIn(mjolnir.client, userId, targetRoomIds);
|
||||
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ interface IConfig {
|
|||
noop: boolean;
|
||||
protectedRooms: string[]; // matrix.to urls
|
||||
fasterMembershipChecks: boolean;
|
||||
automaticallyRedactForReasons: string[]; // case-insensitive globs
|
||||
|
||||
/**
|
||||
* Config options only set at runtime. Try to avoid using the objects
|
||||
|
|
20
src/utils.ts
20
src/utils.ts
|
@ -14,7 +14,9 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { LogService, MatrixClient, MatrixGlob } from "matrix-bot-sdk";
|
||||
import { LogLevel, LogService, MatrixClient, MatrixGlob } from "matrix-bot-sdk";
|
||||
import { logMessage } from "./LogProxy";
|
||||
import config from "./config";
|
||||
|
||||
export function setToArray<T>(set: Set<T>): T[] {
|
||||
const arr: T[] = [];
|
||||
|
@ -35,6 +37,22 @@ export function isTrueJoinEvent(event: any): boolean {
|
|||
return membership === 'join' && prevMembership !== "join";
|
||||
}
|
||||
|
||||
export async function redactUserMessagesIn(client: MatrixClient, userIdOrGlob: string, targetRoomIds: string[]) {
|
||||
for (const targetRoomId of targetRoomIds) {
|
||||
await logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Fetching sent messages for ${userIdOrGlob} in ${targetRoomId} to redact...`);
|
||||
|
||||
const eventsToRedact = await getMessagesByUserSinceLastJoin(client, userIdOrGlob, targetRoomId);
|
||||
for (const victimEvent of eventsToRedact) {
|
||||
await logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Redacting ${victimEvent['event_id']} in ${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`);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all the events sent by a user (or users if using wildcards) in a given room ID, since
|
||||
* the time they joined.
|
||||
|
|
Loading…
Reference in New Issue
Block a user