mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-06-30 16:41:29 +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.
|
# server struggles with /state requests then set this to true.
|
||||||
fasterMembershipChecks: false
|
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)
|
# A list of rooms to protect (matrix.to URLs)
|
||||||
protectedRooms:
|
protectedRooms:
|
||||||
- "https://matrix.to/#/#yourroom:example.org"
|
- "https://matrix.to/#/#yourroom:example.org"
|
||||||
|
|
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
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 BanList, { ALL_RULE_TYPES } from "./models/BanList";
|
||||||
import { applyServerAcls } from "./actions/ApplyAcl";
|
import { applyServerAcls } from "./actions/ApplyAcl";
|
||||||
import { RoomUpdateError } from "./models/RoomUpdateError";
|
import { RoomUpdateError } from "./models/RoomUpdateError";
|
||||||
|
@ -42,12 +42,17 @@ export class Mjolnir {
|
||||||
private currentState: string = STATE_NOT_STARTED;
|
private currentState: string = STATE_NOT_STARTED;
|
||||||
private protections: IProtection[] = [];
|
private protections: IProtection[] = [];
|
||||||
private redactionQueue = new AutomaticRedactionQueue();
|
private redactionQueue = new AutomaticRedactionQueue();
|
||||||
|
private automaticRedactionReasons: MatrixGlob[] = [];
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
public readonly client: MatrixClient,
|
public readonly client: MatrixClient,
|
||||||
public readonly protectedRooms: { [roomId: string]: string },
|
public readonly protectedRooms: { [roomId: string]: string },
|
||||||
private banLists: BanList[],
|
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.event", this.handleEvent.bind(this));
|
||||||
|
|
||||||
client.on("room.message", async (roomId, event) => {
|
client.on("room.message", async (roomId, event) => {
|
||||||
|
@ -95,6 +100,10 @@ export class Mjolnir {
|
||||||
return this.redactionQueue;
|
return this.redactionQueue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get automaticRedactGlobs(): MatrixGlob[] {
|
||||||
|
return this.automaticRedactionReasons;
|
||||||
|
}
|
||||||
|
|
||||||
public start() {
|
public start() {
|
||||||
return this.client.start().then(async () => {
|
return this.client.start().then(async () => {
|
||||||
this.currentState = STATE_CHECKING_PERMISSIONS;
|
this.currentState = STATE_CHECKING_PERMISSIONS;
|
||||||
|
|
|
@ -21,6 +21,7 @@ import config from "../config";
|
||||||
import { logMessage } from "../LogProxy";
|
import { logMessage } from "../LogProxy";
|
||||||
import { LogLevel } from "matrix-bot-sdk";
|
import { LogLevel } from "matrix-bot-sdk";
|
||||||
import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache";
|
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
|
* 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}`);
|
await logMessage(LogLevel.DEBUG, "ApplyBan", `Banning ${member.userId} in ${roomId} for: ${userRule.reason}`);
|
||||||
|
|
||||||
if (!config.noop) {
|
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);
|
await mjolnir.client.banUser(member.userId, roomId, userRule.reason);
|
||||||
} else {
|
} else {
|
||||||
await logMessage(LogLevel.WARN, "ApplyBan", `Tried to ban ${member.userId} in ${roomId} but Mjolnir is running in no-op mode`);
|
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 { Mjolnir } from "../Mjolnir";
|
||||||
import { getMessagesByUserSinceLastJoin } from "../utils";
|
import { redactUserMessagesIn } from "../utils";
|
||||||
import config from "../config";
|
|
||||||
import { logMessage } from "../LogProxy";
|
|
||||||
import { LogLevel } from "matrix-bot-sdk";
|
|
||||||
|
|
||||||
// !mjolnir redact <user ID> [room alias]
|
// !mjolnir redact <user ID> [room alias]
|
||||||
export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
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);
|
const targetRoomIds = roomAlias ? [roomAlias] : Object.keys(mjolnir.protectedRooms);
|
||||||
for (const targetRoomId of targetRoomIds) {
|
await redactUserMessagesIn(mjolnir.client, userId, 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 mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,6 +35,7 @@ interface IConfig {
|
||||||
noop: boolean;
|
noop: boolean;
|
||||||
protectedRooms: string[]; // matrix.to urls
|
protectedRooms: string[]; // matrix.to urls
|
||||||
fasterMembershipChecks: boolean;
|
fasterMembershipChecks: boolean;
|
||||||
|
automaticallyRedactForReasons: string[]; // case-insensitive globs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Config options only set at runtime. Try to avoid using the objects
|
* 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.
|
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[] {
|
export function setToArray<T>(set: Set<T>): T[] {
|
||||||
const arr: T[] = [];
|
const arr: T[] = [];
|
||||||
|
@ -35,6 +37,22 @@ export function isTrueJoinEvent(event: any): boolean {
|
||||||
return membership === 'join' && prevMembership !== "join";
|
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
|
* Gets all the events sent by a user (or users if using wildcards) in a given room ID, since
|
||||||
* the time they joined.
|
* the time they joined.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user