mirror of
https://github.com/matrix-org/mjolnir.git
synced 2024-07-01 00:51:36 +00:00
WIP: First draft
This commit is contained in:
parent
b0262e9d6c
commit
a905a3d077
|
@ -40,6 +40,7 @@ import ManagementRoomOutput from "./ManagementRoomOutput";
|
|||
import { ProtectionManager } from "./protections/ProtectionManager";
|
||||
import { RoomMemberManager } from "./RoomMembers";
|
||||
import { CachingClient, WritableCache } from "./CachingClient";
|
||||
import { DEFAULT_LIST_EVENT_TYPE } from "./commands/SetDefaultBanListCommand";
|
||||
|
||||
export const STATE_NOT_STARTED = "not_started";
|
||||
export const STATE_CHECKING_PERMISSIONS = "checking_permissions";
|
||||
|
@ -50,8 +51,6 @@ const PROTECTED_ROOMS_EVENT_TYPE = "org.matrix.mjolnir.protected_rooms";
|
|||
const WATCHED_LISTS_EVENT_TYPE = "org.matrix.mjolnir.watched_lists";
|
||||
const WARN_UNPROTECTED_ROOM_EVENT_PREFIX = "org.matrix.mjolnir.unprotected_room_warning.for.";
|
||||
|
||||
type WatchedListsEvent = { references?: string[] } | null;
|
||||
|
||||
export class Mjolnir {
|
||||
public readonly client: CachingClient;
|
||||
private currentState: string = STATE_NOT_STARTED;
|
||||
|
@ -97,9 +96,10 @@ export class Mjolnir {
|
|||
/**
|
||||
* The list of protected rooms, as specified in the account data.
|
||||
*/
|
||||
private accountData: {
|
||||
public readonly accountData: {
|
||||
protectedRooms?: WritableCache<any>,
|
||||
watchedLists?: WritableCache<WatchedListsEvent>,
|
||||
watchedLists?: WritableCache<any>,
|
||||
defaultList?: WritableCache<any>,
|
||||
} = {};
|
||||
|
||||
/**
|
||||
|
@ -322,6 +322,7 @@ export class Mjolnir {
|
|||
LogService.warn("Mjolnir", extractRequestError(e));
|
||||
}
|
||||
this.accountData.watchedLists = await this.client.accountData(WATCHED_LISTS_EVENT_TYPE);
|
||||
this.accountData.defaultList = await this.client.accountData(DEFAULT_LIST_EVENT_TYPE);
|
||||
await this.buildWatchedPolicyLists();
|
||||
this.applyUnprotectedRooms();
|
||||
await this.protectionManager.start();
|
||||
|
@ -432,7 +433,7 @@ export class Mjolnir {
|
|||
* @param roomRef A reference (matrix.to URL) for the `PolicyList`.
|
||||
*/
|
||||
private async addPolicyList(roomId: string, roomRef: string): Promise<PolicyList> {
|
||||
const list = new PolicyList(roomId, roomRef, this.client.uncached);
|
||||
const list = new PolicyList(roomId, roomRef, this.client);
|
||||
this.ruleServer?.watch(list);
|
||||
list.on('PolicyList.batch', (...args) => this.protectedRoomsTracker.syncWithPolicyList(...args));
|
||||
await list.updateList();
|
||||
|
|
|
@ -152,7 +152,7 @@ export class ProtectedRooms {
|
|||
* @returns The list of errors encountered, for reporting to the management room.
|
||||
*/
|
||||
public async processRedactionQueue(roomId?: string): Promise<RoomUpdateError[]> {
|
||||
return await this.eventRedactionQueue.process(this.client.uncached, this.managementRoomOutput, roomId);
|
||||
return await this.eventRedactionQueue.process(this.client, this.managementRoomOutput, roomId);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -23,14 +23,14 @@ import { isListSetting } from "../protections/ProtectionSettings";
|
|||
export async function execEnableProtection(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
try {
|
||||
await mjolnir.protectionManager.enableProtection(parts[2]);
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
} catch (e) {
|
||||
LogService.error("ProtectionsCommands", extractRequestError(e));
|
||||
|
||||
const message = `Error enabling protection '${parts[0]}' - check the name and try again.`;
|
||||
const reply = RichReply.createFor(roomId, event, message, message);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ export async function execConfigSetProtection(roomId: string, event: any, mjolni
|
|||
|
||||
const reply = RichReply.createFor(roomId, event, message, message);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -117,7 +117,7 @@ export async function execConfigAddProtection(roomId: string, event: any, mjolni
|
|||
|
||||
const reply = RichReply.createFor(roomId, event, message, message);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -130,7 +130,7 @@ export async function execConfigRemoveProtection(roomId: string, event: any, mjo
|
|||
|
||||
const reply = RichReply.createFor(roomId, event, message, message);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -151,7 +151,7 @@ export async function execConfigGetProtection(roomId: string, event: any, mjolni
|
|||
const errMsg = `Unknown protection: ${parts[0]}`;
|
||||
const errReply = RichReply.createFor(roomId, event, errMsg, errMsg);
|
||||
errReply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, errReply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, errReply);
|
||||
return;
|
||||
}
|
||||
pickProtections = [parts[0]];
|
||||
|
@ -191,13 +191,13 @@ export async function execConfigGetProtection(roomId: string, event: any, mjolni
|
|||
|
||||
const reply = RichReply.createFor(roomId, event, text, html);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
||||
// !mjolnir disable <protection>
|
||||
export async function execDisableProtection(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
await mjolnir.protectionManager.disableProtection(parts[2]);
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
||||
// !mjolnir protections
|
||||
|
@ -217,5 +217,5 @@ export async function execListProtections(roomId: string, event: any, mjolnir: M
|
|||
|
||||
const reply = RichReply.createFor(roomId, event, text, html);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjo
|
|||
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]);
|
||||
roomAlias = await mjolnir.client.uncached.resolveRoom(parts[3]);
|
||||
if (parts.length > 4) {
|
||||
limit = Number.parseInt(parts[4], 10);
|
||||
}
|
||||
|
@ -33,21 +33,21 @@ export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjo
|
|||
// Make sure we always have a limit set
|
||||
if (isNaN(limit)) limit = 1000;
|
||||
|
||||
const processingReactionId = await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], 'In Progress');
|
||||
const processingReactionId = await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['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, event['event_id'], '✅');
|
||||
await mjolnir.client.redactEvent(roomId, processingReactionId, 'done processing command');
|
||||
const targetRoomId = await mjolnir.client.uncached.resolveRoom(parsed.roomIdOrAlias);
|
||||
await mjolnir.client.uncached.redactEvent(targetRoomId, parsed.eventId);
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.redactEvent(roomId, processingReactionId, 'done processing command');
|
||||
return;
|
||||
}
|
||||
|
||||
const targetRoomIds = roomAlias ? [roomAlias] : mjolnir.protectedRoomsTracker.getProtectedRooms();
|
||||
await redactUserMessagesIn(mjolnir.client, mjolnir.managementRoomOutput, userId, targetRoomIds, limit);
|
||||
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.redactEvent(roomId, processingReactionId, 'done processing');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.redactEvent(roomId, processingReactionId, 'done processing');
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ export async function execSetDefaultListCommand(roomId: string, event: any, mjol
|
|||
const replyText = "No ban list with that shortcode was found.";
|
||||
const reply = RichReply.createFor(roomId, event, replyText, replyText);
|
||||
reply["msgtype"] = "m.notice";
|
||||
mjolnir.client.sendMessage(roomId, reply);
|
||||
mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
await mjolnir.client.setAccountData(DEFAULT_LIST_EVENT_TYPE, { shortcode });
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.accountData.defaultList!.set({ shortcode });
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
|
|
@ -23,11 +23,11 @@ export async function execSetPowerLevelCommand(roomId: string, event: any, mjoln
|
|||
const level = Math.round(Number(parts[3]));
|
||||
const inRoom = parts[4];
|
||||
|
||||
let targetRooms = inRoom ? [await mjolnir.client.resolveRoom(inRoom)] : mjolnir.protectedRoomsTracker.getProtectedRooms();
|
||||
let targetRooms = inRoom ? [await mjolnir.client.uncached.resolveRoom(inRoom)] : mjolnir.protectedRoomsTracker.getProtectedRooms();
|
||||
|
||||
for (const targetRoomId of targetRooms) {
|
||||
try {
|
||||
await mjolnir.client.setUserPowerLevel(victim, targetRoomId, level);
|
||||
await mjolnir.client.uncached.setUserPowerLevel(victim, targetRoomId, level);
|
||||
} catch (e) {
|
||||
const message = e.message || (e.body ? e.body.error : '<no message>');
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "SetPowerLevelCommand", `Failed to set power level of ${victim} to ${level} in ${targetRoomId}: ${message}`, targetRoomId);
|
||||
|
@ -35,5 +35,5 @@ export async function execSetPowerLevelCommand(roomId: string, event: any, mjoln
|
|||
}
|
||||
}
|
||||
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
|
|
@ -27,10 +27,10 @@ export async function execShutdownRoomCommand(roomId: string, event: any, mjolni
|
|||
const message = "I am not a Synapse administrator, or the endpoint is blocked";
|
||||
const reply = RichReply.createFor(roomId, event, message, message);
|
||||
reply['msgtype'] = "m.notice";
|
||||
mjolnir.client.sendMessage(roomId, reply);
|
||||
mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
return;
|
||||
}
|
||||
|
||||
await mjolnir.shutdownSynapseRoom(await mjolnir.client.resolveRoom(victim), reason);
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.shutdownSynapseRoom(await mjolnir.client.uncached.resolveRoom(victim), reason);
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
|
|
@ -99,14 +99,14 @@ function getTokenAsString(name: string, token: ParseEntry): {error: string}|{ok:
|
|||
export async function execSinceCommand(destinationRoomId: string, event: any, mjolnir: Mjolnir, tokens: ParseEntry[]) {
|
||||
let result = await execSinceCommandAux(destinationRoomId, event, mjolnir, tokens);
|
||||
if ("error" in result) {
|
||||
mjolnir.client.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '❌');
|
||||
mjolnir.client.uncached.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '❌');
|
||||
mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "SinceCommand", result.error);
|
||||
const reply = RichReply.createFor(destinationRoomId, event, result.error, htmlEscape(result.error));
|
||||
reply["msgtype"] = "m.notice";
|
||||
/* no need to await */ mjolnir.client.sendMessage(destinationRoomId, reply);
|
||||
/* no need to await */ mjolnir.client.uncached.sendMessage(destinationRoomId, reply);
|
||||
} else {
|
||||
// Details have already been printed.
|
||||
mjolnir.client.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '✅');
|
||||
mjolnir.client.uncached.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '✅');
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -200,7 +200,7 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
}
|
||||
continue;
|
||||
} else if (maybeRoom.startsWith("#") || maybeRoom.startsWith("!")) {
|
||||
const roomId = await mjolnir.client.resolveRoom(maybeRoom);
|
||||
const roomId = await mjolnir.client.uncached.resolveRoom(maybeRoom);
|
||||
if (!protectedRooms.has(roomId)) {
|
||||
return mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "SinceCommand", `This room is not protected: ${htmlEscape(roomId)}.`);
|
||||
}
|
||||
|
@ -220,7 +220,7 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
};
|
||||
}
|
||||
|
||||
const progressEventId = await mjolnir.client.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '⏳');
|
||||
const progressEventId = await mjolnir.client.uncached.unstableApis.addReactionToEvent(destinationRoomId, event['event_id'], '⏳');
|
||||
const reason: string | undefined = reasonParts?.join(" ");
|
||||
|
||||
for (let targetRoomId of rooms) {
|
||||
|
@ -235,7 +235,7 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
case Action.Kick: {
|
||||
for (let join of recentJoins) {
|
||||
try {
|
||||
await mjolnir.client.kickUser(join.userId, targetRoomId, reason);
|
||||
await mjolnir.client.uncached.kickUser(join.userId, targetRoomId, reason);
|
||||
results.succeeded.push(join.userId);
|
||||
} catch (ex) {
|
||||
LogService.warn("SinceCommand", "Error while attempting to kick user", ex);
|
||||
|
@ -248,7 +248,7 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
case Action.Ban: {
|
||||
for (let join of recentJoins) {
|
||||
try {
|
||||
await mjolnir.client.banUser(join.userId, targetRoomId, reason);
|
||||
await mjolnir.client.uncached.banUser(join.userId, targetRoomId, reason);
|
||||
results.succeeded.push(join.userId);
|
||||
} catch (ex) {
|
||||
LogService.warn("SinceCommand", "Error while attempting to ban user", ex);
|
||||
|
@ -259,13 +259,13 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
return formatResult("ban", targetRoomId, recentJoins, results);
|
||||
}
|
||||
case Action.Mute: {
|
||||
const powerLevels = await mjolnir.client.getRoomStateEvent(targetRoomId, "m.room.power_levels", "") as {users: Record</* userId */ string, number>};
|
||||
const powerLevels = await mjolnir.client.uncached.getRoomStateEvent(targetRoomId, "m.room.power_levels", "") as {users: Record</* userId */ string, number>};
|
||||
|
||||
for (let join of recentJoins) {
|
||||
powerLevels.users[join.userId] = -1;
|
||||
}
|
||||
try {
|
||||
await mjolnir.client.sendStateEvent(targetRoomId, "m.room.power_levels", "", powerLevels);
|
||||
await mjolnir.client.uncached.sendStateEvent(targetRoomId, "m.room.power_levels", "", powerLevels);
|
||||
for (let join of recentJoins) {
|
||||
results.succeeded.push(join.userId);
|
||||
}
|
||||
|
@ -279,13 +279,13 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
return formatResult("mute", targetRoomId, recentJoins, results);
|
||||
}
|
||||
case Action.Unmute: {
|
||||
const powerLevels = await mjolnir.client.getRoomStateEvent(targetRoomId, "m.room.power_levels", "") as {users: Record</* userId */ string, number>, users_default?: number};
|
||||
const powerLevels = await mjolnir.client.uncached.getRoomStateEvent(targetRoomId, "m.room.power_levels", "") as {users: Record</* userId */ string, number>, users_default?: number};
|
||||
for (let join of recentJoins) {
|
||||
// Restore default powerlevel.
|
||||
delete powerLevels.users[join.userId];
|
||||
}
|
||||
try {
|
||||
await mjolnir.client.sendStateEvent(targetRoomId, "m.room.power_levels", "", powerLevels);
|
||||
await mjolnir.client.uncached.sendStateEvent(targetRoomId, "m.room.power_levels", "", powerLevels);
|
||||
for (let join of recentJoins) {
|
||||
results.succeeded.push(join.userId);
|
||||
}
|
||||
|
@ -303,10 +303,10 @@ async function execSinceCommandAux(destinationRoomId: string, event: any, mjolni
|
|||
|
||||
const reply = RichReply.createFor(destinationRoomId, event, text, html);
|
||||
reply["msgtype"] = "m.notice";
|
||||
/* no need to await */ mjolnir.client.sendMessage(destinationRoomId, reply);
|
||||
/* no need to await */ mjolnir.client.uncached.sendMessage(destinationRoomId, reply);
|
||||
}
|
||||
|
||||
await mjolnir.client.redactEvent(destinationRoomId, progressEventId);
|
||||
await mjolnir.client.uncached.redactEvent(destinationRoomId, progressEventId);
|
||||
return {ok: undefined};
|
||||
}
|
||||
|
||||
|
|
|
@ -86,7 +86,7 @@ async function showMjolnirStatus(roomId: string, event: any, mjolnir: Mjolnir) {
|
|||
|
||||
const reply = RichReply.createFor(roomId, event, text, html);
|
||||
reply["msgtype"] = "m.notice";
|
||||
return mjolnir.client.sendMessage(roomId, reply);
|
||||
return mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
||||
async function showProtectionStatus(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
|
||||
|
@ -108,7 +108,7 @@ async function showProtectionStatus(roomId: string, event: any, mjolnir: Mjolnir
|
|||
}
|
||||
const reply = RichReply.createFor(roomId, event, text, html);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -149,7 +149,7 @@ async function showJoinsStatus(destinationRoomId: string, event: any, mjolnir: M
|
|||
const maxAgeHumanReadable = HUMANIZER.humanize(maxAgeMS, HUMANIZER_OPTIONS);
|
||||
let targetRoomId;
|
||||
try {
|
||||
targetRoomId = await mjolnir.client.resolveRoom(targetRoomAliasOrId);
|
||||
targetRoomId = await mjolnir.client.uncached.resolveRoom(targetRoomAliasOrId);
|
||||
} catch (ex) {
|
||||
return {
|
||||
html: `Cannot resolve room ${htmlEscape(targetRoomAliasOrId)}.`,
|
||||
|
@ -171,6 +171,6 @@ async function showJoinsStatus(destinationRoomId: string, event: any, mjolnir: M
|
|||
})();
|
||||
const reply = RichReply.createFor(destinationRoomId, event, text, html);
|
||||
reply["msgtype"] = "m.notice";
|
||||
return mjolnir.client.sendMessage(destinationRoomId, reply);
|
||||
return mjolnir.client.uncached.sendMessage(destinationRoomId, reply);
|
||||
}
|
||||
|
||||
|
|
|
@ -16,9 +16,8 @@ limitations under the License.
|
|||
|
||||
import { Mjolnir } from "../Mjolnir";
|
||||
import PolicyList from "../models/PolicyList";
|
||||
import { extractRequestError, LogLevel, LogService, MatrixGlob, RichReply } from "matrix-bot-sdk";
|
||||
import { LogLevel, MatrixGlob, RichReply } from "matrix-bot-sdk";
|
||||
import { RULE_ROOM, RULE_SERVER, RULE_USER, USER_RULE_TYPES } from "../models/ListRule";
|
||||
import { DEFAULT_LIST_EVENT_TYPE } from "./SetDefaultBanListCommand";
|
||||
|
||||
interface Arguments {
|
||||
list: PolicyList | null;
|
||||
|
@ -29,16 +28,11 @@ interface Arguments {
|
|||
|
||||
// Exported for tests
|
||||
export async function parseArguments(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]): Promise<Arguments | null> {
|
||||
let defaultShortcode: string | null = null;
|
||||
try {
|
||||
const data: { shortcode: string } = await mjolnir.client.getAccountData(DEFAULT_LIST_EVENT_TYPE);
|
||||
defaultShortcode = data['shortcode'];
|
||||
} catch (e) {
|
||||
LogService.warn("UnbanBanCommand", "Non-fatal error getting default ban list");
|
||||
LogService.warn("UnbanBanCommand", extractRequestError(e));
|
||||
|
||||
// Assume no default.
|
||||
let data = mjolnir.accountData.defaultList!.get();
|
||||
if (!data || !("shortcode" in data) || typeof data["shortcode"] !== "string") {
|
||||
data = { shortcode: null };
|
||||
}
|
||||
let defaultShortcode: string | null = data['shortcode'];
|
||||
|
||||
let argumentIndex = 2;
|
||||
let ruleType: string | null = null;
|
||||
|
@ -101,7 +95,7 @@ export async function parseArguments(roomId: string, event: any, mjolnir: Mjolni
|
|||
if (replyMessage) {
|
||||
const reply = RichReply.createFor(roomId, event, replyMessage, replyMessage);
|
||||
reply["msgtype"] = "m.notice";
|
||||
await mjolnir.client.sendMessage(roomId, reply);
|
||||
await mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
@ -119,7 +113,7 @@ export async function execBanCommand(roomId: string, event: any, mjolnir: Mjolni
|
|||
if (!bits) return; // error already handled
|
||||
|
||||
await bits.list!.banEntity(bits.ruleType!, bits.entity, bits.reason);
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
||||
// !mjolnir unban <shortcode> <user|server|room> <glob> [apply:t/f]
|
||||
|
@ -134,7 +128,7 @@ export async function execUnbanCommand(roomId: string, event: any, mjolnir: Mjol
|
|||
await mjolnir.managementRoomOutput.logMessage(LogLevel.INFO, "UnbanBanCommand", "Unbanning users that match glob: " + bits.entity);
|
||||
let unbannedSomeone = false;
|
||||
for (const protectedRoomId of mjolnir.protectedRoomsTracker.getProtectedRooms()) {
|
||||
const members = await mjolnir.client.getRoomMembers(protectedRoomId, undefined, ['ban'], undefined);
|
||||
const members = await mjolnir.client.uncached.getRoomMembers(protectedRoomId, undefined, ['ban'], undefined);
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.DEBUG, "UnbanBanCommand", `Found ${members.length} banned user(s)`);
|
||||
for (const member of members) {
|
||||
const victim = member.membershipFor;
|
||||
|
@ -143,7 +137,7 @@ export async function execUnbanCommand(roomId: string, event: any, mjolnir: Mjol
|
|||
await mjolnir.managementRoomOutput.logMessage(LogLevel.DEBUG, "UnbanBanCommand", `Unbanning ${victim} in ${protectedRoomId}`, protectedRoomId);
|
||||
|
||||
if (!mjolnir.config.noop) {
|
||||
await mjolnir.client.unbanUser(victim, protectedRoomId);
|
||||
await mjolnir.client.uncached.unbanUser(victim, protectedRoomId);
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "UnbanBanCommand", `Attempted to unban ${victim} in ${protectedRoomId} but Mjolnir is running in no-op mode`, protectedRoomId);
|
||||
}
|
||||
|
@ -159,5 +153,5 @@ export async function execUnbanCommand(roomId: string, event: any, mjolnir: Mjol
|
|||
}
|
||||
}
|
||||
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
|
|
@ -24,10 +24,10 @@ export async function execWatchCommand(roomId: string, event: any, mjolnir: Mjol
|
|||
const replyText = "Cannot watch list due to error - is that a valid room alias?";
|
||||
const reply = RichReply.createFor(roomId, event, replyText, replyText);
|
||||
reply["msgtype"] = "m.notice";
|
||||
mjolnir.client.sendMessage(roomId, reply);
|
||||
mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
return;
|
||||
}
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
||||
// !mjolnir unwatch <room alias or ID>
|
||||
|
@ -37,8 +37,8 @@ export async function execUnwatchCommand(roomId: string, event: any, mjolnir: Mj
|
|||
const replyText = "Cannot unwatch list due to error - is that a valid room alias?";
|
||||
const reply = RichReply.createFor(roomId, event, replyText, replyText);
|
||||
reply["msgtype"] = "m.notice";
|
||||
mjolnir.client.sendMessage(roomId, reply);
|
||||
mjolnir.client.uncached.sendMessage(roomId, reply);
|
||||
return;
|
||||
}
|
||||
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
await mjolnir.client.uncached.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
|
||||
}
|
||||
|
|
|
@ -14,9 +14,10 @@ See the License for the specific language governing permissions and
|
|||
limitations under the License.
|
||||
*/
|
||||
|
||||
import { extractRequestError, LogService, MatrixClient, UserID } from "matrix-bot-sdk";
|
||||
import { extractRequestError, LogService, UserID } from "matrix-bot-sdk";
|
||||
import { EventEmitter } from "events";
|
||||
import { ALL_RULE_TYPES, EntityType, ListRule, Recommendation, ROOM_RULE_TYPES, RULE_ROOM, RULE_SERVER, RULE_USER, SERVER_RULE_TYPES, USER_RULE_TYPES } from "./ListRule";
|
||||
import { CachingClient } from "../CachingClient";
|
||||
|
||||
export const SHORTCODE_EVENT_TYPE = "org.matrix.mjolnir.shortcode";
|
||||
|
||||
|
@ -92,7 +93,7 @@ class PolicyList extends EventEmitter {
|
|||
* @param roomRef A sharable/clickable matrix URL that refers to the room.
|
||||
* @param client A matrix client that is used to read the state of the room when `updateList` is called.
|
||||
*/
|
||||
constructor(public readonly roomId: string, public readonly roomRef: string, private client: MatrixClient) {
|
||||
constructor(public readonly roomId: string, public readonly roomRef: string, private client: CachingClient) {
|
||||
super();
|
||||
this.batcher = new UpdateBatcher(this);
|
||||
}
|
||||
|
@ -156,7 +157,7 @@ class PolicyList extends EventEmitter {
|
|||
public set listShortcode(newShortcode: string) {
|
||||
const currentShortcode = this.shortcode;
|
||||
this.shortcode = newShortcode;
|
||||
this.client.sendStateEvent(this.roomId, SHORTCODE_EVENT_TYPE, '', { shortcode: this.shortcode }).catch(err => {
|
||||
this.client.uncached.sendStateEvent(this.roomId, SHORTCODE_EVENT_TYPE, '', { shortcode: this.shortcode }).catch(err => {
|
||||
LogService.error("PolicyList", extractRequestError(err));
|
||||
if (this.shortcode === newShortcode) this.shortcode = currentShortcode;
|
||||
});
|
||||
|
@ -219,7 +220,7 @@ class PolicyList extends EventEmitter {
|
|||
public async banEntity(ruleType: string, entity: string, reason?: string): Promise<void> {
|
||||
// '@' at the beginning of state keys is reserved.
|
||||
const stateKey = ruleType === RULE_USER ? '_' + entity.substring(1) : entity;
|
||||
const event_id = await this.client.sendStateEvent(this.roomId, ruleType, stateKey, {
|
||||
const event_id = await this.client.uncached.sendStateEvent(this.roomId, ruleType, stateKey, {
|
||||
entity,
|
||||
recommendation: Recommendation.Ban,
|
||||
reason: reason || '<no reason supplied>',
|
||||
|
@ -248,14 +249,14 @@ class PolicyList extends EventEmitter {
|
|||
break;
|
||||
}
|
||||
const sendNullState = async (stateType: string, stateKey: string) => {
|
||||
const event_id = await this.client.sendStateEvent(this.roomId, stateType, stateKey, {});
|
||||
const event_id = await this.client.uncached.sendStateEvent(this.roomId, stateType, stateKey, {});
|
||||
this.updateForEvent(event_id);
|
||||
}
|
||||
const removeRule = async (rule: ListRule): Promise<void> => {
|
||||
const stateKey = rule.sourceEvent.state_key;
|
||||
// We can't cheat and check our state cache because we normalize the event types to the most recent version.
|
||||
const typesToRemove = (await Promise.all(
|
||||
typesToCheck.map(stateType => this.client.getRoomStateEvent(this.roomId, stateType, stateKey)
|
||||
typesToCheck.map(stateType => this.client.uncached.getRoomStateEvent(this.roomId, stateType, stateKey)
|
||||
.then(_ => stateType) // We need the state type as getRoomState only returns the content, not the top level.
|
||||
.catch(e => e.statusCode === 404 ? null : Promise.reject(e))))
|
||||
).filter(e => e); // remove nulls. I don't know why TS still thinks there can be nulls after this??
|
||||
|
@ -277,7 +278,7 @@ class PolicyList extends EventEmitter {
|
|||
public async updateList(): Promise<ListRuleChange[]> {
|
||||
let changes: ListRuleChange[] = [];
|
||||
|
||||
const state = await this.client.getRoomState(this.roomId);
|
||||
const state = await this.client.uncached.getRoomState(this.roomId);
|
||||
for (const event of state) {
|
||||
if (event['state_key'] === '' && event['type'] === SHORTCODE_EVENT_TYPE) {
|
||||
this.shortcode = (event['content'] || {})['shortcode'] || null;
|
||||
|
|
|
@ -64,7 +64,7 @@ export class BasicFlooding extends Protection {
|
|||
if (messageCount >= this.settings.maxPerMinute.value) {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "BasicFlooding", `Banning ${event['sender']} in ${roomId} for flooding (${messageCount} messages in the last minute)`, roomId);
|
||||
if (!mjolnir.config.noop) {
|
||||
await mjolnir.client.banUser(event['sender'], roomId, "spam");
|
||||
await mjolnir.client.uncached.banUser(event['sender'], roomId, "spam");
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "BasicFlooding", `Tried to ban ${event['sender']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
|
||||
}
|
||||
|
@ -76,7 +76,7 @@ export class BasicFlooding extends Protection {
|
|||
// Redact all the things the user said too
|
||||
if (!mjolnir.config.noop) {
|
||||
for (const eventId of forUser.map(e => e.eventId)) {
|
||||
await mjolnir.client.redactEvent(roomId, eventId, "spam");
|
||||
await mjolnir.client.uncached.redactEvent(roomId, eventId, "spam");
|
||||
}
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "BasicFlooding", `Tried to redact messages for ${event['sender']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
|
||||
|
|
|
@ -58,7 +58,7 @@ export class FirstMessageIsImage extends Protection {
|
|||
if (isMedia && this.justJoined[roomId].includes(event['sender'])) {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "FirstMessageIsImage", `Banning ${event['sender']} for posting an image as the first thing after joining in ${roomId}.`);
|
||||
if (!mjolnir.config.noop) {
|
||||
await mjolnir.client.banUser(event['sender'], roomId, "spam");
|
||||
await mjolnir.client.uncached.banUser(event['sender'], roomId, "spam");
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "FirstMessageIsImage", `Tried to ban ${event['sender']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
|
||||
}
|
||||
|
@ -69,7 +69,7 @@ export class FirstMessageIsImage extends Protection {
|
|||
|
||||
// Redact the event
|
||||
if (!mjolnir.config.noop) {
|
||||
await mjolnir.client.redactEvent(roomId, event['event_id'], "spam");
|
||||
await mjolnir.client.uncached.redactEvent(roomId, event['event_id'], "spam");
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "FirstMessageIsImage", `Tried to redact ${event['event_id']} in ${roomId} but Mjolnir is running in no-op mode`, roomId);
|
||||
}
|
||||
|
|
|
@ -89,7 +89,7 @@ export class JoinWaveShortCircuit extends Protection {
|
|||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "JoinWaveShortCircuit", `Setting ${roomId} to invite-only as more than ${this.settings.maxPer.value} users have joined over the last ${this.settings.timescaleMinutes.value} minutes (since ${this.joinBuckets[roomId].lastBucketStart})`, roomId);
|
||||
|
||||
if (!mjolnir.config.noop) {
|
||||
await mjolnir.client.sendStateEvent(roomId, "m.room.join_rules", "", {"join_rule": "invite"})
|
||||
await mjolnir.client.uncached.sendStateEvent(roomId, "m.room.join_rules", "", {"join_rule": "invite"})
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "JoinWaveShortCircuit", `Tried to set ${roomId} to invite-only, but Mjolnir is running in no-op mode`, roomId);
|
||||
}
|
||||
|
|
|
@ -73,16 +73,16 @@ export class TrustedReporters extends Protection {
|
|||
}
|
||||
if (reporters.size === this.settings.redactThreshold.value) {
|
||||
met.push("redact");
|
||||
await mjolnir.client.redactEvent(roomId, event.id, "abuse detected");
|
||||
await mjolnir.client.uncached.redactEvent(roomId, event.id, "abuse detected");
|
||||
}
|
||||
if (reporters.size === this.settings.banThreshold.value) {
|
||||
met.push("ban");
|
||||
await mjolnir.client.banUser(event.userId, roomId, "abuse detected");
|
||||
await mjolnir.client.uncached.banUser(event.userId, roomId, "abuse detected");
|
||||
}
|
||||
|
||||
|
||||
if (met.length > 0) {
|
||||
await mjolnir.client.sendMessage(mjolnir.config.managementRoom, {
|
||||
await mjolnir.client.uncached.sendMessage(mjolnir.config.managementRoom, {
|
||||
msgtype: "m.notice",
|
||||
body: `message ${event.id} reported by ${[...reporters].join(', ')}. `
|
||||
+ `actions: ${met.join(', ')}`
|
||||
|
|
|
@ -13,11 +13,12 @@ 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 { LogLevel, MatrixClient } from "matrix-bot-sdk"
|
||||
import { LogLevel } from "matrix-bot-sdk"
|
||||
import { ERROR_KIND_FATAL } from "../ErrorCache";
|
||||
import { RoomUpdateError } from "../models/RoomUpdateError";
|
||||
import { redactUserMessagesIn } from "../utils";
|
||||
import ManagementRoomOutput from "../ManagementRoomOutput";
|
||||
import { CachingClient } from "../CachingClient";
|
||||
|
||||
export interface QueuedRedaction {
|
||||
/** The room which the redaction will take place in. */
|
||||
|
@ -27,7 +28,7 @@ export interface QueuedRedaction {
|
|||
* Called by the EventRedactionQueue.
|
||||
* @param client A MatrixClient to use to carry out the redaction.
|
||||
*/
|
||||
redact(client: MatrixClient, managementRoom: ManagementRoomOutput): Promise<void>
|
||||
redact(client: CachingClient, managementRoom: ManagementRoomOutput): Promise<void>
|
||||
/**
|
||||
* Used to test whether the redaction is the equivalent to another redaction.
|
||||
* @param redaction Another QueuedRedaction to test if this redaction is an equivalent to.
|
||||
|
@ -47,7 +48,7 @@ export class RedactUserInRoom implements QueuedRedaction {
|
|||
this.roomId = roomId;
|
||||
}
|
||||
|
||||
public async redact(client: MatrixClient, managementRoom: ManagementRoomOutput) {
|
||||
public async redact(client: CachingClient, managementRoom: ManagementRoomOutput) {
|
||||
await managementRoom.logMessage(LogLevel.DEBUG, "Mjolnir", `Redacting events from ${this.userId} in room ${this.roomId}.`);
|
||||
await redactUserMessagesIn(client, managementRoom, this.userId, [this.roomId]);
|
||||
}
|
||||
|
@ -107,7 +108,7 @@ export class EventRedactionQueue {
|
|||
* @param limitToRoomId If the roomId is provided, only redactions for that room will be processed.
|
||||
* @returns A description of any errors encountered by each QueuedRedaction that was processed.
|
||||
*/
|
||||
public async process(client: MatrixClient, managementRoom: ManagementRoomOutput, limitToRoomId?: string): Promise<RoomUpdateError[]> {
|
||||
public async process(client: CachingClient, managementRoom: ManagementRoomOutput, limitToRoomId?: string): Promise<RoomUpdateError[]> {
|
||||
const errors: RoomUpdateError[] = [];
|
||||
const redact = async (currentBatch: QueuedRedaction[]) => {
|
||||
for (const redaction of currentBatch) {
|
||||
|
|
|
@ -43,7 +43,7 @@ export class UnlistedUserRedactionQueue {
|
|||
try {
|
||||
LogService.info("AutomaticRedactionQueue", `Redacting event because the user is listed as bad: ${permalink}`)
|
||||
if (!mjolnir.config.noop) {
|
||||
await mjolnir.client.redactEvent(roomId, event['event_id']);
|
||||
await mjolnir.client.uncached.redactEvent(roomId, event['event_id']);
|
||||
} else {
|
||||
await mjolnir.managementRoomOutput.logMessage(LogLevel.WARN, "AutomaticRedactionQueue", `Tried to redact ${permalink} but Mjolnir is running in no-op mode`);
|
||||
}
|
||||
|
|
10
src/utils.ts
10
src/utils.ts
|
@ -17,7 +17,6 @@ limitations under the License.
|
|||
import {
|
||||
LogLevel,
|
||||
LogService,
|
||||
MatrixClient,
|
||||
MatrixGlob,
|
||||
getRequestFn,
|
||||
setRequestFn,
|
||||
|
@ -25,6 +24,7 @@ import {
|
|||
import { ClientRequest, IncomingMessage } from "http";
|
||||
import { default as parseDuration } from "parse-duration";
|
||||
import ManagementRoomOutput from "./ManagementRoomOutput";
|
||||
import { CachingClient } from "./CachingClient";
|
||||
|
||||
// Define a few aliases to simplify parsing durations.
|
||||
|
||||
|
@ -77,7 +77,7 @@ export function isTrueJoinEvent(event: any): boolean {
|
|||
* @param limit The number of messages to redact from most recent first. If the limit is reached then no further messages will be redacted.
|
||||
* @param noop Whether to operate in noop mode.
|
||||
*/
|
||||
export async function redactUserMessagesIn(client: MatrixClient, managementRoom: ManagementRoomOutput, userIdOrGlob: string, targetRoomIds: string[], limit = 1000, noop = false) {
|
||||
export async function redactUserMessagesIn(client: CachingClient, managementRoom: ManagementRoomOutput, userIdOrGlob: string, targetRoomIds: string[], limit = 1000, noop = false) {
|
||||
for (const targetRoomId of targetRoomIds) {
|
||||
await managementRoom.logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Fetching sent messages for ${userIdOrGlob} in ${targetRoomId} to redact...`, targetRoomId);
|
||||
|
||||
|
@ -85,7 +85,7 @@ export async function redactUserMessagesIn(client: MatrixClient, managementRoom:
|
|||
for (const victimEvent of eventsToRedact) {
|
||||
await managementRoom.logMessage(LogLevel.DEBUG, "utils#redactUserMessagesIn", `Redacting ${victimEvent['event_id']} in ${targetRoomId}`, targetRoomId);
|
||||
if (!noop) {
|
||||
await client.redactEvent(targetRoomId, victimEvent['event_id']);
|
||||
await client.uncached.redactEvent(targetRoomId, victimEvent['event_id']);
|
||||
} else {
|
||||
await managementRoom.logMessage(LogLevel.WARN, "utils#redactUserMessagesIn", `Tried to redact ${victimEvent['event_id']} in ${targetRoomId} but Mjolnir is running in no-op mode`, targetRoomId);
|
||||
}
|
||||
|
@ -110,7 +110,7 @@ export async function redactUserMessagesIn(client: MatrixClient, managementRoom:
|
|||
* The callback will only be called if there are any relevant events.
|
||||
* @returns {Promise<void>} Resolves when either: the limit has been reached, no relevant events could be found or there is no more timeline to paginate.
|
||||
*/
|
||||
export async function getMessagesByUserIn(client: MatrixClient, sender: string, roomId: string, limit: number, cb: (events: any[]) => void): Promise<void> {
|
||||
export async function getMessagesByUserIn(client: CachingClient, sender: string, roomId: string, limit: number, cb: (events: any[]) => void): Promise<void> {
|
||||
const isGlob = sender.includes("*");
|
||||
const roomEventFilter = {
|
||||
rooms: [roomId],
|
||||
|
@ -154,7 +154,7 @@ export async function getMessagesByUserIn(client: MatrixClient, sender: string,
|
|||
... from ? { from } : {}
|
||||
};
|
||||
LogService.info("utils", "Backfilling with token: " + from);
|
||||
return client.doRequest("GET", `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`, qs);
|
||||
return client.uncached.doRequest("GET", `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/messages`, qs);
|
||||
}
|
||||
|
||||
let processed = 0;
|
||||
|
|
|
@ -7,6 +7,7 @@ import { getFirstReaction } from "./commands/commandUtils";
|
|||
import { getMessagesByUserIn } from "../../src/utils";
|
||||
import { Mjolnir } from "../../src/Mjolnir";
|
||||
import { ALL_RULE_TYPES, RULE_SERVER, RULE_USER, SERVER_RULE_TYPES } from "../../src/models/ListRule";
|
||||
import { CachingClient } from "../../src/CachingClient";
|
||||
|
||||
/**
|
||||
* Create a policy rule in a policy room.
|
||||
|
@ -30,32 +31,32 @@ describe("Test: Updating the PolicyList", function() {
|
|||
it("Calculates what has changed correctly.", async function() {
|
||||
this.timeout(10000);
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
const banListId = await mjolnir.client.createRoom({ invite: [await moderator.getUserId()] });
|
||||
const moderator: MatrixClient = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
const banListId = await mjolnir.client.uncached.createRoom({ invite: [await moderator.getUserId()] });
|
||||
const banList = new PolicyList(banListId, banListId, mjolnir.client);
|
||||
await mjolnir.client.setUserPowerLevel(await moderator.getUserId(), banListId, 100);
|
||||
await mjolnir.client.uncached.setUserPowerLevel(await moderator.getUserId(), banListId, 100);
|
||||
|
||||
assert.equal(banList.allRules.length, 0);
|
||||
|
||||
// Test adding a new rule
|
||||
await createPolicyRule(mjolnir.client, banListId, RULE_USER, '@added:localhost:9999', '');
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, '@added:localhost:9999', '');
|
||||
let changes: ListRuleChange[] = await banList.updateList();
|
||||
assert.equal(changes.length, 1, 'There should only be one change');
|
||||
assert.equal(changes[0].changeType, ChangeType.Added);
|
||||
assert.equal(changes[0].sender, await mjolnir.client.getUserId());
|
||||
assert.equal(changes[0].sender, await mjolnir.client.uncached.getUserId());
|
||||
assert.equal(banList.userRules.length, 1);
|
||||
assert.equal(banList.allRules.length, 1);
|
||||
|
||||
// Test modifiying a rule
|
||||
let originalEventId = await createPolicyRule(mjolnir.client, banListId, RULE_USER, '@modified:localhost:9999', '');
|
||||
let originalEventId = await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, '@modified:localhost:9999', '');
|
||||
await banList.updateList();
|
||||
let modifyingEventId = await createPolicyRule(mjolnir.client, banListId, RULE_USER, '@modified:localhost:9999', 'modified reason');
|
||||
let modifyingEventId = await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, '@modified:localhost:9999', 'modified reason');
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Modified);
|
||||
assert.equal(changes[0].previousState['event_id'], originalEventId, 'There should be a previous state event for a modified rule');
|
||||
assert.equal(changes[0].event['event_id'], modifyingEventId);
|
||||
let modifyingAgainEventId = await createPolicyRule(mjolnir.client, banListId, RULE_USER, '@modified:localhost:9999', 'modified again');
|
||||
let modifyingAgainEventId = await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, '@modified:localhost:9999', 'modified again');
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Modified);
|
||||
|
@ -64,10 +65,10 @@ describe("Test: Updating the PolicyList", function() {
|
|||
assert.equal(banList.userRules.length, 2, 'There should be two rules, one for @modified:localhost:9999 and one for @added:localhost:9999');
|
||||
|
||||
// Test redacting a rule
|
||||
const redactThis = await createPolicyRule(mjolnir.client, banListId, RULE_USER, '@redacted:localhost:9999', '');
|
||||
const redactThis = await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, '@redacted:localhost:9999', '');
|
||||
await banList.updateList();
|
||||
assert.equal(banList.userRules.filter(r => r.entity === '@redacted:localhost:9999').length, 1);
|
||||
await mjolnir.client.redactEvent(banListId, redactThis);
|
||||
await mjolnir.client.uncached.redactEvent(banListId, redactThis);
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Removed);
|
||||
|
@ -79,10 +80,10 @@ describe("Test: Updating the PolicyList", function() {
|
|||
|
||||
// Test soft redaction of a rule
|
||||
const softRedactedEntity = '@softredacted:localhost:9999'
|
||||
await createPolicyRule(mjolnir.client, banListId, RULE_USER, softRedactedEntity, '');
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, softRedactedEntity, '');
|
||||
await banList.updateList();
|
||||
assert.equal(banList.userRules.filter(r => r.entity === softRedactedEntity).length, 1);
|
||||
await mjolnir.client.sendStateEvent(banListId, RULE_USER, `rule:${softRedactedEntity}`, {});
|
||||
await mjolnir.client.uncached.sendStateEvent(banListId, RULE_USER, `rule:${softRedactedEntity}`, {});
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Removed);
|
||||
|
@ -92,25 +93,25 @@ describe("Test: Updating the PolicyList", function() {
|
|||
assert.equal(banList.userRules.filter(r => r.entity === softRedactedEntity).length, 0, 'The rule should have been removed');
|
||||
|
||||
// Now test a double soft redaction just to make sure stuff doesn't explode
|
||||
await mjolnir.client.sendStateEvent(banListId, RULE_USER, `rule:${softRedactedEntity}`, {});
|
||||
await mjolnir.client.uncached.sendStateEvent(banListId, RULE_USER, `rule:${softRedactedEntity}`, {});
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 0, "It shouldn't detect a double soft redaction as a change, it should be seen as adding an invalid rule.");
|
||||
assert.equal(banList.userRules.filter(r => r.entity === softRedactedEntity).length, 0, 'The rule should have been removed');
|
||||
|
||||
// Test that different (old) rule types will be modelled as the latest event type.
|
||||
originalEventId = await createPolicyRule(mjolnir.client, banListId, 'org.matrix.mjolnir.rule.user', '@old:localhost:9999', '');
|
||||
originalEventId = await createPolicyRule(mjolnir.client.uncached, banListId, 'org.matrix.mjolnir.rule.user', '@old:localhost:9999', '');
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Added);
|
||||
assert.equal(banList.userRules.filter(r => r.entity === '@old:localhost:9999').length, 1);
|
||||
modifyingEventId = await createPolicyRule(mjolnir.client, banListId, 'm.room.rule.user', '@old:localhost:9999', 'modified reason');
|
||||
modifyingEventId = await createPolicyRule(mjolnir.client.uncached, banListId, 'm.room.rule.user', '@old:localhost:9999', 'modified reason');
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Modified);
|
||||
assert.equal(changes[0].event['event_id'], modifyingEventId);
|
||||
assert.equal(changes[0].previousState['event_id'], originalEventId, 'There should be a previous state event for a modified rule');
|
||||
assert.equal(banList.userRules.filter(r => r.entity === '@old:localhost:9999').length, 1);
|
||||
modifyingAgainEventId = await createPolicyRule(mjolnir.client, banListId, RULE_USER, '@old:localhost:9999', 'changes again');
|
||||
modifyingAgainEventId = await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, '@old:localhost:9999', 'changes again');
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Modified);
|
||||
|
@ -121,18 +122,18 @@ describe("Test: Updating the PolicyList", function() {
|
|||
it("Will remove rules with old types when they are 'soft redacted' with a different but more recent event type.", async function() {
|
||||
this.timeout(3000);
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" }} );
|
||||
const banListId = await mjolnir.client.createRoom({ invite: [await moderator.getUserId()] });
|
||||
const moderator: MatrixClient = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" }} );
|
||||
const banListId = await mjolnir.client.uncached.createRoom({ invite: [await moderator.getUserId()] });
|
||||
const banList = new PolicyList(banListId, banListId, mjolnir.client);
|
||||
await mjolnir.client.setUserPowerLevel(await moderator.getUserId(), banListId, 100);
|
||||
await mjolnir.client.uncached.setUserPowerLevel(await moderator.getUserId(), banListId, 100);
|
||||
|
||||
const entity = '@old:localhost:9999';
|
||||
let originalEventId = await createPolicyRule(mjolnir.client, banListId, 'm.room.rule.user', entity, '');
|
||||
let originalEventId = await createPolicyRule(mjolnir.client.uncached, banListId, 'm.room.rule.user', entity, '');
|
||||
let changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Added);
|
||||
assert.equal(banList.userRules.filter(rule => rule.entity === entity).length, 1, 'There should be a rule stored that we just added...')
|
||||
let softRedactingEventId = await mjolnir.client.sendStateEvent(banListId, RULE_USER, `rule:${entity}`, {});
|
||||
let softRedactingEventId = await mjolnir.client.uncached.sendStateEvent(banListId, RULE_USER, `rule:${entity}`, {});
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Removed);
|
||||
|
@ -142,18 +143,18 @@ describe("Test: Updating the PolicyList", function() {
|
|||
})
|
||||
it("A rule of the most recent type won't be deleted when an old rule is deleted for the same entity.", async function() {
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
const banListId = await mjolnir.client.createRoom({ invite: [await moderator.getUserId()] });
|
||||
const moderator: MatrixClient = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
const banListId = await mjolnir.client.uncached.createRoom({ invite: [await moderator.getUserId()] });
|
||||
const banList = new PolicyList(banListId, banListId, mjolnir.client);
|
||||
await mjolnir.client.setUserPowerLevel(await moderator.getUserId(), banListId, 100);
|
||||
await mjolnir.client.uncached.setUserPowerLevel(await moderator.getUserId(), banListId, 100);
|
||||
|
||||
const entity = '@old:localhost:9999';
|
||||
let originalEventId = await createPolicyRule(mjolnir.client, banListId, 'm.room.rule.user', entity, '');
|
||||
let originalEventId = await createPolicyRule(mjolnir.client.uncached, banListId, 'm.room.rule.user', entity, '');
|
||||
let changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Added);
|
||||
assert.equal(banList.userRules.filter(rule => rule.entity === entity).length, 1, 'There should be a rule stored that we just added...')
|
||||
let updatedEventId = await createPolicyRule(mjolnir.client, banListId, RULE_USER, entity, '');
|
||||
let updatedEventId = await createPolicyRule(mjolnir.client.uncached, banListId, RULE_USER, entity, '');
|
||||
changes = await banList.updateList();
|
||||
// If in the future you change this and it fails, it's really subjective whether this constitutes a modification, since the only thing that has changed
|
||||
// is the rule type. The actual content is identical.
|
||||
|
@ -164,13 +165,13 @@ describe("Test: Updating the PolicyList", function() {
|
|||
assert.equal(banList.userRules.filter(rule => rule.entity === entity).length, 1, 'Only the latest version of the rule gets returned.');
|
||||
|
||||
// Now we delete the old version of the rule without consequence.
|
||||
await mjolnir.client.sendStateEvent(banListId, 'm.room.rule.user', `rule:${entity}`, {});
|
||||
await mjolnir.client.uncached.sendStateEvent(banListId, 'm.room.rule.user', `rule:${entity}`, {});
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 0);
|
||||
assert.equal(banList.userRules.filter(rule => rule.entity === entity).length, 1, 'The rule should still be active.');
|
||||
|
||||
// And we can still delete the new version of the rule.
|
||||
let softRedactingEventId = await mjolnir.client.sendStateEvent(banListId, RULE_USER, `rule:${entity}`, {});
|
||||
let softRedactingEventId = await mjolnir.client.uncached.sendStateEvent(banListId, RULE_USER, `rule:${entity}`, {});
|
||||
changes = await banList.updateList();
|
||||
assert.equal(changes.length, 1);
|
||||
assert.equal(changes[0].changeType, ChangeType.Removed);
|
||||
|
@ -180,10 +181,10 @@ describe("Test: Updating the PolicyList", function() {
|
|||
})
|
||||
it('Test: PolicyList Supports all entity types.', async function () {
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const banListId = await mjolnir.client.createRoom();
|
||||
const banListId = await mjolnir.client.uncached.createRoom();
|
||||
const banList = new PolicyList(banListId, banListId, mjolnir.client);
|
||||
for (let i = 0; i < ALL_RULE_TYPES.length; i++) {
|
||||
await createPolicyRule(mjolnir.client, banListId, ALL_RULE_TYPES[i], `*${i}*`, '');
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, ALL_RULE_TYPES[i], `*${i}*`, '');
|
||||
}
|
||||
let changes: ListRuleChange[] = await banList.updateList();
|
||||
assert.equal(changes.length, ALL_RULE_TYPES.length);
|
||||
|
@ -194,13 +195,13 @@ describe("Test: Updating the PolicyList", function() {
|
|||
describe('Test: We do not respond to recommendations other than m.ban in the PolicyList', function() {
|
||||
it('Will not respond to a rule that has a different recommendation to m.ban (or the unstable equivalent).', async function() {
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const banListId = await mjolnir.client.createRoom();
|
||||
const banListId = await mjolnir.client.uncached.createRoom();
|
||||
const banList = new PolicyList(banListId, banListId, mjolnir.client);
|
||||
await createPolicyRule(mjolnir.client, banListId, RULE_SERVER, 'exmaple.org', '', { recommendation: 'something that is not m.ban' });
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, RULE_SERVER, 'exmaple.org', '', { recommendation: 'something that is not m.ban' });
|
||||
let changes: ListRuleChange[] = await banList.updateList();
|
||||
assert.equal(changes.length, 1, 'There should only be one change');
|
||||
assert.equal(changes[0].changeType, ChangeType.Added);
|
||||
assert.equal(changes[0].sender, await mjolnir.client.getUserId());
|
||||
assert.equal(changes[0].sender, await mjolnir.client.uncached.getUserId());
|
||||
// We really don't want things that aren't m.ban to end up being accessible in these APIs.
|
||||
assert.equal(banList.serverRules.length, 0, `We should have an empty serverRules, got ${JSON.stringify(banList.serverRules)}`);
|
||||
assert.equal(banList.allRules.length, 0, `We should have an empty allRules, got ${JSON.stringify(banList.allRules)}`);
|
||||
|
@ -210,12 +211,12 @@ describe('Test: We do not respond to recommendations other than m.ban in the Pol
|
|||
describe('Test: We will not be able to ban ourselves via ACL.', function() {
|
||||
it('We do not ban ourselves when we put ourselves into the policy list.', async function() {
|
||||
const mjolnir: Mjolnir = this.mjolnir
|
||||
const serverName = new UserID(await mjolnir.client.getUserId()).domain;
|
||||
const banListId = await mjolnir.client.createRoom();
|
||||
const serverName = new UserID(await mjolnir.client.uncached.getUserId()).domain;
|
||||
const banListId = await mjolnir.client.uncached.createRoom();
|
||||
const banList = new PolicyList(banListId, banListId, mjolnir.client);
|
||||
await createPolicyRule(mjolnir.client, banListId, RULE_SERVER, serverName, '');
|
||||
await createPolicyRule(mjolnir.client, banListId, RULE_SERVER, 'evil.com', '');
|
||||
await createPolicyRule(mjolnir.client, banListId, RULE_SERVER, '*', '');
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, RULE_SERVER, serverName, '');
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, RULE_SERVER, 'evil.com', '');
|
||||
await createPolicyRule(mjolnir.client.uncached, banListId, RULE_SERVER, '*', '');
|
||||
// We should still intern the matching rules rule.
|
||||
let changes: ListRuleChange[] = await banList.updateList();
|
||||
assert.equal(banList.serverRules.length, 3);
|
||||
|
@ -231,16 +232,16 @@ describe('Test: We will not be able to ban ourselves via ACL.', function() {
|
|||
describe('Test: ACL updates will batch when rules are added in succession.', function() {
|
||||
it('Will batch ACL updates if we spam rules into a PolicyList', async function() {
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const serverName: string = new UserID(await mjolnir.client.getUserId()).domain
|
||||
const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
const serverName: string = new UserID(await mjolnir.client.uncached.getUserId()).domain
|
||||
const moderator: MatrixClient = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
await moderator.joinRoom(mjolnir.managementRoomId);
|
||||
const mjolnirId = await mjolnir.client.getUserId();
|
||||
const mjolnirId = await mjolnir.client.uncached.getUserId();
|
||||
|
||||
// Setup some protected rooms so we can check their ACL state later.
|
||||
const protectedRooms: string[] = [];
|
||||
for (let i = 0; i < 5; i++) {
|
||||
const room = await moderator.createRoom({ invite: [mjolnirId] });
|
||||
await mjolnir.client.joinRoom(room);
|
||||
await mjolnir.client.uncached.joinRoom(room);
|
||||
await moderator.setUserPowerLevel(mjolnirId, room, 100);
|
||||
await mjolnir.addProtectedRoom(room);
|
||||
protectedRooms.push(room);
|
||||
|
@ -250,13 +251,13 @@ describe('Test: ACL updates will batch when rules are added in succession.', fun
|
|||
await mjolnir.protectedRoomsTracker.syncLists(mjolnir.config.verboseLogging);
|
||||
await Promise.all(protectedRooms.map(async room => {
|
||||
// We're going to need timeline pagination I'm afraid.
|
||||
const roomAcl = await mjolnir.client.getRoomStateEvent(room, "m.room.server_acl", "");
|
||||
const roomAcl = await mjolnir.client.uncached.getRoomStateEvent(room, "m.room.server_acl", "");
|
||||
assert.equal(roomAcl?.deny?.length ?? 0, 0, 'There should be no entries in the deny ACL.');
|
||||
}));
|
||||
|
||||
// Flood the watched list with banned servers, which should prompt Mjolnir to update server ACL in protected rooms.
|
||||
const banListId = await moderator.createRoom({ invite: [mjolnirId] });
|
||||
await mjolnir.client.joinRoom(banListId);
|
||||
await mjolnir.client.uncached.joinRoom(banListId);
|
||||
await mjolnir.watchList(Permalinks.forRoom(banListId));
|
||||
const acl = new ServerAcl(serverName).denyIpAddresses().allowServer("*");
|
||||
const evilServerCount = 200;
|
||||
|
@ -278,7 +279,7 @@ describe('Test: ACL updates will batch when rules are added in succession.', fun
|
|||
|
||||
// Check each of the protected rooms for ACL events and make sure they were batched and are correct.
|
||||
await Promise.all(protectedRooms.map(async room => {
|
||||
const roomAcl = await mjolnir.client.getRoomStateEvent(room, "m.room.server_acl", "");
|
||||
const roomAcl = await mjolnir.client.uncached.getRoomStateEvent(room, "m.room.server_acl", "");
|
||||
if (!acl.matches(roomAcl)) {
|
||||
assert.fail(`Room ${room} doesn't have the correct ACL: ${JSON.stringify(roomAcl, null, 2)}`)
|
||||
}
|
||||
|
@ -299,32 +300,32 @@ describe('Test: unbaning entities via the PolicyList.', function() {
|
|||
afterEach(function() { this.moderator?.stop(); });
|
||||
it('Will remove rules that have legacy types', async function() {
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const serverName: string = new UserID(await mjolnir.client.getUserId()).domain
|
||||
const serverName: string = new UserID(await mjolnir.client.uncached.getUserId()).domain
|
||||
const moderator: MatrixClient = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
this.moderator = moderator;
|
||||
await moderator.joinRoom(mjolnir.managementRoomId);
|
||||
const mjolnirId = await mjolnir.client.getUserId();
|
||||
const mjolnirId = await mjolnir.client.uncached.getUserId();
|
||||
|
||||
// We'll make 1 protected room to test ACLs in.
|
||||
const protectedRoom = await moderator.createRoom({ invite: [mjolnirId] });
|
||||
await mjolnir.client.joinRoom(protectedRoom);
|
||||
await mjolnir.client.uncached.joinRoom(protectedRoom);
|
||||
await moderator.setUserPowerLevel(mjolnirId, protectedRoom, 100);
|
||||
await mjolnir.addProtectedRoom(protectedRoom);
|
||||
|
||||
// If a previous test hasn't cleaned up properly, these rooms will be populated by bogus ACLs at this point.
|
||||
await mjolnir.protectedRoomsTracker.syncLists(mjolnir.config.verboseLogging);
|
||||
// If this is not present, then it means the room isn't being protected, which is really bad.
|
||||
const roomAcl = await mjolnir.client.getRoomStateEvent(protectedRoom, "m.room.server_acl", "");
|
||||
const roomAcl = await mjolnir.client.uncached.getRoomStateEvent(protectedRoom, "m.room.server_acl", "");
|
||||
assert.equal(roomAcl?.deny?.length ?? 0, 0, 'There should be no entries in the deny ACL.');
|
||||
|
||||
// Create some legacy rules on a PolicyList.
|
||||
const banListId = await moderator.createRoom({ invite: [mjolnirId] });
|
||||
await moderator.setUserPowerLevel(await mjolnir.client.getUserId(), banListId, 100);
|
||||
await moderator.setUserPowerLevel(await mjolnir.client.uncached.getUserId(), banListId, 100);
|
||||
await moderator.sendStateEvent(banListId, 'org.matrix.mjolnir.shortcode', '', { shortcode: "unban-test" });
|
||||
await mjolnir.client.joinRoom(banListId);
|
||||
await mjolnir.client.uncached.joinRoom(banListId);
|
||||
await mjolnir.watchList(Permalinks.forRoom(banListId));
|
||||
// we use this to compare changes.
|
||||
const banList = new PolicyList(banListId, banListId, moderator);
|
||||
const banList = new PolicyList(banListId, banListId, new CachingClient(moderator));
|
||||
// we need two because we need to test the case where an entity has all rule types in the list
|
||||
// and another one that only has one (so that we would hit 404 while looking up state)
|
||||
const olderBadServer = "old.evil.example"
|
||||
|
@ -341,7 +342,7 @@ describe('Test: unbaning entities via the PolicyList.', function() {
|
|||
|
||||
// Check that we have setup our test properly and therefore evil.example is banned.
|
||||
const acl = new ServerAcl(serverName).denyIpAddresses().allowServer("*").denyServer(olderBadServer).denyServer(newerBadServer);
|
||||
const protectedAcl = await mjolnir.client.getRoomStateEvent(protectedRoom, "m.room.server_acl", "");
|
||||
const protectedAcl = await mjolnir.client.uncached.getRoomStateEvent(protectedRoom, "m.room.server_acl", "");
|
||||
if (!acl.matches(protectedAcl)) {
|
||||
assert.fail(`Room ${protectedRoom} doesn't have the correct ACL: ${JSON.stringify(roomAcl, null, 2)}`);
|
||||
}
|
||||
|
@ -363,7 +364,7 @@ describe('Test: unbaning entities via the PolicyList.', function() {
|
|||
// Confirm that the server is unbanned.
|
||||
await banList.updateList();
|
||||
assert.equal(banList.allRules.length, 0);
|
||||
const aclAfter = await mjolnir.client.getRoomStateEvent(protectedRoom, "m.room.server_acl", "");
|
||||
const aclAfter = await mjolnir.client.uncached.getRoomStateEvent(protectedRoom, "m.room.server_acl", "");
|
||||
assert.equal(aclAfter.deny.length, 0, 'Should be no servers denied anymore');
|
||||
})
|
||||
})
|
||||
|
@ -372,16 +373,16 @@ describe('Test: should apply bans to the most recently active rooms first', func
|
|||
it('Applies bans to the most recently active rooms first', async function() {
|
||||
this.timeout(180000)
|
||||
const mjolnir: Mjolnir = this.mjolnir!
|
||||
const serverName: string = new UserID(await mjolnir.client.getUserId()).domain
|
||||
const moderator = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
const serverName: string = new UserID(await mjolnir.client.uncached.getUserId()).domain
|
||||
const moderator: MatrixClient = await newTestUser(this.config.homeserverUrl, { name: { contains: "moderator" } });
|
||||
await moderator.joinRoom(mjolnir.managementRoomId);
|
||||
const mjolnirId = await mjolnir.client.getUserId();
|
||||
const mjolnirId = await mjolnir.client.uncached.getUserId();
|
||||
|
||||
// Setup some protected rooms so we can check their ACL state later.
|
||||
const protectedRooms: string[] = [];
|
||||
for (let i = 0; i < 10; i++) {
|
||||
const room = await moderator.createRoom({ invite: [mjolnirId] });
|
||||
await mjolnir.client.joinRoom(room);
|
||||
await mjolnir.client.uncached.joinRoom(room);
|
||||
await moderator.setUserPowerLevel(mjolnirId, room, 100);
|
||||
await mjolnir.addProtectedRoom(room);
|
||||
protectedRooms.push(room);
|
||||
|
@ -390,13 +391,13 @@ describe('Test: should apply bans to the most recently active rooms first', func
|
|||
// If a previous test hasn't cleaned up properly, these rooms will be populated by bogus ACLs at this point.
|
||||
await mjolnir.protectedRoomsTracker.syncLists(mjolnir.config.verboseLogging);
|
||||
await Promise.all(protectedRooms.map(async room => {
|
||||
const roomAcl = await mjolnir.client.getRoomStateEvent(room, "m.room.server_acl", "").catch(e => e.statusCode === 404 ? { deny: [] } : Promise.reject(e));
|
||||
const roomAcl = await mjolnir.client.uncached.getRoomStateEvent(room, "m.room.server_acl", "").catch(e => e.statusCode === 404 ? { deny: [] } : Promise.reject(e));
|
||||
assert.equal(roomAcl?.deny?.length ?? 0, 0, 'There should be no entries in the deny ACL.');
|
||||
}));
|
||||
|
||||
// Flood the watched list with banned servers, which should prompt Mjolnir to update server ACL in protected rooms.
|
||||
const banListId = await moderator.createRoom({ invite: [mjolnirId] });
|
||||
await mjolnir.client.joinRoom(banListId);
|
||||
await mjolnir.client.uncached.joinRoom(banListId);
|
||||
await mjolnir.watchList(Permalinks.forRoom(banListId));
|
||||
|
||||
await mjolnir.protectedRoomsTracker.syncLists(mjolnir.config.verboseLogging);
|
||||
|
@ -423,7 +424,7 @@ describe('Test: should apply bans to the most recently active rooms first', func
|
|||
// collect all the rooms that received an ACL event.
|
||||
const aclRooms: any[] = await new Promise(async resolve => {
|
||||
const rooms: any[] = [];
|
||||
this.mjolnir.client.on('room.event', (room: string, event: any) => {
|
||||
this.mjolnir.client.uncached.on('room.event', (room: string, event: any) => {
|
||||
if (protectedRooms.includes(room)) {
|
||||
rooms.push(room);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue
Block a user