mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-10-01 01:36:06 -04:00
Optionally perform permission checks on startup
This commit is contained in:
parent
383985c732
commit
7bd23a17d9
@ -17,7 +17,7 @@ Phase 2:
|
|||||||
* [ ] Redact messages on ban (optionally)
|
* [ ] Redact messages on ban (optionally)
|
||||||
* [x] More useful spam in management room
|
* [x] More useful spam in management room
|
||||||
* [ ] Command to import ACLs, etc from rooms
|
* [ ] Command to import ACLs, etc from rooms
|
||||||
* [ ] Vet rooms on startup option
|
* [x] Vet rooms on startup option
|
||||||
* [ ] Command to actually unban users (instead of leaving them stuck)
|
* [ ] Command to actually unban users (instead of leaving them stuck)
|
||||||
|
|
||||||
Phase 3:
|
Phase 3:
|
||||||
|
@ -37,6 +37,11 @@ verboseLogging: true
|
|||||||
# is the same as running !mjolnir sync immediately after startup.
|
# is the same as running !mjolnir sync immediately after startup.
|
||||||
syncOnStartup: true
|
syncOnStartup: true
|
||||||
|
|
||||||
|
# Set to false to prevent Mjolnir from checking its permissions on startup. This
|
||||||
|
# is recommended to be left as "true" to catch room permission problems (state
|
||||||
|
# resets, etc) before Mjolnir is needed.
|
||||||
|
verifyPermissionsOnStartup: true
|
||||||
|
|
||||||
# The room ID or alias where the bot's own personal ban list is kept. This is
|
# The room ID or alias where the bot's own personal ban list is kept. This is
|
||||||
# where the commands to manage a ban list end up being routed to. Note that
|
# where the commands to manage a ban list end up being routed to. Note that
|
||||||
# this room is NOT automatically added to the banLists list below - you will
|
# this room is NOT automatically added to the banLists list below - you will
|
||||||
|
@ -14,7 +14,7 @@ See the License for the specific language governing permissions and
|
|||||||
limitations under the License.
|
limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { MatrixClient } from "matrix-bot-sdk";
|
import { LogService, MatrixClient } from "matrix-bot-sdk";
|
||||||
import BanList, { ALL_RULE_TYPES } from "./models/BanList";
|
import BanList, { ALL_RULE_TYPES } from "./models/BanList";
|
||||||
import { applyServerAcls } from "./actions/ApplyAcl";
|
import { applyServerAcls } from "./actions/ApplyAcl";
|
||||||
import { RoomUpdateError } from "./models/RoomUpdateError";
|
import { RoomUpdateError } from "./models/RoomUpdateError";
|
||||||
@ -75,14 +75,91 @@ export class Mjolnir {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public start() {
|
public start() {
|
||||||
return this.client.start().then(() => {
|
return this.client.start().then(async () => {
|
||||||
if (config.syncOnStartup) {
|
this.currentState = STATE_CHECKING_PERMISSIONS;
|
||||||
this.client.sendNotice(this.managementRoomId, "Syncing lists...");
|
if (config.verifyPermissionsOnStartup) {
|
||||||
return this.syncLists();
|
await this.client.sendNotice(this.managementRoomId, "Checking permissions...");
|
||||||
|
await this.verifyPermissions();
|
||||||
}
|
}
|
||||||
|
}).then(async () => {
|
||||||
|
this.currentState = STATE_SYNCING;
|
||||||
|
if (config.syncOnStartup) {
|
||||||
|
await this.client.sendNotice(this.managementRoomId, "Syncing lists...");
|
||||||
|
await this.syncLists();
|
||||||
|
}
|
||||||
|
}).then(async () => {
|
||||||
|
this.currentState = STATE_RUNNING;
|
||||||
|
await this.client.sendNotice(this.managementRoomId, "Startup complete.");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async verifyPermissions() {
|
||||||
|
const ownUserId = await this.client.getUserId();
|
||||||
|
|
||||||
|
const errors: RoomUpdateError[] = [];
|
||||||
|
for (const roomId of Object.keys(this.protectedRooms)) {
|
||||||
|
try {
|
||||||
|
const powerLevels = await this.client.getRoomStateEvent(roomId, "m.room.power_levels", "");
|
||||||
|
if (!powerLevels) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error("Missing power levels state event");
|
||||||
|
}
|
||||||
|
|
||||||
|
function plDefault(val: number|undefined|null, def: number): number {
|
||||||
|
if (!val && val !== 0) return def;
|
||||||
|
return val;
|
||||||
|
}
|
||||||
|
|
||||||
|
const users = powerLevels['users'] || {};
|
||||||
|
const events = powerLevels['events'] || {};
|
||||||
|
const usersDefault = plDefault(powerLevels['users_default'], 0);
|
||||||
|
const stateDefault = plDefault(powerLevels['state_default'], 50);
|
||||||
|
const ban = plDefault(powerLevels['ban'], 50);
|
||||||
|
const kick = plDefault(powerLevels['kick'], 50);
|
||||||
|
const redact = plDefault(powerLevels['redact'], 50);
|
||||||
|
|
||||||
|
const userLevel = plDefault(users[ownUserId], usersDefault);
|
||||||
|
const aclLevel = plDefault(events["m.room.server_acl"], stateDefault);
|
||||||
|
|
||||||
|
// Wants: ban, kick, redact, m.room.server_acl
|
||||||
|
|
||||||
|
if (userLevel < ban) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error(`Missing power level for bans: ${userLevel} < ${ban}`);
|
||||||
|
}
|
||||||
|
if (userLevel < kick) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error(`Missing power level for kicks: ${userLevel} < ${kick}`);
|
||||||
|
}
|
||||||
|
if (userLevel < redact) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error(`Missing power level for redactions: ${userLevel} < ${redact}`);
|
||||||
|
}
|
||||||
|
if (userLevel < aclLevel) {
|
||||||
|
// noinspection ExceptionCaughtLocallyJS
|
||||||
|
throw new Error(`Missing power level for server ACLs: ${userLevel} < ${aclLevel}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Otherwise OK
|
||||||
|
} catch (e) {
|
||||||
|
LogService.error("Mjolnir", e);
|
||||||
|
errors.push({roomId, errorMessage: e.message || (e.body ? e.body.error : '<no message>')});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const hadErrors = await this.printActionResult(errors, "Permission errors in protected rooms:");
|
||||||
|
if (!hadErrors) {
|
||||||
|
const html = `<font color="#00cc00">All permissions look OK.</font>`;
|
||||||
|
const text = "All permissions look OK.";
|
||||||
|
await this.client.sendMessage(this.managementRoomId, {
|
||||||
|
msgtype: "m.notice",
|
||||||
|
body: text,
|
||||||
|
format: "org.matrix.custom.html",
|
||||||
|
formatted_body: html,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async syncLists() {
|
public async syncLists() {
|
||||||
for (const list of this.banLists) {
|
for (const list of this.banLists) {
|
||||||
await list.updateList();
|
await list.updateList();
|
||||||
|
@ -29,6 +29,7 @@ interface IConfig {
|
|||||||
managementRoom: string;
|
managementRoom: string;
|
||||||
verboseLogging: boolean;
|
verboseLogging: boolean;
|
||||||
syncOnStartup: boolean;
|
syncOnStartup: boolean;
|
||||||
|
verifyPermissionsOnStartup: boolean;
|
||||||
publishedBanListRoom: string;
|
publishedBanListRoom: string;
|
||||||
protectedRooms: string[]; // matrix.to urls
|
protectedRooms: string[]; // matrix.to urls
|
||||||
banLists: string[]; // matrix.to urls
|
banLists: string[]; // matrix.to urls
|
||||||
|
@ -90,7 +90,6 @@ LogService.setLogger(new RichConsoleLogger());
|
|||||||
const bot = new Mjolnir(client, managementRoomId, banListRoomId, protectedRooms, banLists);
|
const bot = new Mjolnir(client, managementRoomId, banListRoomId, protectedRooms, banLists);
|
||||||
await bot.start();
|
await bot.start();
|
||||||
|
|
||||||
// TODO: Check permissions for mjolnir in protected rooms
|
|
||||||
// TODO: Complain about permission changes in protected rooms (including after power levels change)
|
// TODO: Complain about permission changes in protected rooms (including after power levels change)
|
||||||
|
|
||||||
LogService.info("index", "Bot started!")
|
LogService.info("index", "Bot started!")
|
||||||
|
Loading…
Reference in New Issue
Block a user