From 11ab4cb660ad88d842aa91b276205bfba2d4747f Mon Sep 17 00:00:00 2001 From: Martin Weinelt Date: Tue, 17 Dec 2024 23:20:49 +0100 Subject: [PATCH] mjolnir: 1.8.3 -> 1.9.1 https://github.com/matrix-org/mjolnir/releases/tag/v1.9.0 https://github.com/matrix-org/mjolnir/releases/tag/v1.9.1 --- .../mjolnir/001-disable-nsfwprotection.patch | 155 ++++++++++-------- pkgs/by-name/mj/mjolnir/package.json | 8 +- pkgs/by-name/mj/mjolnir/package.nix | 6 +- 3 files changed, 98 insertions(+), 71 deletions(-) diff --git a/pkgs/by-name/mj/mjolnir/001-disable-nsfwprotection.patch b/pkgs/by-name/mj/mjolnir/001-disable-nsfwprotection.patch index ceeaa90f6351..2566f65b1d1b 100644 --- a/pkgs/by-name/mj/mjolnir/001-disable-nsfwprotection.patch +++ b/pkgs/by-name/mj/mjolnir/001-disable-nsfwprotection.patch @@ -1,9 +1,9 @@ diff --git a/src/protections/NsfwProtection.ts b/src/protections/NsfwProtection.ts deleted file mode 100644 -index 8b6f8fd..0000000 +index a6f45b2..0000000 --- a/src/protections/NsfwProtection.ts +++ /dev/null -@@ -1,99 +0,0 @@ +@@ -1,115 +0,0 @@ -/* -Copyright 2024 The Matrix.org Foundation C.I.C. - @@ -22,10 +22,9 @@ index 8b6f8fd..0000000 - -import { Protection } from "./IProtection"; -import { Mjolnir } from "../Mjolnir"; --import * as nsfw from 'nsfwjs'; --import {LogLevel} from "@vector-im/matrix-bot-sdk"; --import { node } from '@tensorflow/tfjs-node'; -- +-import * as nsfw from "nsfwjs"; +-import { LogLevel, LogService } from "@vector-im/matrix-bot-sdk"; +-import { node } from "@tensorflow/tfjs-node"; - -export class NsfwProtection extends Protection { - settings = {}; @@ -41,37 +40,50 @@ index 8b6f8fd..0000000 - } - - public get name(): string { -- return 'NsfwProtection'; +- return "NsfwProtection"; - } - - public get description(): string { -- return "Scans all images sent into a protected room to determine if the image is " + -- "NSFW. If it is, the image will automatically be redacted."; +- return ( +- "Scans all images sent into a protected room to determine if the image is " + +- "NSFW. If it is, the image will automatically be redacted." +- ); - } - - public async handleEvent(mjolnir: Mjolnir, roomId: string, event: any): Promise { -- if (event['type'] === 'm.room.message') { -- let content = JSON.stringify(event['content']); +- if (event["type"] === "m.room.message") { +- let content = JSON.stringify(event["content"]); - if (!content.toLowerCase().includes("mxc")) { - return; -- } +- } - // try and grab a human-readable alias for more helpful management room output -- const maybeAlias = await mjolnir.client.getPublishedAlias(roomId) -- const room = maybeAlias ? maybeAlias : roomId +- const maybeAlias = await mjolnir.client.getPublishedAlias(roomId); +- const room = maybeAlias ? maybeAlias : roomId; - - const mxcs = content.match(/(mxc?:\/\/[^\s'"]+)/gim); - if (!mxcs) { - //something's gone wrong with the regex -- await mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "NSFWProtection", `Unable to find any mxcs in ${event["event_id"]} in ${room}`); +- await mjolnir.managementRoomOutput.logMessage( +- LogLevel.ERROR, +- "NSFWProtection", +- `Unable to find any mxcs in ${event["event_id"]} in ${room}`, +- ); - return; - } - - // @ts-ignore - see null check immediately above - for (const mxc of mxcs) { - const image = await mjolnir.client.downloadContent(mxc); -- const decodedImage = await node.decodeImage(image.data, 3); -- const predictions = await this.model.classify(decodedImage); - +- let decodedImage; +- try { +- decodedImage = await node.decodeImage(image.data, 3); +- } catch (e) { +- LogService.error("NsfwProtection", `There was an error processing an image: ${e}`); +- continue; +- } +- +- const predictions = await this.model.classify(decodedImage); - - for (const prediction of predictions) { - if (["Hentai", "Porn"].includes(prediction["className"])) { @@ -79,22 +91,26 @@ index 8b6f8fd..0000000 - try { - await mjolnir.client.redactEvent(roomId, event["event_id"]); - } catch (err) { -- await mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "NSFWProtection", `There was an error redacting ${event["event_id"]} in ${room}: ${err}`); +- await mjolnir.managementRoomOutput.logMessage( +- LogLevel.ERROR, +- "NSFWProtection", +- `There was an error redacting ${event["event_id"]} in ${room}: ${err}`, +- ); - } -- let eventId = event["event_id"] -- let body = `Redacted an image in ${room} ${eventId}` +- let eventId = event["event_id"]; +- let body = `Redacted an image in ${room} ${eventId}`; - let formatted_body = `
- Redacted an image in ${room} --
${eventId}
${room}
--                                                  
` +-
${eventId}
${room}
+- `; - const msg = { - msgtype: "m.notice", - body: body, - format: "org.matrix.custom.html", -- formatted_body: formatted_body +- formatted_body: formatted_body, - }; - await mjolnir.client.sendMessage(mjolnir.managementRoomId, msg); -- break +- break; - } - } - } @@ -103,16 +119,15 @@ index 8b6f8fd..0000000 - } - } -} -\ No newline at end of file diff --git a/src/protections/ProtectionManager.ts b/src/protections/ProtectionManager.ts -index 9b84318..67f10dc 100644 +index 485f05e..6ffb0d1 100644 --- a/src/protections/ProtectionManager.ts +++ b/src/protections/ProtectionManager.ts @@ -31,7 +31,6 @@ import { htmlEscape } from "../utils"; import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache"; import { RoomUpdateError } from "../models/RoomUpdateError"; import { LocalAbuseReports } from "./LocalAbuseReports"; --import {NsfwProtection} from "./NsfwProtection"; +-import { NsfwProtection } from "./NsfwProtection"; import { MentionSpam } from "./MentionSpam"; const PROTECTIONS: Protection[] = [ @@ -121,10 +136,10 @@ index 9b84318..67f10dc 100644 new JoinWaveShortCircuit(), new LocalAbuseReports(), - new NsfwProtection(), - new MentionSpam() + new MentionSpam(), ]; -@@ -104,9 +102,6 @@ export class ProtectionManager { +@@ -106,9 +104,6 @@ export class ProtectionManager { protection.settings[key].setValue(value); } if (protection.enabled) { @@ -136,49 +151,54 @@ index 9b84318..67f10dc 100644 } diff --git a/test/integration/nsfwProtectionTest.ts b/test/integration/nsfwProtectionTest.ts deleted file mode 100644 -index c86fd38..0000000 +index ed215e0..0000000 --- a/test/integration/nsfwProtectionTest.ts +++ /dev/null -@@ -1,78 +0,0 @@ --import {newTestUser} from "./clientHelper"; +@@ -1,89 +0,0 @@ +-import { newTestUser } from "./clientHelper"; - --import {MatrixClient} from "@vector-im/matrix-bot-sdk"; --import {getFirstReaction} from "./commands/commandUtils"; --import {strict as assert} from "assert"; --import { readFileSync } from 'fs'; +-import { MatrixClient } from "@vector-im/matrix-bot-sdk"; +-import { getFirstReaction } from "./commands/commandUtils"; +-import { strict as assert } from "assert"; +-import { readFileSync } from "fs"; - -describe("Test: NSFW protection", function () { - let client: MatrixClient; - let room: string; - this.beforeEach(async function () { -- client = await newTestUser(this.config.homeserverUrl, {name: {contains: "nsfw-protection"}}); +- client = await newTestUser(this.config.homeserverUrl, { name: { contains: "nsfw-protection" } }); - await client.start(); - const mjolnirId = await this.mjolnir.client.getUserId(); - room = await client.createRoom({ invite: [mjolnirId] }); - await client.joinRoom(room); - await client.joinRoom(this.config.managementRoom); - await client.setUserPowerLevel(mjolnirId, room, 100); -- }) +- }); - this.afterEach(async function () { - await client.stop(); -- }) +- }); - - function delay(ms: number) { -- return new Promise(resolve => setTimeout(resolve, ms)); +- return new Promise((resolve) => setTimeout(resolve, ms)); - } - -- -- it("Nsfw protection doesn't redact sfw images", async function() { +- it("Nsfw protection doesn't redact sfw images", async function () { - this.timeout(20000); - -- await client.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir rooms add ${room}` }); -- await getFirstReaction(client, this.mjolnir.managementRoomId, '✅', async () => { -- return await client.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir enable NsfwProtection` }); +- await client.sendMessage(this.mjolnir.managementRoomId, { +- msgtype: "m.text", +- body: `!mjolnir rooms add ${room}`, +- }); +- await getFirstReaction(client, this.mjolnir.managementRoomId, "✅", async () => { +- return await client.sendMessage(this.mjolnir.managementRoomId, { +- msgtype: "m.text", +- body: `!mjolnir enable NsfwProtection`, +- }); - }); - -- const data = readFileSync('test_tree.jpg'); -- const mxc = await client.uploadContent(data, 'image/png'); -- let content = {"msgtype": "m.image", "body": "test.jpeg", "url": mxc}; +- const data = readFileSync("test_tree.jpg"); +- const mxc = await client.uploadContent(data, "image/png"); +- let content = { msgtype: "m.image", body: "test.jpeg", url: mxc }; - let imageMessage = await client.sendMessage(room, content); - - await delay(500); @@ -186,36 +206,41 @@ index c86fd38..0000000 - assert.equal(Object.keys(processedImage.content).length, 3, "This event should not have been redacted"); - }); - -- it("Nsfw protection redacts nsfw images", async function() { +- it("Nsfw protection redacts nsfw images", async function () { - this.timeout(20000); - // dial the sensitivity on the protection way up so that all images are flagged as NSFW - this.mjolnir.config.nsfwSensitivity = 0.0; - -- await client.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir rooms add ${room}` }); -- await getFirstReaction(client, this.mjolnir.managementRoomId, '✅', async () => { -- return await client.sendMessage(this.mjolnir.managementRoomId, { msgtype: 'm.text', body: `!mjolnir enable NsfwProtection` }); +- await client.sendMessage(this.mjolnir.managementRoomId, { +- msgtype: "m.text", +- body: `!mjolnir rooms add ${room}`, +- }); +- await getFirstReaction(client, this.mjolnir.managementRoomId, "✅", async () => { +- return await client.sendMessage(this.mjolnir.managementRoomId, { +- msgtype: "m.text", +- body: `!mjolnir enable NsfwProtection`, +- }); - }); - -- const data = readFileSync('test_tree.jpg'); -- const mxc = await client.uploadContent(data, 'image/png'); -- let content = {"msgtype": "m.image", "body": "test.jpeg", "url": mxc}; +- const data = readFileSync("test_tree.jpg"); +- const mxc = await client.uploadContent(data, "image/png"); +- let content = { msgtype: "m.image", body: "test.jpeg", url: mxc }; - let imageMessage = await client.sendMessage(room, content); - -- let formatted_body = `` +- let formatted_body = ``; - let htmlContent = { -- msgtype: "m.image", -- body: formatted_body, -- format: "org.matrix.custom.html", -- formatted_body: formatted_body -- }; -- let htmlMessage = await client.sendMessage(room, htmlContent) +- msgtype: "m.image", +- body: formatted_body, +- format: "org.matrix.custom.html", +- formatted_body: formatted_body, +- }; +- let htmlMessage = await client.sendMessage(room, htmlContent); - - await delay(500); - let processedImage = await client.getEvent(room, imageMessage); - assert.equal(Object.keys(processedImage.content).length, 0, "This event should have been redacted"); - -- let processedHtml = await client.getEvent(room, htmlMessage) -- assert.equal(Object.keys(processedHtml.content).length, 0, "This html image event should have been redacted") +- let processedHtml = await client.getEvent(room, htmlMessage); +- assert.equal(Object.keys(processedHtml.content).length, 0, "This html image event should have been redacted"); - }); -}); -\ No newline at end of file diff --git a/pkgs/by-name/mj/mjolnir/package.json b/pkgs/by-name/mj/mjolnir/package.json index fa276e8569a2..d0ffe772a827 100644 --- a/pkgs/by-name/mj/mjolnir/package.json +++ b/pkgs/by-name/mj/mjolnir/package.json @@ -1,6 +1,6 @@ { "name": "mjolnir", - "version": "1.8.3", + "version": "1.9.1", "description": "A moderation tool for Matrix", "main": "lib/index.js", "repository": "git@github.com:matrix-org/mjolnir.git", @@ -10,7 +10,7 @@ "scripts": { "build": "tsc", "postbuild": "rm -rf lib/test/ && cp -r lib/src/* lib/ && rm -rf lib/src/", - "lint": "tslint --project ./tsconfig.json -t stylish", + "lint": "tslint --project ./tsconfig.json -t stylish && npx prettier . --check", "start:dev": "yarn build && node --async-stack-traces lib/index.js", "test": "ts-mocha --project ./tsconfig.json test/commands/**/*.ts", "test:integration": "NODE_ENV=harness ts-mocha --async-stack-traces --require test/integration/fixtures.ts --timeout 300000 --project ./tsconfig.json \"test/integration/**/*Test.ts\"", @@ -58,6 +58,7 @@ "humanize-duration-ts": "^2.1.1", "js-yaml": "^4.1.0", "jsdom": "^16.6.0", + "lru-cache": "^11.0.1", "matrix-appservice-bridge": "10.3.1", "nsfwjs": "^4.1.0", "parse-duration": "^1.0.2", @@ -69,5 +70,6 @@ }, "engines": { "node": ">=20.0.0" - } + }, + "packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e" } diff --git a/pkgs/by-name/mj/mjolnir/package.nix b/pkgs/by-name/mj/mjolnir/package.nix index 098ed9bf9b3a..215675d0f5cb 100644 --- a/pkgs/by-name/mj/mjolnir/package.nix +++ b/pkgs/by-name/mj/mjolnir/package.nix @@ -11,13 +11,13 @@ mkYarnPackage rec { pname = "mjolnir"; - version = "1.8.3"; + version = "1.9.1"; src = fetchFromGitHub { owner = "matrix-org"; repo = "mjolnir"; rev = "refs/tags/v${version}"; - hash = "sha256-yD7QGsS2Em8Z95po9pGRUDmHgHe4z0j0Jnvy3IG7xKY="; + hash = "sha256-LK2CgMLDJHfr1+ejHYeJNw2ekCnUA8GHufZ6vbifzGQ="; }; patches = [ @@ -29,7 +29,7 @@ mkYarnPackage rec { offlineCache = fetchYarnDeps { yarnLock = src + "/yarn.lock"; - hash = "sha256-05DqddK8+136Qq/JGeiITZkVJ8Dw9K9HfACKW86989U="; + hash = "sha256-1V7ooONt9j+4hk/3w6Dsv/SdWwa1xsLk97EwhuPegNo="; }; packageResolutions = {