mjolnir: 1.8.3 -> 1.9.1 (#366017)
This commit is contained in:
@@ -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<any> {
|
||||
- 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 = `<details>
|
||||
- <summary>Redacted an image in ${room}</summary>
|
||||
- <pre>${eventId}</pre> <pre></pre>${room}</pre>
|
||||
- </details>`
|
||||
- <pre>${eventId}</pre> <pre>${room}</pre>
|
||||
- </details>`;
|
||||
- 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 = `<img src=${mxc} />`
|
||||
- let formatted_body = `<img src=${mxc} />`;
|
||||
- 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
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
|
||||
@@ -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 = {
|
||||
|
||||
Reference in New Issue
Block a user