Add commands to add/remove protected rooms on the fly

This commit is contained in:
Travis Ralston 2020-01-21 13:43:36 -07:00
parent c1ea98f55d
commit 38e22ee155
5 changed files with 137 additions and 2 deletions

View File

@ -83,3 +83,8 @@ you want to redact events by that person from all protected rooms, don't specify
Sometimes you might want to see what Mjolnir is up to. There's some commands in `!mjolnir help` that could
be of use to you, such as `!mjolnir rules` to see what rules it is actually enforcing and `!mjolnir status`
to see if Mjolnir is even running where you expect it to.
Adding protected rooms on the fly is as easy as `!mjolnir rooms add <room alias>`. You can see all the rooms
which are protected with `!mjolnir rooms`, and remove a room with `!mjolnir rooms remove <room alias>`. Note
that rooms which are listed in the config may be protected again when the bot restarts - to remove these rooms
permanently from protection, remove them from the config.

View File

@ -34,6 +34,7 @@ export const STATE_RUNNING = "running";
const WATCHED_LISTS_EVENT_TYPE = "org.matrix.mjolnir.watched_lists";
const ENABLED_PROTECTIONS_EVENT_TYPE = "org.matrix.mjolnir.enabled_protections";
const PROTECTED_ROOMS_EVENT_TYPE = "org.matrix.mjolnir.protected_rooms";
export class Mjolnir {
@ -81,7 +82,7 @@ export class Mjolnir {
if (profile['displayname']) {
this.displayName = profile['displayname'];
}
})
});
}
public get lists(): BanList[] {
@ -113,6 +114,17 @@ export class Mjolnir {
}
}).then(async () => {
this.currentState = STATE_SYNCING;
await logMessage(LogLevel.DEBUG, "Mjolnir@startup", "Loading protected rooms...");
try {
const data = await this.client.getAccountData(PROTECTED_ROOMS_EVENT_TYPE);
if (data && data['rooms']) {
for (const roomId of data['rooms']) {
this.protectedRooms[roomId] = Permalinks.forRoom(roomId);
}
}
} catch (e) {
LogService.warn("Mjolnir", e);
}
if (config.syncOnStartup) {
await logMessage(LogLevel.INFO, "Mjolnir@startup", "Syncing lists...");
await this.buildWatchedBanLists();
@ -125,6 +137,36 @@ export class Mjolnir {
});
}
public async addProtectedRoom(roomId: string) {
const permalink = Permalinks.forRoom(roomId);
this.protectedRooms[roomId] = permalink;
let additionalProtectedRooms;
try {
additionalProtectedRooms = await this.client.getAccountData(PROTECTED_ROOMS_EVENT_TYPE);
} catch (e) {
LogService.warn("Mjolnir", e);
}
if (!additionalProtectedRooms || !additionalProtectedRooms['rooms']) additionalProtectedRooms = {rooms: []};
additionalProtectedRooms.rooms.push(roomId);
await this.client.setAccountData(PROTECTED_ROOMS_EVENT_TYPE, additionalProtectedRooms);
await this.syncLists(config.verboseLogging);
}
public async removeProtectedRoom(roomId: string) {
delete this.protectedRooms[roomId];
let additionalProtectedRooms;
try {
additionalProtectedRooms = await this.client.getAccountData(PROTECTED_ROOMS_EVENT_TYPE);
} catch (e) {
LogService.warn("Mjolnir", e);
}
if (!additionalProtectedRooms || !additionalProtectedRooms['rooms']) additionalProtectedRooms = {rooms: []};
additionalProtectedRooms.rooms = additionalProtectedRooms.rooms.filter(r => r !== roomId);
await this.client.setAccountData(PROTECTED_ROOMS_EVENT_TYPE, additionalProtectedRooms);
}
private async getEnabledProtections() {
let enabled: string[] = [];
try {

View File

@ -0,0 +1,33 @@
/*
Copyright 2020 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 { RichReply } from "matrix-bot-sdk";
// !mjolnir rooms add <room alias/ID>
export async function execAddProtectedRoom(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const protectedRoomId = await mjolnir.client.joinRoom(parts[3]);
await mjolnir.addProtectedRoom(protectedRoomId);
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
}
// !mjolnir rooms remove <room alias/ID>
export async function execRemoveProtectedRoom(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const protectedRoomId = await mjolnir.client.resolveRoom(parts[3]);
await mjolnir.removeProtectedRoom(protectedRoomId);
await mjolnir.client.leaveRoom(protectedRoomId);
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
}

View File

@ -1,5 +1,5 @@
/*
Copyright 2019 The Matrix.org Foundation C.I.C.
Copyright 2019, 2020 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.
@ -29,6 +29,8 @@ import { execImportCommand } from "./ImportCommand";
import { execSetDefaultListCommand } from "./SetDefaultBanListCommand";
import { execDeactivateCommand } from "./DeactivateCommand";
import { execDisableProtection, execEnableProtection, execListProtections } from "./ProtectionsCommands";
import { execListProtectedRooms } from "./ListProtectedRoomsCommand";
import { execAddProtectedRoom, execRemoveProtectedRoom } from "./AddRemoveProtectedRoomsCommand";
export const COMMAND_PREFIX = "!mjolnir";
@ -69,6 +71,12 @@ export async function handleCommand(roomId: string, event: any, mjolnir: Mjolnir
return await execEnableProtection(roomId, event, mjolnir, parts);
} else if (parts[1] === 'disable' && parts.length > 1) {
return await execDisableProtection(roomId, event, mjolnir, parts);
} else if (parts[1] === 'rooms' && parts.length > 3 && parts[2] === 'add') {
return await execAddProtectedRoom(roomId, event, mjolnir, parts);
} else if (parts[1] === 'rooms' && parts.length > 3 && parts[2] === 'remove') {
return await execRemoveProtectedRoom(roomId, event, mjolnir, parts);
} else if (parts[1] === 'rooms' && parts.length === 2) {
return await execListProtectedRooms(roomId, event, mjolnir);
} else {
// Help menu
const menu = "" +
@ -89,6 +97,9 @@ export async function handleCommand(roomId: string, event: any, mjolnir: Mjolnir
"!mjolnir protections - List all available protections\n" +
"!mjolnir enable <protection> - Enables a particular protection\n" +
"!mjolnir disable <protection> - Disables a particular protection\n" +
"!mjolnir rooms - Lists all the protected rooms\n" +
"!mjolnir rooms add <room alias/ID> - Adds a protected room (may cause high server load)\n" +
"!mjolnir rooms remove <room alias/ID> - Removes a protected room\n" +
"!mjolnir help - This menu\n";
const html = `<b>Mjolnir help:</b><br><pre><code>${htmlEscape(menu)}</code></pre>`;
const text = `Mjolnir help:\n${menu}`;

View File

@ -0,0 +1,44 @@
/*
Copyright 2020 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 { RichReply } from "matrix-bot-sdk";
// !mjolnir rooms
export async function execListProtectedRooms(roomId: string, event: any, mjolnir: Mjolnir) {
let html = "<b>Protected rooms:</b><br/><ul>";
let text = "Protected rooms:\n";
let hasRooms = false;
for (const roomId in mjolnir.protectedRooms) {
hasRooms = true;
const roomUrl = mjolnir.protectedRooms[roomId];
html += `<li><a href="${roomUrl}">${roomId}</a></li>`;
text += `* ${roomUrl}\n`;
}
html += "</ul>";
if (!hasRooms) {
html = "No protected rooms";
text = "No protected rooms";
}
const reply = RichReply.createFor(roomId, event, text, html);
reply["msgtype"] = "m.notice";
return mjolnir.client.sendMessage(roomId, reply);
}