mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-10-01 01:36:06 -04:00
Setting up Decentralized Abuse Reports automatically by default
This commit is contained in:
parent
7b2f60985a
commit
e2725b1bb2
@ -243,8 +243,13 @@ export class Mjolnir {
|
|||||||
this.protectionManager = new ProtectionManager(this);
|
this.protectionManager = new ProtectionManager(this);
|
||||||
|
|
||||||
this.managementRoomOutput = new ManagementRoomOutput(managementRoomId, client, config);
|
this.managementRoomOutput = new ManagementRoomOutput(managementRoomId, client, config);
|
||||||
const protections = new ProtectionManager(this);
|
this.protectedRoomsTracker = new ProtectedRoomsSet(
|
||||||
this.protectedRoomsTracker = new ProtectedRoomsSet(client, clientUserId, managementRoomId, this.managementRoomOutput, protections, config);
|
client,
|
||||||
|
clientUserId,
|
||||||
|
managementRoomId,
|
||||||
|
this.managementRoomOutput,
|
||||||
|
this.protectionManager,
|
||||||
|
config);
|
||||||
}
|
}
|
||||||
|
|
||||||
public get state(): string {
|
public get state(): string {
|
||||||
|
@ -104,12 +104,6 @@ export class ProtectedRoomsSet {
|
|||||||
private readonly clientUserId: string,
|
private readonly clientUserId: string,
|
||||||
private readonly managementRoomId: string,
|
private readonly managementRoomId: string,
|
||||||
private readonly managementRoomOutput: ManagementRoomOutput,
|
private readonly managementRoomOutput: ManagementRoomOutput,
|
||||||
/**
|
|
||||||
* The protection manager is only used to verify the permissions
|
|
||||||
* that the protection manager requires are correct for this set of rooms.
|
|
||||||
* The protection manager is not really compatible with this abstraction yet
|
|
||||||
* because of a direct dependency on the protection manager in Mjolnir commands.
|
|
||||||
*/
|
|
||||||
private readonly protectionManager: ProtectionManager,
|
private readonly protectionManager: ProtectionManager,
|
||||||
private readonly config: IConfig,
|
private readonly config: IConfig,
|
||||||
) {
|
) {
|
||||||
@ -264,11 +258,13 @@ export class ProtectedRoomsSet {
|
|||||||
}
|
}
|
||||||
this.protectedRooms.add(roomId);
|
this.protectedRooms.add(roomId);
|
||||||
this.protectedRoomActivityTracker.addProtectedRoom(roomId);
|
this.protectedRoomActivityTracker.addProtectedRoom(roomId);
|
||||||
|
this.protectionManager.addProtectedRoom(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeProtectedRoom(roomId: string): void {
|
public removeProtectedRoom(roomId: string): void {
|
||||||
this.protectedRoomActivityTracker.removeProtectedRoom(roomId);
|
this.protectedRoomActivityTracker.removeProtectedRoom(roomId);
|
||||||
this.protectedRooms.delete(roomId);
|
this.protectedRooms.delete(roomId);
|
||||||
|
this.protectionManager.removeProtectedRoom(roomId);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,11 +31,26 @@ export abstract class Protection {
|
|||||||
readonly requiredStatePermissions: string[] = [];
|
readonly requiredStatePermissions: string[] = [];
|
||||||
abstract settings: { [setting: string]: AbstractProtectionSetting<any, any> };
|
abstract settings: { [setting: string]: AbstractProtectionSetting<any, any> };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A new room has been added to the list of rooms to protect with this protection.
|
||||||
|
*/
|
||||||
|
async startProtectingRoom(mjolnir: Mjolnir, roomId: string) {
|
||||||
|
// By default, do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A room has been removed from the list of rooms to protect with this protection.
|
||||||
|
*/
|
||||||
|
async stopProtectingRoom(mjolnir: Mjolnir, roomId: string) {
|
||||||
|
// By default, do nothing.
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Handle a single event from a protected room, to decide if we need to
|
* Handle a single event from a protected room, to decide if we need to
|
||||||
* respond to it
|
* respond to it
|
||||||
*/
|
*/
|
||||||
async handleEvent(mjolnir: Mjolnir, roomId: string, event: any): Promise<Consequence[] | any> {
|
async handleEvent(mjolnir: Mjolnir, roomId: string, event: any): Promise<Consequence[] | any> {
|
||||||
|
// By default, do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -43,6 +58,7 @@ export abstract class Protection {
|
|||||||
* need to respond to it
|
* need to respond to it
|
||||||
*/
|
*/
|
||||||
async handleReport(mjolnir: Mjolnir, roomId: string, reporterId: string, event: any, reason?: string): Promise<any> {
|
async handleReport(mjolnir: Mjolnir, roomId: string, reporterId: string, event: any, reason?: string): Promise<any> {
|
||||||
|
// By default, do nothing.
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
98
src/protections/LocalAbuseReports.ts
Normal file
98
src/protections/LocalAbuseReports.ts
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
/*
|
||||||
|
Copyright 2023 Element.
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import { LogLevel } from "matrix-bot-sdk";
|
||||||
|
import { Mjolnir } from "../Mjolnir";
|
||||||
|
import { Protection } from "./IProtection";
|
||||||
|
|
||||||
|
/*
|
||||||
|
An implementation of per decentralized abuse reports, as per
|
||||||
|
https://github.com/Yoric/matrix-doc/blob/aristotle/proposals/3215-towards-decentralized-moderation.md
|
||||||
|
*/
|
||||||
|
|
||||||
|
const EVENT_MODERATED_BY = "org.matrix.msc3215.room.moderation.moderated_by";
|
||||||
|
const EVENT_MODERATOR_OF = "org.matrix.msc3215.room.moderation.moderator_of";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup decentralized abuse reports in protected rooms.
|
||||||
|
*/
|
||||||
|
export class LocalAbuseReports extends Protection {
|
||||||
|
settings: { };
|
||||||
|
public readonly name = "LocalAbuseReports";
|
||||||
|
public readonly description = "Enables MSC3215-compliant web clients to send abuse reports to the moderator instead of the homeserver admin";
|
||||||
|
readonly requiredStatePermissions = [EVENT_MODERATED_BY];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A new room has been added to the list of rooms to protect with this protection.
|
||||||
|
*/
|
||||||
|
async startProtectingRoom(mjolnir: Mjolnir, protectedRoomId: string) {
|
||||||
|
try {
|
||||||
|
const userId = await mjolnir.client.getUserId();
|
||||||
|
|
||||||
|
// Fetch the previous state of the room, to avoid overwriting any existing setup.
|
||||||
|
let previousState: /* previous content */ any | /* there was no previous content */ null;
|
||||||
|
try {
|
||||||
|
previousState = await mjolnir.client.getRoomStateEvent(protectedRoomId, EVENT_MODERATED_BY, EVENT_MODERATED_BY);
|
||||||
|
} catch (ex) {
|
||||||
|
previousState = null;
|
||||||
|
}
|
||||||
|
if (previousState && previousState["room_id"] && previousState["user_id"]) {
|
||||||
|
if (previousState["room_id"] === mjolnir.managementRoomId && previousState["user_id"] === userId) {
|
||||||
|
// The room is already setup, do nothing.
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
// There is a setup already, but it's not for us. Don't overwrite it.
|
||||||
|
let protectedRoomAliasOrId = await mjolnir.client.getPublishedAlias(protectedRoomId) || protectedRoomId;
|
||||||
|
mjolnir.managementRoomOutput.logMessage(LogLevel.INFO, "LocalAbuseReports", `Room ${protectedRoomAliasOrId} is already setup for decentralized abuse reports with bot ${previousState["user_id"]} and room ${previousState["room_id"]}, not overwriting automatically. To overwrite, use command \`!mjolnir rooms setup ${protectedRoomId} reporting\``);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup protected room -> moderation room link.
|
||||||
|
// We do this before the other one to be able to fail early if we do not have a sufficient
|
||||||
|
// powerlevel.
|
||||||
|
let eventId;
|
||||||
|
try {
|
||||||
|
eventId = await mjolnir.client.sendStateEvent(protectedRoomId, EVENT_MODERATED_BY, EVENT_MODERATED_BY, {
|
||||||
|
room_id: mjolnir.managementRoomId,
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
|
} catch (ex) {
|
||||||
|
mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "LocalAbuseReports", `Could not autoset protected room -> moderation room link: ${ex.message}. To set it manually, use command \`!mjolnir rooms setup ${protectedRoomId} reporting\``);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Setup moderation room -> protected room.
|
||||||
|
await mjolnir.client.sendStateEvent(mjolnir.managementRoomId, EVENT_MODERATOR_OF, protectedRoomId, {
|
||||||
|
user_id: userId,
|
||||||
|
});
|
||||||
|
} catch (ex) {
|
||||||
|
// If the second `sendStateEvent` fails, we could end up with a room half setup, which
|
||||||
|
// is bad. Attempt to rollback.
|
||||||
|
mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "LocalAbuseReports", `Could not autoset moderation room -> protected room link: ${ex.message}. To set it manually, use command \`!mjolnir rooms setup ${protectedRoomId} reporting\``);
|
||||||
|
try {
|
||||||
|
await mjolnir.client.redactEvent(protectedRoomId, eventId, "Rolling back incomplete MSC3215 setup");
|
||||||
|
} finally {
|
||||||
|
// Ignore second exception, propagate first.
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (ex) {
|
||||||
|
mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "LocalAbuseReports", ex.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -30,6 +30,7 @@ import { Consequence } from "./consequence";
|
|||||||
import { htmlEscape } from "../utils";
|
import { htmlEscape } from "../utils";
|
||||||
import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache";
|
import { ERROR_KIND_FATAL, ERROR_KIND_PERMISSION } from "../ErrorCache";
|
||||||
import { RoomUpdateError } from "../models/RoomUpdateError";
|
import { RoomUpdateError } from "../models/RoomUpdateError";
|
||||||
|
import { LocalAbuseReports } from "./LocalAbuseReports";
|
||||||
|
|
||||||
const PROTECTIONS: Protection[] = [
|
const PROTECTIONS: Protection[] = [
|
||||||
new FirstMessageIsImage(),
|
new FirstMessageIsImage(),
|
||||||
@ -40,6 +41,7 @@ const PROTECTIONS: Protection[] = [
|
|||||||
new TrustedReporters(),
|
new TrustedReporters(),
|
||||||
new DetectFederationLag(),
|
new DetectFederationLag(),
|
||||||
new JoinWaveShortCircuit(),
|
new JoinWaveShortCircuit(),
|
||||||
|
new LocalAbuseReports(),
|
||||||
];
|
];
|
||||||
|
|
||||||
const ENABLED_PROTECTIONS_EVENT_TYPE = "org.matrix.mjolnir.enabled_protections";
|
const ENABLED_PROTECTIONS_EVENT_TYPE = "org.matrix.mjolnir.enabled_protections";
|
||||||
@ -97,6 +99,11 @@ export class ProtectionManager {
|
|||||||
// this.getProtectionSettings() validates this data for us, so we don't need to
|
// this.getProtectionSettings() validates this data for us, so we don't need to
|
||||||
protection.settings[key].setValue(value);
|
protection.settings[key].setValue(value);
|
||||||
}
|
}
|
||||||
|
if (protection.enabled) {
|
||||||
|
for (let roomId of this.mjolnir.protectedRoomsTracker.getProtectedRooms()) {
|
||||||
|
await protection.startProtectingRoom(this.mjolnir, roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -104,11 +111,17 @@ export class ProtectionManager {
|
|||||||
*
|
*
|
||||||
* @param protection The protection object we want to unregister
|
* @param protection The protection object we want to unregister
|
||||||
*/
|
*/
|
||||||
public unregisterProtection(protectionName: string) {
|
public async unregisterProtection(protectionName: string) {
|
||||||
if (!(this._protections.has(protectionName))) {
|
let protection = this._protections.get(protectionName);
|
||||||
|
if (!protection) {
|
||||||
throw new Error("Failed to find protection by name: " + protectionName);
|
throw new Error("Failed to find protection by name: " + protectionName);
|
||||||
}
|
}
|
||||||
this._protections.delete(protectionName);
|
this._protections.delete(protectionName);
|
||||||
|
if (protection.enabled) {
|
||||||
|
for (let roomId of this.mjolnir.protectedRoomsTracker.getProtectedRooms()) {
|
||||||
|
await protection.stopProtectingRoom(this.mjolnir, roomId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -159,9 +172,13 @@ export class ProtectionManager {
|
|||||||
*/
|
*/
|
||||||
public async enableProtection(name: string) {
|
public async enableProtection(name: string) {
|
||||||
const protection = this._protections.get(name);
|
const protection = this._protections.get(name);
|
||||||
if (protection !== undefined) {
|
if (protection === undefined) {
|
||||||
protection.enabled = true;
|
return;
|
||||||
await this.saveEnabledProtections();
|
}
|
||||||
|
protection.enabled = true;
|
||||||
|
await this.saveEnabledProtections();
|
||||||
|
for (let roomId of this.mjolnir.protectedRoomsTracker.getProtectedRooms()) {
|
||||||
|
await protection.startProtectingRoom(this.mjolnir, roomId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -187,9 +204,13 @@ export class ProtectionManager {
|
|||||||
*/
|
*/
|
||||||
public async disableProtection(name: string) {
|
public async disableProtection(name: string) {
|
||||||
const protection = this._protections.get(name);
|
const protection = this._protections.get(name);
|
||||||
if (protection !== undefined) {
|
if (protection === undefined) {
|
||||||
protection.enabled = false;
|
return;
|
||||||
await this.saveEnabledProtections();
|
}
|
||||||
|
protection.enabled = false;
|
||||||
|
await this.saveEnabledProtections();
|
||||||
|
for (let roomId of this.mjolnir.protectedRoomsTracker.getProtectedRooms()) {
|
||||||
|
await protection.stopProtectingRoom(this.mjolnir, roomId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,4 +415,24 @@ export class ProtectionManager {
|
|||||||
await protection.handleReport(this.mjolnir, roomId, reporterId, event, reason);
|
await protection.handleReport(this.mjolnir, roomId, reporterId, event, reason);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async addProtectedRoom(roomId: string) {
|
||||||
|
for (const protection of this.enabledProtections) {
|
||||||
|
try {
|
||||||
|
await protection.startProtectingRoom(this.mjolnir, roomId);
|
||||||
|
} catch (ex) {
|
||||||
|
this.mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, protection.name, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async removeProtectedRoom(roomId: string) {
|
||||||
|
for (const protection of this.enabledProtections) {
|
||||||
|
try {
|
||||||
|
await protection.stopProtectingRoom(this.mjolnir, roomId);
|
||||||
|
} catch (ex) {
|
||||||
|
this.mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, protection.name, ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,7 +16,89 @@ const EVENT_MODERATED_BY = "org.matrix.msc3215.room.moderation.moderated_by";
|
|||||||
const EVENT_MODERATOR_OF = "org.matrix.msc3215.room.moderation.moderator_of";
|
const EVENT_MODERATOR_OF = "org.matrix.msc3215.room.moderation.moderator_of";
|
||||||
const EVENT_MODERATION_REQUEST = "org.matrix.msc3215.abuse.report";
|
const EVENT_MODERATION_REQUEST = "org.matrix.msc3215.abuse.report";
|
||||||
|
|
||||||
|
enum SetupMechanism {
|
||||||
|
ManualCommand,
|
||||||
|
Protection
|
||||||
|
}
|
||||||
|
|
||||||
describe("Test: Requesting moderation", async () => {
|
describe("Test: Requesting moderation", async () => {
|
||||||
|
it(`Mjölnir can setup a room for moderation requests using !mjolnir command`, async function() {
|
||||||
|
// Create a few users and a room, make sure that Mjölnir is moderator in the room.
|
||||||
|
let goodUser = await newTestUser(this.config.homeserverUrl, { name: { contains: "reporting-abuse-good-user" }});
|
||||||
|
let badUser = await newTestUser(this.config.homeserverUrl, { name: { contains: "reporting-abuse-bad-user" }});
|
||||||
|
|
||||||
|
let roomId = await goodUser.createRoom({ invite: [await badUser.getUserId(), await this.mjolnir.client.getUserId()] });
|
||||||
|
await goodUser.inviteUser(await badUser.getUserId(), roomId);
|
||||||
|
await badUser.joinRoom(roomId);
|
||||||
|
await goodUser.setUserPowerLevel(await this.mjolnir.client.getUserId(), roomId, 100);
|
||||||
|
|
||||||
|
// Setup moderated_by/moderator_of.
|
||||||
|
await this.mjolnir.client.sendText(this.mjolnir.managementRoomId, `!mjolnir rooms setup ${roomId} reporting`);
|
||||||
|
|
||||||
|
// Wait until moderated_by/moderator_of are setup
|
||||||
|
while (true) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
try {
|
||||||
|
await goodUser.getRoomStateEvent(roomId, EVENT_MODERATED_BY, EVENT_MODERATED_BY);
|
||||||
|
} catch (ex) {
|
||||||
|
console.log("moderated_by not setup yet, waiting");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.mjolnir.client.getRoomStateEvent(this.mjolnir.managementRoomId, EVENT_MODERATOR_OF, roomId);
|
||||||
|
} catch (ex) {
|
||||||
|
console.log("moderator_of not setup yet, waiting");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
it(`Mjölnir can setup a room for moderation requests using room protections`, async function() {
|
||||||
|
await this.mjolnir.protectionManager.enableProtection("LocalAbuseReports");
|
||||||
|
|
||||||
|
// Create a few users and a room, make sure that Mjölnir is moderator in the room.
|
||||||
|
let goodUser = await newTestUser(this.config.homeserverUrl, { name: { contains: "reporting-abuse-good-user" }});
|
||||||
|
let badUser = await newTestUser(this.config.homeserverUrl, { name: { contains: "reporting-abuse-bad-user" }});
|
||||||
|
|
||||||
|
let roomId = await goodUser.createRoom({ invite: [await badUser.getUserId(), await this.mjolnir.client.getUserId()] });
|
||||||
|
await goodUser.inviteUser(await badUser.getUserId(), roomId);
|
||||||
|
await badUser.joinRoom(roomId);
|
||||||
|
await this.mjolnir.client.joinRoom(roomId);
|
||||||
|
await goodUser.setUserPowerLevel(await this.mjolnir.client.getUserId(), roomId, 100);
|
||||||
|
|
||||||
|
// Wait until Mjölnir has joined the room.
|
||||||
|
while (true) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
const joinedRooms = await this.mjolnir.client.getJoinedRooms();
|
||||||
|
console.debug("Looking for room", roomId, "in", joinedRooms);
|
||||||
|
if (joinedRooms.some(joinedRoomId => joinedRoomId == roomId)) {
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
console.log("Mjölnir hasn't joined the room yet, waiting");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Setup moderated_by/moderator_of.
|
||||||
|
this.mjolnir.addProtectedRoom(roomId);
|
||||||
|
|
||||||
|
// Wait until moderated_by/moderator_of are setup
|
||||||
|
while (true) {
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
try {
|
||||||
|
await goodUser.getRoomStateEvent(roomId, EVENT_MODERATED_BY, EVENT_MODERATED_BY);
|
||||||
|
} catch (ex) {
|
||||||
|
console.log("moderated_by not setup yet, waiting");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
await this.mjolnir.client.getRoomStateEvent(this.mjolnir.managementRoomId, EVENT_MODERATOR_OF, roomId);
|
||||||
|
} catch (ex) {
|
||||||
|
console.log("moderator_of not setup yet, waiting");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
});
|
||||||
it(`Mjölnir propagates moderation requests`, async function() {
|
it(`Mjölnir propagates moderation requests`, async function() {
|
||||||
this.timeout(90000);
|
this.timeout(90000);
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { strict as assert } from "assert";
|
import { strict as assert } from "assert";
|
||||||
|
|
||||||
import { Mjolnir } from "../../src/Mjolnir";
|
import { Mjolnir } from "../../src/Mjolnir";
|
||||||
import { IProtection } from "../../src/protections/IProtection";
|
import { Protection } from "../../src/protections/IProtection";
|
||||||
import { ProtectionSettingValidationError } from "../../src/protections/ProtectionSettings";
|
import { ProtectionSettingValidationError } from "../../src/protections/ProtectionSettings";
|
||||||
import { NumberProtectionSetting, StringProtectionSetting, StringListProtectionSetting } from "../../src/protections/ProtectionSettings";
|
import { NumberProtectionSetting, StringProtectionSetting, StringListProtectionSetting } from "../../src/protections/ProtectionSettings";
|
||||||
import { newTestUser, noticeListener } from "./clientHelper";
|
import { newTestUser, noticeListener } from "./clientHelper";
|
||||||
@ -26,7 +26,7 @@ describe("Test: Protection settings", function() {
|
|||||||
it("Mjolnir successfully saves valid protection setting values", async function() {
|
it("Mjolnir successfully saves valid protection setting values", async function() {
|
||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "05OVMS";
|
name = "05OVMS";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { test: new NumberProtectionSetting(3) };
|
settings = { test: new NumberProtectionSetting(3) };
|
||||||
@ -41,8 +41,9 @@ describe("Test: Protection settings", function() {
|
|||||||
it("Mjolnir should accumulate changed settings", async function() {
|
it("Mjolnir should accumulate changed settings", async function() {
|
||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "HPUjKN";
|
name = "HPUjKN";
|
||||||
|
description = "A test protection";
|
||||||
settings = {
|
settings = {
|
||||||
test1: new NumberProtectionSetting(3),
|
test1: new NumberProtectionSetting(3),
|
||||||
test2: new NumberProtectionSetting(4)
|
test2: new NumberProtectionSetting(4)
|
||||||
@ -59,7 +60,7 @@ describe("Test: Protection settings", function() {
|
|||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
await client.joinRoom(this.config.managementRoom);
|
await client.joinRoom(this.config.managementRoom);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "JY2TPN";
|
name = "JY2TPN";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { test: new StringProtectionSetting() };
|
settings = { test: new StringProtectionSetting() };
|
||||||
@ -84,7 +85,7 @@ describe("Test: Protection settings", function() {
|
|||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
await client.joinRoom(this.config.managementRoom);
|
await client.joinRoom(this.config.managementRoom);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "r33XyT";
|
name = "r33XyT";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { test: new StringListProtectionSetting() };
|
settings = { test: new StringListProtectionSetting() };
|
||||||
@ -108,7 +109,7 @@ describe("Test: Protection settings", function() {
|
|||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
await client.joinRoom(this.config.managementRoom);
|
await client.joinRoom(this.config.managementRoom);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "oXzT0E";
|
name = "oXzT0E";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { test: new StringListProtectionSetting() };
|
settings = { test: new StringListProtectionSetting() };
|
||||||
@ -133,13 +134,13 @@ describe("Test: Protection settings", function() {
|
|||||||
this.timeout(20000);
|
this.timeout(20000);
|
||||||
await client.joinRoom(this.config.managementRoom);
|
await client.joinRoom(this.config.managementRoom);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "d0sNrt";
|
name = "d0sNrt";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { test: new StringProtectionSetting() };
|
settings = { test: new StringProtectionSetting() };
|
||||||
});
|
});
|
||||||
|
|
||||||
let replyPromise = new Promise((resolve, reject) => {
|
let replyPromise: Promise<any> = new Promise((resolve, reject) => {
|
||||||
let i = 0;
|
let i = 0;
|
||||||
client.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
|
client.on('room.message', noticeListener(this.mjolnir.managementRoomId, (event) => {
|
||||||
if (event.content.body.includes("Changed d0sNrt.test ")) {
|
if (event.content.body.includes("Changed d0sNrt.test ")) {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import { Mjolnir } from "../../src/Mjolnir";
|
import { Mjolnir } from "../../src/Mjolnir";
|
||||||
import { IProtection } from "../../src/protections/IProtection";
|
import { Protection } from "../../src/protections/IProtection";
|
||||||
import { newTestUser } from "./clientHelper";
|
import { newTestUser } from "./clientHelper";
|
||||||
|
|
||||||
describe("Test: Report polling", function() {
|
describe("Test: Report polling", function() {
|
||||||
@ -15,18 +15,21 @@ describe("Test: Report polling", function() {
|
|||||||
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
||||||
|
|
||||||
const eventId = await client.sendMessage(protectedRoomId, {msgtype: "m.text", body: "uwNd3q"});
|
const eventId = await client.sendMessage(protectedRoomId, {msgtype: "m.text", body: "uwNd3q"});
|
||||||
|
class CustomProtection extends Protection {
|
||||||
|
name = "jYvufI";
|
||||||
|
description = "A test protection";
|
||||||
|
settings = { };
|
||||||
|
constructor(private resolve) {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
async handleReport (mjolnir: Mjolnir, roomId: string, reporterId: string, event: any, reason?: string) {
|
||||||
|
if (reason === "x5h1Je") {
|
||||||
|
this.resolve(null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
await new Promise(async resolve => {
|
await new Promise(async resolve => {
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new CustomProtection(resolve));
|
||||||
name = "jYvufI";
|
|
||||||
description = "A test protection";
|
|
||||||
settings = { };
|
|
||||||
handleEvent = async (mjolnir: Mjolnir, roomId: string, event: any) => { };
|
|
||||||
handleReport = (mjolnir: Mjolnir, roomId: string, reporterId: string, event: any, reason?: string) => {
|
|
||||||
if (reason === "x5h1Je") {
|
|
||||||
resolve(null);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
});
|
|
||||||
await this.mjolnir.protectionManager.enableProtection("jYvufI");
|
await this.mjolnir.protectionManager.enableProtection("jYvufI");
|
||||||
await client.doRequest(
|
await client.doRequest(
|
||||||
"POST",
|
"POST",
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { strict as assert } from "assert";
|
import { strict as assert } from "assert";
|
||||||
|
|
||||||
import { Mjolnir } from "../../src/Mjolnir";
|
import { Mjolnir } from "../../src/Mjolnir";
|
||||||
import { IProtection } from "../../src/protections/IProtection";
|
import { Protection } from "../../src/protections/IProtection";
|
||||||
import { newTestUser, noticeListener } from "./clientHelper";
|
import { newTestUser, noticeListener } from "./clientHelper";
|
||||||
import { matrixClient, mjolnir } from "./mjolnirSetupUtils";
|
import { matrixClient, mjolnir } from "./mjolnirSetupUtils";
|
||||||
import { ConsequenceBan, ConsequenceRedact } from "../../src/protections/consequence";
|
import { ConsequenceBan, ConsequenceRedact } from "../../src/protections/consequence";
|
||||||
@ -27,7 +27,7 @@ describe("Test: standard consequences", function() {
|
|||||||
await badUser.joinRoom(protectedRoomId);
|
await badUser.joinRoom(protectedRoomId);
|
||||||
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "JY2TPN";
|
name = "JY2TPN";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { };
|
settings = { };
|
||||||
@ -39,7 +39,7 @@ describe("Test: standard consequences", function() {
|
|||||||
});
|
});
|
||||||
await this.mjolnir.protectionManager.enableProtection("JY2TPN");
|
await this.mjolnir.protectionManager.enableProtection("JY2TPN");
|
||||||
|
|
||||||
let reply = new Promise(async (resolve, reject) => {
|
let reply: Promise<any> = new Promise(async (resolve, reject) => {
|
||||||
const messageId = await badUser.sendMessage(protectedRoomId, {msgtype: "m.text", body: "ngmWkF"});
|
const messageId = await badUser.sendMessage(protectedRoomId, {msgtype: "m.text", body: "ngmWkF"});
|
||||||
let redaction;
|
let redaction;
|
||||||
badUser.on('room.event', (roomId, event) => {
|
badUser.on('room.event', (roomId, event) => {
|
||||||
@ -71,7 +71,7 @@ describe("Test: standard consequences", function() {
|
|||||||
await badUser.joinRoom(protectedRoomId);
|
await badUser.joinRoom(protectedRoomId);
|
||||||
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "0LxMTy";
|
name = "0LxMTy";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { };
|
settings = { };
|
||||||
@ -83,7 +83,7 @@ describe("Test: standard consequences", function() {
|
|||||||
});
|
});
|
||||||
await this.mjolnir.protectionManager.enableProtection("0LxMTy");
|
await this.mjolnir.protectionManager.enableProtection("0LxMTy");
|
||||||
|
|
||||||
let reply = new Promise(async (resolve, reject) => {
|
let reply: Promise<any> = new Promise(async (resolve, reject) => {
|
||||||
const messageId = await badUser.sendMessage(protectedRoomId, {msgtype: "m.text", body: "7Uga3d"});
|
const messageId = await badUser.sendMessage(protectedRoomId, {msgtype: "m.text", body: "7Uga3d"});
|
||||||
let ban;
|
let ban;
|
||||||
badUser.on('room.leave', (roomId, event) => {
|
badUser.on('room.leave', (roomId, event) => {
|
||||||
@ -118,7 +118,7 @@ describe("Test: standard consequences", function() {
|
|||||||
await goodUser.joinRoom(protectedRoomId);
|
await goodUser.joinRoom(protectedRoomId);
|
||||||
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
await this.mjolnir.addProtectedRoom(protectedRoomId);
|
||||||
|
|
||||||
await this.mjolnir.protectionManager.registerProtection(new class implements IProtection {
|
await this.mjolnir.protectionManager.registerProtection(new class extends Protection {
|
||||||
name = "95B1Cr";
|
name = "95B1Cr";
|
||||||
description = "A test protection";
|
description = "A test protection";
|
||||||
settings = { };
|
settings = { };
|
||||||
|
Loading…
Reference in New Issue
Block a user