Skip to content

Commit

Permalink
Use spoilers when mentioning targets of a rule (#559)
Browse files Browse the repository at this point in the history
* make managment room id public so it can be used to send messages

* use spoilers when mentioning targets of a rule

* html escapse targets

* lint
  • Loading branch information
H-Shay authored Nov 22, 2024
1 parent 1cea815 commit f2ca79c
Show file tree
Hide file tree
Showing 7 changed files with 57 additions and 51 deletions.
2 changes: 1 addition & 1 deletion src/ManagementRoomOutput.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const levelToFn = {
*/
export default class ManagementRoomOutput {
constructor(
private readonly managementRoomId: string,
public readonly managementRoomId: string,
private readonly client: MatrixSendClient,
private readonly config: IConfig,
) {}
Expand Down
27 changes: 13 additions & 14 deletions src/ProtectedRoomsSet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -362,13 +362,12 @@ export class ProtectedRoomsSet {
// ignore - assume no ACL
}

// We specifically use sendNotice to avoid having to escape HTML
await this.managementRoomOutput.logMessage(
LogLevel.DEBUG,
"ApplyAcl",
`Applying ACL in ${roomId}`,
roomId,
);
await this.client.sendMessage(this.managementRoomId, {
msgtype: "m.text",
body: `Applying ACL in ${roomId}.`,
format: "org.matrix.custom.html",
formatted_body: `Applying ACL in <span data-mx-spoiler>${htmlEscape(roomId)}</span>.`,
});

if (!this.config.noop) {
await this.client.sendStateEvent(roomId, "m.room.server_acl", "", finalAcl);
Expand Down Expand Up @@ -439,13 +438,13 @@ export class ProtectedRoomsSet {
const memberAccess = this.accessControlUnit.getAccessForUser(member.userId, "IGNORE_SERVER");
if (memberAccess.outcome === Access.Banned) {
const reason = memberAccess.rule ? memberAccess.rule.reason : "<no reason supplied>";
// We specifically use sendNotice to avoid having to escape HTML
await this.managementRoomOutput.logMessage(
LogLevel.INFO,
"ApplyBan",
`Banning ${member.userId} in ${roomId} for: ${reason}`,
roomId,
);

await this.client.sendMessage(this.managementRoomId, {
msgtype: "m.text",
body: `Banning ${member.userId} in ${roomId} for: ${reason}.`,
format: "org.matrix.custom.html",
formatted_body: `Banning <span data-mx-spoiler>${htmlEscape(member.userId)}</span> in ${roomId} for: ${reason}.`,
});

if (!this.config.noop) {
if (this.moderators.checkMembership(member.userId)) {
Expand Down
24 changes: 13 additions & 11 deletions src/commands/KickCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

import { Mjolnir } from "../Mjolnir";
import { LogLevel, MatrixGlob, RichReply } from "@vector-im/matrix-bot-sdk";
import { htmlEscape } from "../utils";

// !mjolnir kick <user|filter> [room] [reason]
export async function execKickCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
Expand Down Expand Up @@ -57,24 +58,25 @@ export async function execKickCommand(roomId: string, event: any, mjolnir: Mjoln
const target = member.membershipFor;

if (kickRule.test(target)) {
await mjolnir.managementRoomOutput.logMessage(
LogLevel.DEBUG,
"KickCommand",
`Removing ${target} in ${protectedRoomId}`,
protectedRoomId,
);
await mjolnir.client.sendMessage(mjolnir.managementRoomId, {
msgtype: "m.text",
body: `Removing ${target} in ${protectedRoomId}.`,
format: "org.matrix.custom.html",
formatted_body: `Removing <span data-mx-spoiler>${htmlEscape(target)}</span> in ${protectedRoomId}.`,
});

if (!mjolnir.config.noop) {
try {
await mjolnir.taskQueue.push(async () => {
return mjolnir.client.kickUser(target, protectedRoomId, reason);
});
} catch (e) {
await mjolnir.managementRoomOutput.logMessage(
LogLevel.WARN,
"KickCommand",
`An error happened while trying to kick ${target}: ${e}`,
);
await mjolnir.client.sendMessage(mjolnir.managementRoomId, {
msgtype: "m.text",
body: `An error happened while trying to kick ${target}: ${e}`,
format: "org.matrix.custom.html",
formatted_body: `An error happened while trying to kick <span data-mx-spoiler>${htmlEscape(target)}</span>: ${e}.`,
});
}
} else {
await mjolnir.managementRoomOutput.logMessage(
Expand Down
4 changes: 3 additions & 1 deletion src/commands/SuspendCommand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ limitations under the License.

import { Mjolnir } from "../Mjolnir";
import { RichReply } from "@vector-im/matrix-bot-sdk";
import { htmlEscape } from "../utils";

export async function execSuspendCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const target = parts[2];
Expand All @@ -31,7 +32,8 @@ export async function execSuspendCommand(roomId: string, event: any, mjolnir: Mj

await mjolnir.suspendSynapseUser(target);
const msg = `User ${target} has been suspended.`;
const confirmation = RichReply.createFor(roomId, event, msg, msg);
const htmlMsg = `User <span data-mx-spoiler>${htmlEscape(target)}</span> has been suspended.`;
const confirmation = RichReply.createFor(roomId, event, msg, htmlMsg);
confirmation["msgtype"] = "m.notice";
await mjolnir.client.sendMessage(roomId, confirmation);
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event["event_id"], "✅");
Expand Down
13 changes: 7 additions & 6 deletions src/protections/BasicFlooding.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import { Protection } from "./IProtection";
import { NumberProtectionSetting } from "./ProtectionSettings";
import { Mjolnir } from "../Mjolnir";
import { LogLevel, LogService } from "@vector-im/matrix-bot-sdk";
import { htmlEscape } from "../utils";

// if this is exceeded, we'll ban the user for spam and redact their messages
export const DEFAULT_MAX_PER_MINUTE = 10;
Expand Down Expand Up @@ -68,12 +69,12 @@ export class BasicFlooding extends Protection {
}

if (messageCount >= this.settings.maxPerMinute.value) {
await mjolnir.managementRoomOutput.logMessage(
LogLevel.WARN,
"BasicFlooding",
`Banning ${event["sender"]} in ${roomId} for flooding (${messageCount} messages in the last minute)`,
roomId,
);
await mjolnir.client.sendMessage(mjolnir.managementRoomId, {
msgtype: "m.text",
body: `Banning ${event["sender"]} in ${roomId} for flooding (${messageCount} messages in the last minute)`,
format: "org.matrix.custom.html",
formatted_body: `Banning <span data-mx-spoiler>${htmlEscape(event["sender"])}</span> in ${roomId} for flooding (${messageCount} messages in the last minute).`,
});
if (!mjolnir.config.noop) {
if (mjolnir.moderators.checkMembership(event["sender"])) {
mjolnir.managementRoomOutput.logMessage(
Expand Down
13 changes: 7 additions & 6 deletions src/protections/FirstMessageIsImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ limitations under the License.
import { Protection } from "./IProtection";
import { Mjolnir } from "../Mjolnir";
import { LogLevel, LogService } from "@vector-im/matrix-bot-sdk";
import { isTrueJoinEvent } from "../utils";
import { htmlEscape, isTrueJoinEvent } from "../utils";

export class FirstMessageIsImage extends Protection {
private justJoined: { [roomId: string]: string[] } = {};
Expand Down Expand Up @@ -58,11 +58,12 @@ export class FirstMessageIsImage extends Protection {
const isMedia =
msgtype === "m.image" || msgtype === "m.video" || formattedBody.toLowerCase().includes("<img");
if (isMedia && this.justJoined[roomId].includes(event["sender"])) {
await mjolnir.managementRoomOutput.logMessage(
LogLevel.WARN,
"FirstMessageIsImage",
`Banning ${event["sender"]} for posting an image as the first thing after joining in ${roomId}.`,
);
await mjolnir.client.sendMessage(mjolnir.managementRoomId, {
msgtype: "m.text",
body: `Banning ${event["sender"]} for posting an image as the first thing after joining in ${roomId}.`,
format: "org.matrix.custom.html",
formatted_body: `Banning <span data-mx-spoiler>${htmlEscape(event["sender"])}</span> for posting an image as the first thing after joining in ${roomId}.`,
});
if (!mjolnir.config.noop) {
if (mjolnir.moderators.checkMembership(event["sender"])) {
await mjolnir.managementRoomOutput.logMessage(
Expand Down
25 changes: 13 additions & 12 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -130,12 +130,12 @@ async function botRedactUserMessagesIn(
}
});
} catch (error) {
await managementRoom.logMessage(
LogLevel.ERROR,
"utils#redactUserMessagesIn",
`Caught an error while trying to redact messages for ${userIdOrGlob} in ${targetRoomId}: ${error}`,
targetRoomId,
);
await client.sendMessage(managementRoom.managementRoomId, {
msgtype: "m.text",
body: `Caught an error while trying to redact messages for ${userIdOrGlob} in ${targetRoomId}: ${error}`,
format: "org.matrix.custom.html",
formatted_body: `Caught an error while trying to redact messages for <span data-mx-spoiler>${htmlEscape(userIdOrGlob)}</span> in ${targetRoomId}: ${error}`,
});
}
}
}
Expand Down Expand Up @@ -215,12 +215,13 @@ export async function redactUserMessagesIn(
"utils#redactUserMessagesIn",
`Error using admin API to redact messages: ${extractRequestError(e)}`,
);
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 client.sendMessage(managementRoom.managementRoomId, {
msgtype: "m.text",
body: `Error using admin API to redact messages for user ${userIdOrGlob}, please check logs for more info - falling back to non-admin redaction process.`,
format: "org.matrix.custom.html",
formatted_body: `Error using admin API to redact messages for user <span data-mx-spoiler>${htmlEscape(userIdOrGlob)}</span>, please check logs for more info - falling
back to non-admin redaction process.`,
});
await botRedactUserMessagesIn(client, managementRoom, userIdOrGlob, filteredRooms, limit, noop);
}
} else {
Expand Down

0 comments on commit f2ca79c

Please sign in to comment.