2019-09-27 17:15:10 -04:00
|
|
|
/*
|
|
|
|
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";
|
2019-09-27 21:54:13 -04:00
|
|
|
import { applyUserBans } from "./actions/ApplyBan";
|
2019-09-27 17:15:10 -04:00
|
|
|
|
|
|
|
export class Mjolnir {
|
2019-09-27 18:04:08 -04:00
|
|
|
|
|
|
|
private displayName: string;
|
|
|
|
private localpart: string;
|
|
|
|
|
2019-09-27 17:15:10 -04:00
|
|
|
constructor(
|
|
|
|
public readonly client: MatrixClient,
|
2019-09-27 17:44:28 -04:00
|
|
|
public readonly managementRoomId: string,
|
|
|
|
public readonly publishedBanListRoomId: string,
|
2019-09-27 17:15:10 -04:00
|
|
|
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'];
|
2019-09-27 18:04:08 -04:00
|
|
|
if (content['msgtype'] === "m.text" && content['body']) {
|
|
|
|
const prefixes = [COMMAND_PREFIX, this.localpart + ":", this.displayName + ":", await client.getUserId() + ":"];
|
|
|
|
if (!prefixes.find(p => content['body'].startsWith(p))) return;
|
|
|
|
|
2019-09-27 17:15:10 -04:00
|
|
|
await client.sendReadReceipt(roomId, event['event_id']);
|
|
|
|
return handleCommand(roomId, event, this);
|
|
|
|
}
|
|
|
|
});
|
2019-09-27 18:04:08 -04:00
|
|
|
|
|
|
|
client.getUserId().then(userId => {
|
|
|
|
this.localpart = userId.split(':')[0].substring(1);
|
|
|
|
return client.getUserProfile(userId);
|
|
|
|
}).then(profile => {
|
|
|
|
if (profile['displayname']) {
|
|
|
|
this.displayName = profile['displayname'];
|
|
|
|
}
|
|
|
|
})
|
2019-09-27 17:15:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
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'])) {
|
2019-09-27 17:44:28 -04:00
|
|
|
let updated = false;
|
2019-09-27 17:15:10 -04:00
|
|
|
for (const list of this.banLists) {
|
|
|
|
if (list.roomId !== roomId) continue;
|
|
|
|
await list.updateList();
|
2019-09-27 17:44:28 -04:00
|
|
|
updated = true;
|
2019-09-27 17:15:10 -04:00
|
|
|
}
|
2019-09-27 17:44:28 -04:00
|
|
|
if (!updated) return;
|
2019-09-27 17:15:10 -04:00
|
|
|
|
2019-09-27 21:54:13 -04:00
|
|
|
let errors = await applyServerAcls(this.banLists, Object.keys(this.protectedRooms), this.client);
|
|
|
|
await this.printActionResult(errors);
|
|
|
|
|
|
|
|
errors = await applyUserBans(this.banLists, Object.keys(this.protectedRooms), this.client);
|
|
|
|
await this.printActionResult(errors);
|
2019-09-27 17:15:10 -04:00
|
|
|
} else if (event['type'] === "m.room.member") {
|
2019-09-27 21:54:13 -04:00
|
|
|
const errors = await applyUserBans(this.banLists, Object.keys(this.protectedRooms), this.client);
|
|
|
|
await this.printActionResult(errors);
|
2019-09-27 17:15:10 -04:00
|
|
|
}
|
2019-09-27 21:54:13 -04:00
|
|
|
|
|
|
|
|
|
|
|
const html = `<font color="#00cc00"><b>Updated all protected rooms with new rules successfully.</b></font>`;
|
|
|
|
const text = "Updated all protected rooms with new rules successfully";
|
|
|
|
await this.client.sendMessage(this.managementRoomId, {
|
|
|
|
msgtype: "m.notice",
|
|
|
|
body: text,
|
|
|
|
format: "org.matrix.custom.html",
|
|
|
|
formatted_body: html,
|
|
|
|
});
|
2019-09-27 17:15:10 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
private async printActionResult(errors: RoomUpdateError[]) {
|
2019-09-27 21:54:13 -04:00
|
|
|
if (errors.length <= 0) return;
|
|
|
|
|
2019-09-27 17:15:10 -04:00
|
|
|
let html = "";
|
|
|
|
let text = "";
|
|
|
|
|
2019-09-27 21:54:13 -04:00
|
|
|
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`;
|
2019-09-27 17:15:10 -04:00
|
|
|
}
|
2019-09-27 21:54:13 -04:00
|
|
|
html += "</ul>";
|
2019-09-27 17:15:10 -04:00
|
|
|
|
|
|
|
const message = {
|
|
|
|
msgtype: "m.notice",
|
|
|
|
body: text,
|
|
|
|
format: "org.matrix.custom.html",
|
|
|
|
formatted_body: html,
|
|
|
|
};
|
|
|
|
return this.client.sendMessage(this.managementRoomId, message);
|
|
|
|
}
|
|
|
|
}
|