mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-09-28 20:26:02 +00:00
WIP
This commit is contained in:
parent
77784a88b1
commit
df63b608e7
@ -192,3 +192,42 @@ web:
|
||||
abuseReporting:
|
||||
# Whether to enable this feature.
|
||||
enabled: false
|
||||
|
||||
# Uncomment to enable support for undoable actions.
|
||||
#
|
||||
# As of this writing, the only undoable action is `softredact`.
|
||||
#
|
||||
#trashcan:
|
||||
# # The room in which we store undoable actions for review.
|
||||
# # Mjölnir will not create it. This can be the same as the
|
||||
# # management room but it doesn't have to.
|
||||
# roomAliasOrId: "#trashcan:localhost"
|
||||
#
|
||||
# # Support for soft redactions, i.e. using Mjölnir to mark
|
||||
# # messages as hidden pending moderation.
|
||||
# #
|
||||
# # As of this writing, this feature only works with develop
|
||||
# # versions of Element Web, with feature
|
||||
# # `feature_msc3531_hide_messages_pending_moderation`
|
||||
# # enabled.
|
||||
# #
|
||||
# # Comment this out if you wish to disable soft redactions.
|
||||
# softRedact:
|
||||
# # After `goodAfterMs` milliseconds, any message hidden
|
||||
# # pending moderation by Mjölnir will revert to visible
|
||||
# # and vanish from the trashcan.
|
||||
# # Ignored if `goodAfterMs` is >= `badAfterMs` or `retainMs`.
|
||||
# goodAfterMs: .inf
|
||||
#
|
||||
# # After `badAfterMs` milliseconds, any message hidden
|
||||
# # pending moderation by Mjölnir will be irreversibly
|
||||
# # deleted from homeservers and up-to-date clients and
|
||||
# # vanish from the trashcan.
|
||||
# # Ignored if `badAfterMs` is > `goodAfterMs` or `retainMs`.
|
||||
# badAfterMs: .inf
|
||||
#
|
||||
# # After `retainMs` milliseconds, any message hidden
|
||||
# # pending moderation will vanish from the trashcan, without
|
||||
# # further action.
|
||||
# # Ignored if `retainMs` is > `goodAfterMs` or `badAfterMs`.
|
||||
# retainMs: 604800000 # Approximately one week.
|
||||
|
@ -42,6 +42,7 @@ import { EventRedactionQueue, RedactUserInRoom } from "./queues/EventRedactionQu
|
||||
import * as htmlEscape from "escape-html";
|
||||
import { ReportManager } from "./report/ReportManager";
|
||||
import { WebAPIs } from "./webapis/WebAPIs";
|
||||
import { TrashManager } from "./trashcan/TrashManager";
|
||||
|
||||
export const STATE_NOT_STARTED = "not_started";
|
||||
export const STATE_CHECKING_PERMISSIONS = "checking_permissions";
|
||||
@ -73,6 +74,8 @@ export class Mjolnir {
|
||||
private explicitlyProtectedRoomIds: string[] = [];
|
||||
private knownUnprotectedRooms: string[] = [];
|
||||
private webapis: WebAPIs;
|
||||
public trashcanManager?: TrashManager;
|
||||
|
||||
/**
|
||||
* Adds a listener to the client that will automatically accept invitations.
|
||||
* @param {MatrixClient} client
|
||||
@ -146,15 +149,25 @@ export class Mjolnir {
|
||||
} else {
|
||||
config.managementRoom = managementRoomId;
|
||||
}
|
||||
await logMessage(LogLevel.INFO, "index", "Mjolnir is starting up. Use !mjolnir to query status.");
|
||||
|
||||
return new Mjolnir(client, protectedRooms, banLists);
|
||||
let trashcanRoomId;
|
||||
if (config.trashcan) {
|
||||
trashcanRoomId = await client.resolveRoom(config.trashcan.roomAliasOrId);
|
||||
const joinedRooms = await client.getJoinedRooms();
|
||||
if (!joinedRooms.includes(trashcanRoomId)) {
|
||||
await client.joinRoom(trashcanRoomId);
|
||||
}
|
||||
}
|
||||
|
||||
await logMessage(LogLevel.INFO, "index", "Mjolnir is starting up. Use !mjolnir to query status.");
|
||||
return new Mjolnir(client, protectedRooms, banLists, trashcanRoomId);
|
||||
}
|
||||
|
||||
constructor(
|
||||
public readonly client: MatrixClient,
|
||||
public readonly protectedRooms: { [roomId: string]: string },
|
||||
private banLists: BanList[],
|
||||
trashcanRoomId?: string,
|
||||
) {
|
||||
this.explicitlyProtectedRoomIds = Object.keys(this.protectedRooms);
|
||||
|
||||
@ -222,6 +235,12 @@ export class Mjolnir {
|
||||
// Setup Web APIs
|
||||
console.log("Creating Web APIs");
|
||||
this.webapis = new WebAPIs(new ReportManager(this));
|
||||
|
||||
// Setup trashcan.
|
||||
console.log("Creating Trashcan Manager");
|
||||
if (trashcanRoomId) {
|
||||
this.trashcanManager = new TrashManager(this, trashcanRoomId);
|
||||
}
|
||||
}
|
||||
|
||||
public get lists(): BanList[] {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019-2021 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019-2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -24,7 +24,8 @@ import { execSyncCommand } from "./SyncCommand";
|
||||
import { execPermissionCheckCommand } from "./PermissionCheckCommand";
|
||||
import { execCreateListCommand } from "./CreateBanListCommand";
|
||||
import { execUnwatchCommand, execWatchCommand } from "./WatchUnwatchCommand";
|
||||
import { execRedactCommand } from "./RedactCommand";
|
||||
import { execHardRedactCommand } from "./HardRedactCommand";
|
||||
import { execSoftRedactCommand } from "./SoftRedactCommand";
|
||||
import { execImportCommand } from "./ImportCommand";
|
||||
import { execSetDefaultListCommand } from "./SetDefaultBanListCommand";
|
||||
import { execDeactivateCommand } from "./DeactivateCommand";
|
||||
@ -63,7 +64,9 @@ export async function handleCommand(roomId: string, event: any, mjolnir: Mjolnir
|
||||
} else if (parts[1] === 'unwatch' && parts.length > 1) {
|
||||
return await execUnwatchCommand(roomId, event, mjolnir, parts);
|
||||
} else if (parts[1] === 'redact' && parts.length > 1) {
|
||||
return await execRedactCommand(roomId, event, mjolnir, parts);
|
||||
return await execHardRedactCommand(roomId, event, mjolnir, parts);
|
||||
} else if (parts[1] === 'hide' && parts.length > 1) {
|
||||
return await execSoftRedactCommand(roomId, event, mjolnir, parts);
|
||||
} else if (parts[1] === 'import' && parts.length > 2) {
|
||||
return await execImportCommand(roomId, event, mjolnir, parts);
|
||||
} else if (parts[1] === 'default' && parts.length > 2) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
Copyright 2019 The Matrix.org Foundation C.I.C.
|
||||
Copyright 2019-2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -18,8 +18,16 @@ import { Mjolnir } from "../Mjolnir";
|
||||
import { redactUserMessagesIn } from "../utils";
|
||||
import { Permalinks } from "matrix-bot-sdk";
|
||||
|
||||
/*!
|
||||
* "Hard redaction", cannot be undone.
|
||||
*
|
||||
* Instruct all participant homeservers to permanently erase the
|
||||
* contents of the message from the timeline and to request the
|
||||
* same from all clients.
|
||||
*/
|
||||
|
||||
// !mjolnir redact <user ID> [room alias] [limit]
|
||||
export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
export async function execHardRedactCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
const userId = parts[2];
|
||||
let roomAlias: string|null = null;
|
||||
let limit = Number.parseInt(parts.length > 3 ? parts[3] : "", 10); // default to NaN for later
|
66
src/commands/SoftRedactCommand.ts
Normal file
66
src/commands/SoftRedactCommand.ts
Normal file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
Copyright 2022 The Matrix.org Foundation C.I.C.
|
||||
|
||||
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 { Mjolnir } from "../Mjolnir";
|
||||
import { redactUserMessagesIn } from "../utils";
|
||||
import { Permalinks } from "matrix-bot-sdk";
|
||||
|
||||
/*!
|
||||
* "Soft redaction", aka "undoable redaction".
|
||||
*
|
||||
* 1. Instruct all clients to mark the message as hidden
|
||||
* pending moderation. Only moderators and the author
|
||||
* of the message may still see it.
|
||||
* 2. Copy the message to the trashcan room.
|
||||
* 3. In the trashcan room, moderators have the ability
|
||||
* to either restore the message or trash (i.e. redact)
|
||||
* it permanently.
|
||||
*/
|
||||
|
||||
// !mjolnir hide <user ID> [room alias] [limit]
|
||||
export async function execSoftRedactCommand(roomId: string, instructionEvent: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
// This could either be an eventId or a userId.
|
||||
const targetId = parts[2];
|
||||
let roomAlias: string | null = null;
|
||||
let limit = Number.parseInt(parts.length > 3 ? parts[3] : "", 10); // default to NaN for later
|
||||
if (parts.length > 3 && isNaN(limit)) {
|
||||
roomAlias = await mjolnir.client.resolveRoom(parts[3]);
|
||||
if (parts.length > 4) {
|
||||
limit = Number.parseInt(parts[4], 10);
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure we always have a limit set
|
||||
if (isNaN(limit)) limit = 1000;
|
||||
|
||||
const processingReactionId = await mjolnir.client.unstableApis.addReactionToEvent(roomId, instructionEvent['event_id'], 'In Progress');
|
||||
|
||||
if (userId[0] !== '@') {
|
||||
// Assume it's a permalink
|
||||
const parsed = Permalinks.parseUrl(parts[2]);
|
||||
const targetRoomId = await mjolnir.client.resolveRoom(parsed.roomIdOrAlias);
|
||||
await mjolnir.client.redactEvent(targetRoomId, parsed.eventId);
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, instructionEvent['event_id'], '✅');
|
||||
await mjolnir.client.redactEvent(roomId, processingReactionId, 'done processing command');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetRoomIds = roomAlias ? [roomAlias] : Object.keys(mjolnir.protectedRooms);
|
||||
await redactUserMessagesIn(mjolnir.client, userId, targetRoomIds, limit);
|
||||
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, instructionEvent['event_id'], '✅');
|
||||
await mjolnir.client.redactEvent(roomId, processingReactionId, 'done processing');
|
||||
}
|
@ -76,7 +76,15 @@ interface IConfig {
|
||||
abuseReporting: {
|
||||
enabled: boolean;
|
||||
}
|
||||
}
|
||||
};
|
||||
trashcan?: {
|
||||
roomAliasOrId: string;
|
||||
softRedact?: {
|
||||
goodAfterMs: number;
|
||||
badAfterMs: number;
|
||||
retainMs: number;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Config options only set at runtime. Try to avoid using the objects
|
||||
|
Loading…
Reference in New Issue
Block a user