mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-10-01 01:36:06 -04:00
Refactor bot into its own class
This commit is contained in:
parent
3a567edc38
commit
41cc36e4c6
90
src/Mjolnir.ts
Normal file
90
src/Mjolnir.ts
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
Copyright 2019 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 { MatrixClient } from "matrix-bot-sdk";
|
||||
import BanList, { ALL_RULE_TYPES } from "./models/BanList";
|
||||
import { applyServerAcls } from "./actions/ApplyAcl";
|
||||
import { RoomUpdateError } from "./models/RoomUpdateError";
|
||||
import { COMMAND_PREFIX, handleCommand } from "./commands/CommandHandler";
|
||||
|
||||
export class Mjolnir {
|
||||
constructor(
|
||||
public readonly client: MatrixClient,
|
||||
private managementRoomId: string,
|
||||
public readonly protectedRooms: { [roomId: string]: string },
|
||||
public readonly banLists: BanList[],
|
||||
) {
|
||||
client.on("room.event", this.handleEvent.bind(this));
|
||||
|
||||
client.on("room.message", async (roomId, event) => {
|
||||
if (roomId !== managementRoomId) return;
|
||||
if (!event['content']) return;
|
||||
|
||||
const content = event['content'];
|
||||
if (content['msgtype'] === "m.text" && content['body'] && content['body'].startsWith(COMMAND_PREFIX)) {
|
||||
await client.sendReadReceipt(roomId, event['event_id']);
|
||||
return handleCommand(roomId, event, this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public start() {
|
||||
return this.client.start();
|
||||
}
|
||||
|
||||
private async handleEvent(roomId: string, event: any) {
|
||||
if (!event['state_key']) return; // we also don't do anything with state events that have no state key
|
||||
|
||||
if (ALL_RULE_TYPES.includes(event['type'])) {
|
||||
for (const list of this.banLists) {
|
||||
if (list.roomId !== roomId) continue;
|
||||
await list.updateList();
|
||||
}
|
||||
|
||||
const errors = await applyServerAcls(this.banLists, Object.keys(this.protectedRooms), this.client);
|
||||
return this.printActionResult(errors);
|
||||
} else if (event['type'] === "m.room.member") {
|
||||
// TODO: Check membership against ban banLists
|
||||
}
|
||||
}
|
||||
|
||||
private async printActionResult(errors: RoomUpdateError[]) {
|
||||
let html = "";
|
||||
let text = "";
|
||||
|
||||
if (errors.length > 0) {
|
||||
html += `<font color="#ff0000"><b>${errors.length} errors updating protected rooms!</b></font><br /><ul>`;
|
||||
text += `${errors.length} errors updating protected rooms!\n`;
|
||||
for (const error of errors) {
|
||||
const url = this.protectedRooms[error.roomId] ? this.protectedRooms[error.roomId] : `https://matrix.to/#/${error.roomId}`;
|
||||
html += `<li><a href="${url}">${error.roomId}</a> - ${error.errorMessage}</li>`;
|
||||
text += `${url} - ${error.errorMessage}\n`;
|
||||
}
|
||||
html += "</ul>";
|
||||
} else {
|
||||
html += `<font color="#00cc00"><b>Updated all protected rooms with new rules successfully.</b></font>`;
|
||||
text += "Updated all protected rooms with new rules successfully";
|
||||
}
|
||||
|
||||
const message = {
|
||||
msgtype: "m.notice",
|
||||
body: text,
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: html,
|
||||
};
|
||||
return this.client.sendMessage(this.managementRoomId, message);
|
||||
}
|
||||
}
|
32
src/commands/CommandHandler.ts
Normal file
32
src/commands/CommandHandler.ts
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
Copyright 2019 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 { MatrixClient } from "matrix-bot-sdk";
|
||||
import { Mjolnir } from "../Mjolnir";
|
||||
import { execStatusCommand } from "./StatusCommand";
|
||||
|
||||
export const COMMAND_PREFIX = "!mjolnir";
|
||||
|
||||
export function handleCommand(roomId: string, event: any, mjolnir: Mjolnir) {
|
||||
const cmd = event['content']['body'];
|
||||
const parts = cmd.trim().split(' ');
|
||||
|
||||
if (parts.length === 1) {
|
||||
return execStatusCommand(roomId, event, mjolnir);
|
||||
} else {
|
||||
// TODO: Help menu
|
||||
}
|
||||
}
|
46
src/commands/StatusCommand.ts
Normal file
46
src/commands/StatusCommand.ts
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
Copyright 2019 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";
|
||||
|
||||
export async function execStatusCommand(roomId: string, event: any, mjolnir: Mjolnir) {
|
||||
let html = "";
|
||||
let text = "";
|
||||
|
||||
// Append header information first
|
||||
html += "<b>Running: </b>✅<br/>";
|
||||
text += "Running: ✅\n";
|
||||
html += `<b>Protected rooms: </b> ${Object.keys(mjolnir.protectedRooms).length}<br/>`;
|
||||
text += `Protected rooms: ${mjolnir.protectedRooms.length}\n`;
|
||||
|
||||
// Append list information
|
||||
html += "<b>Subscribed ban lists:</b><br><ul>";
|
||||
text += "Subscribed ban lists:\n";
|
||||
for (const list of mjolnir.banLists) {
|
||||
const ruleInfo = `rules: ${list.serverRules.length} servers, ${list.userRules.length} users, ${list.roomRules.length} rooms`;
|
||||
html += `<li><a href="${list.roomRef}">${list.roomId}</a> (${ruleInfo})</li>`;
|
||||
text += `${list.roomRef} (${ruleInfo})\n`;
|
||||
}
|
||||
html += "</ul>";
|
||||
|
||||
const message = {
|
||||
msgtype: "m.notice",
|
||||
body: text,
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: html,
|
||||
};
|
||||
return mjolnir.client.sendMessage(roomId, message);
|
||||
}
|
101
src/index.ts
101
src/index.ts
@ -27,48 +27,21 @@ import config from "./config";
|
||||
import BanList, { ALL_RULE_TYPES } from "./models/BanList";
|
||||
import { applyServerAcls } from "./actions/ApplyAcl";
|
||||
import { RoomUpdateError } from "./models/RoomUpdateError";
|
||||
import { Mjolnir } from "./Mjolnir";
|
||||
|
||||
LogService.setLogger(new RichConsoleLogger());
|
||||
|
||||
const storage = new SimpleFsStorageProvider(path.join(config.dataPath, "bot.json"));
|
||||
const client = new MatrixClient(config.homeserverUrl, config.accessToken, storage);
|
||||
const lists: BanList[] = [];
|
||||
let managementRoomId = "";
|
||||
const protectedRooms: { [roomId: string]: string } = {};
|
||||
|
||||
if (config.autojoin) {
|
||||
AutojoinRoomsMixin.setupOnClient(client);
|
||||
}
|
||||
|
||||
client.on("room.event", async (roomId, event) => {
|
||||
if (!event['state_key']) return; // we also don't do anything with state events that have no state key
|
||||
|
||||
if (ALL_RULE_TYPES.includes(event['type'])) {
|
||||
for (const list of lists) {
|
||||
if (list.roomId !== roomId) continue;
|
||||
await list.updateList();
|
||||
}
|
||||
|
||||
const errors = await applyServerAcls(lists, Object.keys(protectedRooms), client);
|
||||
return printActionResult(errors);
|
||||
} else if (event['type'] === "m.room.member") {
|
||||
// TODO: Check membership against ban lists
|
||||
}
|
||||
});
|
||||
|
||||
client.on("room.message", async (roomId, event) => {
|
||||
if (roomId !== managementRoomId) return;
|
||||
if (!event['content']) return;
|
||||
|
||||
const content = event['content'];
|
||||
if (content['msgtype'] === "m.text" && content['body'] === "!mjolnir") {
|
||||
await client.sendReadReceipt(roomId, event['event_id']);
|
||||
return printStatus(roomId);
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
(async function () {
|
||||
const banLists: BanList[] = [];
|
||||
const protectedRooms:{[roomId: string]: string} = {};
|
||||
|
||||
// Ensure we're in all the rooms we expect to be in
|
||||
const joinedRooms = await client.getJoinedRooms();
|
||||
for (const roomRef of config.banLists) {
|
||||
@ -82,7 +55,7 @@ client.on("room.message", async (roomId, event) => {
|
||||
|
||||
const list = new BanList(roomId, roomRef, client);
|
||||
await list.updateList();
|
||||
lists.push(list);
|
||||
banLists.push(list);
|
||||
}
|
||||
|
||||
// Ensure we're also joined to the rooms we're protecting
|
||||
@ -99,70 +72,14 @@ client.on("room.message", async (roomId, event) => {
|
||||
}
|
||||
|
||||
// Ensure we're also in the management room
|
||||
managementRoomId = await client.joinRoom(config.managementRoom);
|
||||
const managementRoomId = await client.joinRoom(config.managementRoom);
|
||||
await client.sendNotice(managementRoomId, "Mjolnir is starting up. Use !mjolnir to query status.");
|
||||
|
||||
const bot = new Mjolnir(client, managementRoomId, protectedRooms, banLists);
|
||||
await bot.start();
|
||||
|
||||
// TODO: Check permissions for mjolnir in protected rooms
|
||||
// TODO: Complain about permission changes in protected rooms (including after power levels change)
|
||||
|
||||
await client.start();
|
||||
LogService.info("index", "Bot started!")
|
||||
})();
|
||||
|
||||
async function printStatus(roomId: string) {
|
||||
const rooms = await client.getJoinedRooms();
|
||||
|
||||
let html = "";
|
||||
let text = "";
|
||||
|
||||
// Append header information first
|
||||
html += "<b>Running: </b>✅<br/>";
|
||||
text += "Running: ✅\n";
|
||||
html += `<b>Protected rooms: </b> ${Object.keys(protectedRooms).length}<br/>`;
|
||||
text += `Protected rooms: ${rooms.length}\n`;
|
||||
|
||||
// Append list information
|
||||
html += "<b>Subscribed lists:</b><br><ul>";
|
||||
text += "Subscribed lists:\n";
|
||||
for (const list of lists) {
|
||||
const ruleInfo = `rules: ${list.serverRules.length} servers, ${list.userRules.length} users, ${list.roomRules.length} rooms`;
|
||||
html += `<li><a href="${list.roomRef}">${list.roomId}</a> (${ruleInfo})</li>`;
|
||||
text += `${list.roomRef} (${ruleInfo})\n`;
|
||||
}
|
||||
html += "</ul>";
|
||||
|
||||
const message = {
|
||||
msgtype: "m.notice",
|
||||
body: text,
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: html,
|
||||
};
|
||||
return client.sendMessage(roomId, message);
|
||||
}
|
||||
|
||||
async function printActionResult(errors: RoomUpdateError[]) {
|
||||
let html = "";
|
||||
let text = "";
|
||||
|
||||
if (errors.length > 0) {
|
||||
html += `<font color="#ff0000"><b>${errors.length} errors updating protected rooms!</b></font><br /><ul>`;
|
||||
text += `${errors.length} errors updating protected rooms!\n`;
|
||||
for (const error of errors) {
|
||||
const url = protectedRooms[error.roomId] ? protectedRooms[error.roomId] : `https://matrix.to/#/${error.roomId}`;
|
||||
html += `<li><a href="${url}">${error.roomId}</a> - ${error.errorMessage}</li>`;
|
||||
text += `${url} - ${error.errorMessage}\n`;
|
||||
}
|
||||
html += "</ul>";
|
||||
} else {
|
||||
html += `<font color="#00cc00"><b>Updated all protected rooms with new rules successfully.</b></font>`;
|
||||
text += "Updated all protected rooms with new rules successfully";
|
||||
}
|
||||
|
||||
const message = {
|
||||
msgtype: "m.notice",
|
||||
body: text,
|
||||
format: "org.matrix.custom.html",
|
||||
formatted_body: html,
|
||||
};
|
||||
return client.sendMessage(managementRoomId, message);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user