Use the new WatchedPolicyRooms MPS feature.

This simplifies anything to do with the way policy rooms are watched.
There was a lot of weird glue code around finding policy rooms and
revisions that has just been whipped out into the WatchedPolicyRooms
abstraction.
This commit is contained in:
gnuxie committed 2025-02-10 16:39:03 +00:00
1 parent 5d727d7114
commit 2f7c598266
17 files changed
+140 -346

No files matched your search

+2 -5
View File
@@ -23,7 +23,6 @@ import {
ActionExceptionKind,
ActionResult,
Ok,
PropagationType,
Task,
isError,
} from "matrix-protection-suite";
@@ -412,9 +411,7 @@ async function createFirstList(
if (isError(addRoomResult)) {
return addRoomResult;
}
return await draupnir.protectedRoomsSet.issuerManager.watchList(
PropagationType.Direct,
policyRoom.ok,
{}
return await draupnir.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly(
policyRoom.ok
);
}
+14 -22
View File
@@ -1,4 +1,4 @@
// Copyright 2022 - 2023 Gnuxie <Gnuxie@protonmail.com>
// Copyright 2022 - 2025 Gnuxie <Gnuxie@protonmail.com>
// Copyright 2019 - 2021 The Matrix.org Foundation C.I.C.
//
// SPDX-License-Identifier: AFL-3.0 AND Apache-2.0
@@ -16,14 +16,11 @@ import {
Ok,
PolicyRoomManager,
RoomResolver,
PolicyListConfig,
WatchedPolicyRooms,
} from "matrix-protection-suite";
import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand";
import {
MatrixRoomID,
MatrixRoomReference,
MatrixUserID,
StringRoomID,
StringUserID,
} from "@the-draupnir-project/matrix-basic-types";
import {
@@ -40,6 +37,7 @@ import {
DraupnirContextToCommandContextTranslator,
DraupnirInterfaceAdaptor,
} from "./DraupnirCommandPrerequisites";
import { ResultError } from "@gnuxie/typescript-result";
export async function findPolicyRoomEditorFromRoomReference(
roomResolver: RoomResolver,
@@ -55,12 +53,10 @@ export async function findPolicyRoomEditorFromRoomReference(
export type DraupnirBanCommandContext = {
policyRoomManager: PolicyRoomManager;
issuerManager: PolicyListConfig;
watchedPolicyRooms: WatchedPolicyRooms;
defaultReasons: string[];
roomResolver: RoomResolver;
clientUserID: StringUserID;
allJoinedRooms: StringRoomID[];
protectedRooms: MatrixRoomID[];
};
export const DraupnirBanCommand = describeCommand({
@@ -108,12 +104,9 @@ export const DraupnirBanCommand = describeCommand({
},
async executor(
{
issuerManager,
watchedPolicyRooms,
policyRoomManager,
roomResolver,
clientUserID,
allJoinedRooms,
protectedRooms,
}: DraupnirBanCommandContext,
_info: BasicInvocationInformation,
_keywords,
@@ -123,18 +116,19 @@ export const DraupnirBanCommand = describeCommand({
): Promise<ActionResult<string>> {
const policyRoomReference =
typeof policyRoomDesignator === "string"
? await findPolicyRoomIDFromShortcode(
issuerManager,
policyRoomManager,
allJoinedRooms,
protectedRooms,
clientUserID,
policyRoomDesignator
? Ok(
watchedPolicyRooms.findPolicyRoomFromShortcode(policyRoomDesignator)
?.room
)
: Ok(policyRoomDesignator);
if (isError(policyRoomReference)) {
return policyRoomReference;
}
if (policyRoomReference.ok === undefined) {
return ResultError.Result(
`Unable to find a policy room from the shortcode ${policyRoomDesignator.toString()}`
);
}
const policyListEditorResult = await findPolicyRoomEditorFromRoomReference(
roomResolver,
policyRoomManager,
@@ -176,12 +170,10 @@ DraupnirContextToCommandContextTranslator.registerTranslation(
function (draupnir) {
return {
policyRoomManager: draupnir.policyRoomManager,
issuerManager: draupnir.protectedRoomsSet.issuerManager,
watchedPolicyRooms: draupnir.protectedRoomsSet.watchedPolicyRooms,
defaultReasons: draupnir.config.commands.ban.defaultReasons,
roomResolver: draupnir.clientPlatform.toRoomResolver(),
clientUserID: draupnir.clientUserID,
allJoinedRooms: draupnir.clientRooms.currentRevision.allJoinedRooms,
protectedRooms: draupnir.protectedRoomsSet.allProtectedRooms,
};
}
);
+6 -65
View File
@@ -8,23 +8,9 @@
// https://github.com/matrix-org/mjolnir
// </text>
import {
ActionError,
ActionResult,
Ok,
PolicyListConfig,
PolicyRoomManager,
PolicyRuleType,
PropagationType,
isError,
} from "matrix-protection-suite";
import { getWatchedPolicyRoomsInfo } from "./StatusCommand";
import { ActionResult, isError } from "matrix-protection-suite";
import { Draupnir } from "../Draupnir";
import {
MatrixRoomID,
StringRoomID,
StringUserID,
} from "@the-draupnir-project/matrix-basic-types";
import { MatrixRoomID } from "@the-draupnir-project/matrix-basic-types";
import {
BasicInvocationInformation,
ParsedKeywords,
@@ -53,11 +39,10 @@ export async function createList(
if (isError(newList)) {
return newList;
}
const watchResult = await draupnir.protectedRoomsSet.issuerManager.watchList(
PropagationType.Direct,
newList.ok,
{}
);
const watchResult =
await draupnir.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly(
newList.ok
);
if (isError(watchResult)) {
return watchResult;
}
@@ -88,47 +73,3 @@ export const DraupnirListCreateCommand = describeCommand({
DraupnirInterfaceAdaptor.describeRenderer(DraupnirListCreateCommand, {
isAlwaysSupposedToUseDefaultRenderer: true,
});
export async function findPolicyRoomIDFromShortcode(
issuerManager: PolicyListConfig,
policyRoomManager: PolicyRoomManager,
allJoinedRooms: StringRoomID[],
protectedRooms: MatrixRoomID[],
editingClientUserID: StringUserID,
shortcode: string
): Promise<ActionResult<MatrixRoomID>> {
const info = await getWatchedPolicyRoomsInfo(
issuerManager,
policyRoomManager,
allJoinedRooms,
protectedRooms
);
if (isError(info)) {
return info;
}
const matchingRevisions = [
...info.ok.subscribedAndProtectedLists,
...info.ok.subscribedLists,
].filter((list) => list.revision.shortcode === shortcode);
if (matchingRevisions.length === 0 || matchingRevisions[0] === undefined) {
return ActionError.Result(
`Could not find a policy room from the shortcode: ${shortcode}`
);
} else if (matchingRevisions.length === 1) {
return Ok(matchingRevisions[0].revision.room);
} else {
const remainingRevisions = matchingRevisions.filter((revision) =>
revision.revision.isAbleToEdit(editingClientUserID, PolicyRuleType.User)
);
if (
remainingRevisions.length !== 1 ||
remainingRevisions[0] === undefined
) {
return ActionError.Result(
`The shortcode ${shortcode} is ambiguous and is currently used by ${remainingRevisions.length} lists.`
);
} else {
return Ok(remainingRevisions[0].revision.room);
}
}
}
+10 -13
View File
@@ -14,6 +14,7 @@ import {
ActionResult,
Ok,
Revision,
WatchedPolicyRoom,
isError,
} from "matrix-protection-suite";
import {
@@ -31,8 +32,7 @@ import { Draupnir } from "../Draupnir";
import { Result } from "@gnuxie/typescript-result";
import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites";
import {
getWatchedPolicyRoomsInfo,
WatchedPolicyRoomInfo,
groupWatchedPolicyRoomsByProtectionStatus,
renderPolicyList,
} from "./StatusCommand";
@@ -43,9 +43,9 @@ type RoomListItem = {
};
type ListRoomsCommandInfo = {
joinedAndProtectedLists: WatchedPolicyRoomInfo[];
joinedAndWatchedLists: WatchedPolicyRoomInfo[];
partedAndWatchedLists: RoomListItem[];
joinedAndProtectedLists: WatchedPolicyRoom[];
joinedAndWatchedLists: WatchedPolicyRoom[];
partedAndWatchedLists: WatchedPolicyRoom[];
joinedAndProtectedRooms: RoomListItem[];
joinedAndUnprotectedRooms: RoomListItem[];
partedAndProtectedRooms: RoomListItem[];
@@ -57,9 +57,8 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({
async executor(draupnir: Draupnir): Promise<Result<ListRoomsCommandInfo>> {
const allJoinedRooms = draupnir.clientRooms.currentRevision.allJoinedRooms;
const allProtectedRooms = draupnir.protectedRoomsSet.allProtectedRooms;
const listInfo = await getWatchedPolicyRoomsInfo(
draupnir.protectedRoomsSet.issuerManager,
draupnir.policyRoomManager,
const listInfo = groupWatchedPolicyRoomsByProtectionStatus(
draupnir.protectedRoomsSet.watchedPolicyRooms,
draupnir.clientRooms.currentRevision.allJoinedRooms,
draupnir.protectedRoomsSet.allProtectedRooms
);
@@ -79,9 +78,7 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({
return Ok({
joinedAndProtectedLists: listInfo.ok.subscribedAndProtectedLists,
joinedAndWatchedLists: listInfo.ok.subscribedLists,
partedAndWatchedLists: listInfo.ok.subscribedButPartedLists.map(
(profile) => makeRoomListItem(profile.room)
),
partedAndWatchedLists: listInfo.ok.subscribedButPartedLists,
joinedAndProtectedRooms: allProtectedRooms
.filter((room) => allJoinedRooms.includes(room.toRoomIDOrAlias()))
.map(makeRoomListItem),
@@ -101,7 +98,7 @@ export const DraupnirListProtectedRoomsCommand = describeCommand({
});
function renderPolicyLists(
rooms: WatchedPolicyRoomInfo[],
rooms: WatchedPolicyRoom[],
options: { name: string }
): DocumentNode {
if (rooms.length === 0) {
@@ -169,7 +166,7 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirListProtectedRoomsCommand, {
{renderPolicyLists(result.ok.joinedAndWatchedLists, {
name: "Joined and watched unprotected policy rooms",
})}
{renderRoomList(result.ok.partedAndWatchedLists, {
{renderPolicyLists(result.ok.partedAndWatchedLists, {
name: "Parted policy rooms that are still marked as watched",
})}
{renderRoomList(result.ok.joinedAndProtectedRooms, {
+10 -37
View File
@@ -14,7 +14,6 @@ import {
PolicyRule,
isError,
} from "matrix-protection-suite";
import { getWatchedPolicyRoomsInfo } from "./StatusCommand";
import {
StringRoomID,
MatrixRoomID,
@@ -90,24 +89,12 @@ export const DraupnirListRulesCommand = describeCommand({
summary: "Lists the rules currently in use by Draupnir.",
parameters: [],
async executor(draupnir: Draupnir): Promise<Result<ListMatches[]>> {
const infoResult = await getWatchedPolicyRoomsInfo(
draupnir.protectedRoomsSet.issuerManager,
draupnir.policyRoomManager,
draupnir.clientRooms.currentRevision.allJoinedRooms,
draupnir.protectedRoomsSet.allProtectedRooms
);
if (isError(infoResult)) {
return infoResult;
}
return Ok(
[
...infoResult.ok.subscribedAndProtectedLists,
...infoResult.ok.subscribedLists,
].map((policyRoom) => ({
room: policyRoom.revision.room,
roomID: policyRoom.revision.room.toRoomIDOrAlias(),
profile: policyRoom.watchedListProfile,
matches: policyRoom.revision.allRules(),
draupnir.protectedRoomsSet.watchedPolicyRooms.allRooms.map((profile) => ({
room: profile.revision.room,
roomID: profile.revision.room.toRoomIDOrAlias(),
profile: profile,
matches: profile.revision.allRules(),
}))
);
},
@@ -135,27 +122,13 @@ export const DraupnirRulesMatchingCommand = describeCommand({
_rest,
entity
): Promise<Result<ListMatches[]>> {
const policyRooms = await getWatchedPolicyRoomsInfo(
draupnir.protectedRoomsSet.issuerManager,
draupnir.policyRoomManager,
draupnir.clientRooms.currentRevision.allJoinedRooms,
draupnir.protectedRoomsSet.allProtectedRooms
);
if (isError(policyRooms)) {
return policyRooms;
}
return Ok(
[
...policyRooms.ok.subscribedAndProtectedLists,
...policyRooms.ok.subscribedLists,
].map((policyRoom) => {
draupnir.protectedRoomsSet.watchedPolicyRooms.allRooms.map((profile) => {
return {
room: policyRoom.revision.room,
roomID: policyRoom.revision.room.toRoomIDOrAlias(),
matches: policyRoom.revision.allRulesMatchingEntity(
entity.toString()
),
profile: policyRoom.watchedListProfile,
room: profile.revision.room,
roomID: profile.revision.room.toRoomIDOrAlias(),
matches: profile.revision.allRulesMatchingEntity(entity.toString()),
profile: profile,
};
})
);
+30 -76
View File
@@ -12,11 +12,9 @@ import { DOCUMENTATION_URL, PACKAGE_JSON, SOFTWARE_VERSION } from "../config";
import {
ActionResult,
Ok,
PolicyListConfig,
PolicyRoomManager,
PolicyRoomRevision,
PolicyRoomWatchProfile,
PolicyRuleType,
WatchedPolicyRoom,
WatchedPolicyRooms,
isError,
} from "matrix-protection-suite";
import { Draupnir } from "../Draupnir";
@@ -40,15 +38,10 @@ export const DraupnirStatusCommand = describeCommand({
},
});
export interface WatchedPolicyRoomInfo {
watchedListProfile: PolicyRoomWatchProfile;
revision: PolicyRoomRevision;
}
export type WatchedPolicyRoomsInfo = {
subscribedLists: WatchedPolicyRoomInfo[];
subscribedAndProtectedLists: WatchedPolicyRoomInfo[];
subscribedButPartedLists: PolicyRoomWatchProfile[];
subscribedLists: WatchedPolicyRoom[];
subscribedAndProtectedLists: WatchedPolicyRoom[];
subscribedButPartedLists: WatchedPolicyRoom[];
};
export type StatusInfo = {
@@ -59,69 +52,34 @@ export type StatusInfo = {
documentationURL: string;
} & WatchedPolicyRoomsInfo;
async function findRevisionIssuers(
policyRoomManager: PolicyRoomManager,
profiles: PolicyRoomWatchProfile[]
): Promise<Result<WatchedPolicyRoomInfo[]>> {
const issuers: WatchedPolicyRoomInfo[] = [];
for (const profile of profiles) {
const issuerResult = await policyRoomManager.getPolicyRoomRevisionIssuer(
profile.room
);
if (isError(issuerResult)) {
return issuerResult.elaborate(
"Unable to find a policy room revision issuer for a watched policy list"
);
}
issuers.push({
watchedListProfile: profile,
revision: issuerResult.ok.currentRevision,
});
}
return Ok(issuers);
}
export async function getWatchedPolicyRoomsInfo(
issuerManager: PolicyListConfig,
policyRoomManager: PolicyRoomManager,
export function groupWatchedPolicyRoomsByProtectionStatus(
watchedPolicyRooms: WatchedPolicyRooms,
allJoinedRooms: StringRoomID[],
protectedRooms: MatrixRoomID[]
): Promise<Result<WatchedPolicyRoomsInfo>> {
const watchedListProfiles = issuerManager.allWatchedLists;
const subscribedAndProtectedLists = await findRevisionIssuers(
policyRoomManager,
watchedListProfiles.filter(
(profile) =>
allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) &&
protectedRooms.find(
(protectedRoom) =>
protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias()
)
)
): Result<WatchedPolicyRoomsInfo> {
const watchedListProfiles = watchedPolicyRooms.allRooms;
const subscribedAndProtectedLists = watchedListProfiles.filter(
(profile) =>
allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) &&
protectedRooms.find(
(protectedRoom) =>
protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias()
)
);
if (isError(subscribedAndProtectedLists)) {
return subscribedAndProtectedLists;
}
const subscribedLists = await findRevisionIssuers(
policyRoomManager,
watchedListProfiles.filter(
(profile) =>
allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) &&
!protectedRooms.find(
(protectedRoom) =>
protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias()
)
)
const subscribedLists = watchedListProfiles.filter(
(profile) =>
allJoinedRooms.includes(profile.room.toRoomIDOrAlias()) &&
!protectedRooms.find(
(protectedRoom) =>
protectedRoom.toRoomIDOrAlias() === profile.room.toRoomIDOrAlias()
)
);
if (isError(subscribedLists)) {
return subscribedLists;
}
const subscribedButPartedLists = watchedListProfiles.filter(
(profile) => !allJoinedRooms.includes(profile.room.toRoomIDOrAlias())
);
return Ok({
subscribedLists: subscribedLists.ok,
subscribedAndProtectedLists: subscribedAndProtectedLists.ok,
subscribedLists: subscribedLists,
subscribedAndProtectedLists: subscribedAndProtectedLists,
subscribedButPartedLists,
});
}
@@ -139,9 +97,8 @@ DraupnirInterfaceAdaptor.describeRenderer(DraupnirStatusCommand, {
export async function draupnirStatusInfo(
draupnir: Draupnir
): Promise<Result<StatusInfo>> {
const watchedListInfo = await getWatchedPolicyRoomsInfo(
draupnir.protectedRoomsSet.issuerManager,
draupnir.policyRoomManager,
const watchedListInfo = groupWatchedPolicyRoomsByProtectionStatus(
draupnir.protectedRoomsSet.watchedPolicyRooms,
draupnir.clientRooms.currentRevision.allJoinedRooms,
draupnir.protectedRoomsSet.allProtectedRooms
);
@@ -161,14 +118,14 @@ export async function draupnirStatusInfo(
});
}
export function renderPolicyList(list: WatchedPolicyRoomInfo): DocumentNode {
export function renderPolicyList(list: WatchedPolicyRoom): DocumentNode {
return (
<li>
<a href={list.revision.room.toPermalink()}>
{list.revision.room.toRoomIDOrAlias()}
</a>{" "}
&#32; ({list.revision.shortcode ?? "<no shortcode>"}) propagation:{" "}
{list.watchedListProfile.propagation} &#32; (rules:{" "}
{list.propagation} &#32; (rules:{" "}
{list.revision.allRulesOfType(PolicyRuleType.Server).length} servers,{" "}
{list.revision.allRulesOfType(PolicyRuleType.User).length} users,{" "}
{list.revision.allRulesOfType(PolicyRuleType.Room).length} rooms) (last
@@ -179,10 +136,7 @@ export function renderPolicyList(list: WatchedPolicyRoomInfo): DocumentNode {
}
export function renderStatusInfo(info: StatusInfo): DocumentNode {
const renderPolicyLists = (
header: string,
lists: WatchedPolicyRoomInfo[]
) => {
const renderPolicyLists = (header: string, lists: WatchedPolicyRoom[]) => {
const renderedLists = lists.map(renderPolicyList);
return (
<fragment>
+14 -24
View File
@@ -11,22 +11,19 @@
import {
isError,
Ok,
PolicyListConfig,
PolicyRoomManager,
PolicyRuleType,
RoomInviter,
RoomResolver,
RoomUnbanner,
SetRoomMembership,
WatchedPolicyRooms,
} from "matrix-protection-suite";
import { LogLevel } from "matrix-bot-sdk";
import { findPolicyRoomIDFromShortcode } from "./CreateBanListCommand";
import {
isStringUserID,
MatrixGlob,
MatrixRoomID,
MatrixUserID,
StringRoomID,
StringUserID,
} from "@the-draupnir-project/matrix-basic-types";
import {
@@ -38,13 +35,12 @@ import {
tuple,
union,
} from "@the-draupnir-project/interface-manager";
import { Result } from "@gnuxie/typescript-result";
import { Result, ResultError } from "@gnuxie/typescript-result";
import {
DraupnirContextToCommandContextTranslator,
DraupnirInterfaceAdaptor,
} from "./DraupnirCommandPrerequisites";
import ManagementRoomOutput from "../managementroom/ManagementRoomOutput";
import { DraupnirBanCommandContext } from "./Ban";
import { UnlistedUserRedactionQueue } from "../queues/UnlistedUserRedactionQueue";
async function unbanUserFromRooms(
@@ -108,7 +104,7 @@ async function unbanUserFromRooms(
export type DraupnirUnbanCommandContext = {
policyRoomManager: PolicyRoomManager;
issuerManager: PolicyListConfig;
watchedPolicyRooms: WatchedPolicyRooms;
roomResolver: RoomResolver;
clientUserID: StringUserID;
setMembership: SetRoomMembership;
@@ -117,8 +113,6 @@ export type DraupnirUnbanCommandContext = {
roomUnbanner: RoomUnbanner;
unlistedUserRedactionQueue: UnlistedUserRedactionQueue;
roomInviter: RoomInviter;
allJoinedRooms: StringRoomID[];
protectedRooms: MatrixRoomID[];
};
export const DraupnirUnbanCommand = describeCommand({
@@ -143,7 +137,7 @@ export const DraupnirUnbanCommand = describeCommand({
prompt: async function ({
policyRoomManager,
clientUserID,
}: DraupnirBanCommandContext) {
}: DraupnirUnbanCommandContext) {
return Ok({
suggestions: policyRoomManager
.getEditablePolicyRoomIDs(clientUserID, PolicyRuleType.User)
@@ -179,26 +173,24 @@ export const DraupnirUnbanCommand = describeCommand({
const {
roomResolver,
policyRoomManager,
issuerManager,
clientUserID,
watchedPolicyRooms,
unlistedUserRedactionQueue,
allJoinedRooms,
protectedRooms,
} = context;
const policyRoomReference =
typeof policyRoomDesignator === "string"
? await findPolicyRoomIDFromShortcode(
issuerManager,
policyRoomManager,
allJoinedRooms,
protectedRooms,
clientUserID,
policyRoomDesignator
? Ok(
watchedPolicyRooms.findPolicyRoomFromShortcode(policyRoomDesignator)
?.room
)
: Ok(policyRoomDesignator);
if (isError(policyRoomReference)) {
return policyRoomReference;
}
if (policyRoomReference.ok === undefined) {
return ResultError.Result(
`Unable to find a policy room from the shortcode ${policyRoomDesignator.toString()}`
);
}
const policyRoom = await roomResolver.resolveRoom(policyRoomReference.ok);
if (isError(policyRoom)) {
return policyRoom;
@@ -251,7 +243,7 @@ DraupnirContextToCommandContextTranslator.registerTranslation(
function (draupnir) {
return {
policyRoomManager: draupnir.policyRoomManager,
issuerManager: draupnir.protectedRoomsSet.issuerManager,
watchedPolicyRooms: draupnir.protectedRoomsSet.watchedPolicyRooms,
roomResolver: draupnir.clientPlatform.toRoomResolver(),
clientUserID: draupnir.clientUserID,
setMembership: draupnir.protectedRoomsSet.setRoomMembership,
@@ -260,8 +252,6 @@ DraupnirContextToCommandContextTranslator.registerTranslation(
roomUnbanner: draupnir.clientPlatform.toRoomUnbanner(),
unlistedUserRedactionQueue: draupnir.unlistedUserRedactionQueue,
roomInviter: draupnir.clientPlatform.toRoomInviter(),
allJoinedRooms: draupnir.clientRooms.currentRevision.allJoinedRooms,
protectedRooms: draupnir.protectedRoomsSet.allProtectedRooms,
};
}
);
+8 -16
View File
@@ -9,9 +9,8 @@
// </text>
import {
PolicyListConfig,
PropagationType,
RoomResolver,
WatchedPolicyRooms,
isError,
} from "matrix-protection-suite";
import {
@@ -27,7 +26,7 @@ import {
} from "./DraupnirCommandPrerequisites";
export type DraupnirWatchUnwatchCommandContext = {
issuerManager: PolicyListConfig;
watchedPolicyRooms: WatchedPolicyRooms;
roomResolver: RoomResolver;
};
@@ -39,7 +38,7 @@ export const DraupnirWatchPolicyRoomCommand = describeCommand({
acceptor: MatrixRoomReferencePresentationSchema,
}),
async executor(
{ issuerManager, roomResolver }: DraupnirWatchUnwatchCommandContext,
{ watchedPolicyRooms, roomResolver }: DraupnirWatchUnwatchCommandContext,
_info,
_keywords,
_rest,
@@ -50,18 +49,14 @@ export const DraupnirWatchPolicyRoomCommand = describeCommand({
return policyRoom;
}
if (
issuerManager.allWatchedLists.some(
watchedPolicyRooms.allRooms.some(
(profile) =>
profile.room.toRoomIDOrAlias() === policyRoom.ok.toRoomIDOrAlias()
)
) {
return ResultError.Result("We are already watching this list.");
}
return await issuerManager.watchList(
PropagationType.Direct,
policyRoom.ok,
{}
);
return await watchedPolicyRooms.watchPolicyRoomDirectly(policyRoom.ok);
},
});
@@ -73,7 +68,7 @@ export const DraupnirUnwatchPolicyRoomCommand = describeCommand({
acceptor: MatrixRoomReferencePresentationSchema,
}),
async executor(
{ issuerManager, roomResolver }: DraupnirWatchUnwatchCommandContext,
{ watchedPolicyRooms, roomResolver }: DraupnirWatchUnwatchCommandContext,
_info,
_keywords,
_rest,
@@ -83,10 +78,7 @@ export const DraupnirUnwatchPolicyRoomCommand = describeCommand({
if (isError(policyRoom)) {
return policyRoom;
}
return await issuerManager.unwatchList(
PropagationType.Direct,
policyRoom.ok
);
return await watchedPolicyRooms.unwatchPolicyRoom(policyRoom.ok);
},
});
@@ -100,7 +92,7 @@ for (const command of [
DraupnirContextToCommandContextTranslator.registerTranslation(
command,
(draupnir: Draupnir) => ({
issuerManager: draupnir.protectedRoomsSet.issuerManager,
watchedPolicyRooms: draupnir.protectedRoomsSet.watchedPolicyRooms,
roomResolver: draupnir.clientPlatform.toRoomResolver(),
})
);
@@ -38,6 +38,7 @@ import {
StandardProtectionsManager,
StandardSetRoomMembership,
StandardSetRoomState,
StandardWatchedPolicyRooms,
isError,
} from "matrix-protection-suite";
import {
@@ -59,7 +60,6 @@ const log = new Logger("DraupnirProtectedRoomsSet");
async function makePolicyListConfig(
client: MatrixSendClient,
policyRoomManager: PolicyRoomManager,
roomJoiner: RoomJoiner
): Promise<ActionResult<PolicyListConfig>> {
const result = await MjolnirPolicyRoomsConfig.createFromStore(
@@ -67,7 +67,6 @@ async function makePolicyListConfig(
client,
MJOLNIR_WATCHED_POLICY_ROOMS_EVENT_TYPE
),
policyRoomManager,
roomJoiner
);
return result;
@@ -192,12 +191,19 @@ export async function makeProtectedRoomsSet(
}
const policyListConfig = await makePolicyListConfig(
client,
policyRoomManager,
clientPlatform.toRoomJoiner()
);
if (isError(policyListConfig)) {
return policyListConfig;
}
const watchedPolicyRooms = await StandardWatchedPolicyRooms.create(
policyListConfig.ok,
policyRoomManager,
clientPlatform.toRoomJoiner()
);
if (isError(watchedPolicyRooms)) {
return watchedPolicyRooms;
}
const protectionsConfig = await makeProtectionsManager(
client,
roomStateManager,
@@ -209,7 +215,7 @@ export async function makeProtectedRoomsSet(
return protectionsConfig;
}
const protectedRoomsSet = new StandardProtectedRoomsSet(
policyListConfig.ok,
watchedPolicyRooms.ok,
protectedRoomsManager.ok,
protectionsConfig.ok,
userID,
+12 -32
View File
@@ -43,7 +43,6 @@ import {
import { Draupnir } from "../Draupnir";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
import { DraupnirProtection } from "./Protection";
import { getWatchedPolicyRoomsInfo } from "../commands/StatusCommand";
import { MatrixReactionHandler } from "../commands/interface-manager/MatrixReactionHandler";
import {
MatrixRoomID,
@@ -310,15 +309,14 @@ export class BanPropagationProtection
this.handleBan(ban);
}
for (const unban of unbans) {
void Task(this.handleUnban(unban, this.draupnir));
void Task(this.handleUnban(unban));
}
return Ok(undefined);
}
private handleBan(change: MembershipChange): void {
const policyRevision =
this.protectedRoomsSet.issuerManager.policyListRevisionIssuer
.currentRevision;
this.protectedRoomsSet.watchedPolicyRooms.currentRevision;
const rulesMatchingUser = policyRevision.allRulesMatchingEntity(
change.userID,
PolicyRuleType.User,
@@ -330,13 +328,9 @@ export class BanPropagationProtection
void Task(promptBanPropagation(this.draupnir, change));
}
private async handleUnban(
change: MembershipChange,
draupnir: Draupnir
): Promise<void> {
private async handleUnban(change: MembershipChange): Promise<void> {
const policyRevision =
this.protectedRoomsSet.issuerManager.policyListRevisionIssuer
.currentRevision;
this.protectedRoomsSet.watchedPolicyRooms.currentRevision;
const rulesMatchingUser = policyRevision.allRulesMatchingEntity(
change.userID,
PolicyRuleType.User,
@@ -366,38 +360,25 @@ export class BanPropagationProtection
(map, rule) => addRule(map, rule),
new Map<StringRoomID, PolicyRule[]>()
);
const policyRoomInfo = await getWatchedPolicyRoomsInfo(
draupnir.protectedRoomsSet.issuerManager,
draupnir.policyRoomManager,
draupnir.clientRooms.currentRevision.allJoinedRooms,
draupnir.protectedRoomsSet.allProtectedRooms
);
if (isError(policyRoomInfo)) {
log.error(
`Unable to fetch policy rooms info to be able to prompt to unban ${change.userID}`,
policyRoomInfo.error
);
return;
}
await promptUnbanPropagation(
this.draupnir,
change,
change.roomID,
[...rulesByPolicyRoom.entries()].map(([policyRoomID, rules]) => {
const info = [
...policyRoomInfo.ok.subscribedAndProtectedLists,
...policyRoomInfo.ok.subscribedLists,
].find((i) => i.revision.room.toRoomIDOrAlias() === policyRoomID);
if (info === undefined) {
const profile =
this.draupnir.protectedRoomsSet.watchedPolicyRooms.allRooms.find(
(i) => i.revision.room.toRoomIDOrAlias() === policyRoomID
);
if (profile === undefined) {
throw new TypeError(
`Shouldn't be possible to have a rule from an unwatched list.`
);
}
return {
room: info.revision.room,
room: profile.revision.room,
roomID: policyRoomID,
matches: rules,
profile: info.watchedListProfile,
profile: profile,
};
}),
roomsBannedFrom.map((revision) => revision.room)
@@ -465,8 +446,7 @@ export class BanPropagationProtection
// the unban from lists code should be moved to a standard consequence.
const errors: RoomUpdateError[] = [];
const policyRevision =
this.protectedRoomsSet.issuerManager.policyListRevisionIssuer
.currentRevision;
this.protectedRoomsSet.watchedPolicyRooms.currentRevision;
const rulesMatchingUser = policyRevision.allRulesMatchingEntity(
context.target,
PolicyRuleType.User,
@@ -69,10 +69,9 @@ export class ProtectedJoinedRooms {
}
public async syncProtectedRooms() {
const policyRooms =
this.protectedRoomsSet.issuerManager.allWatchedLists.map((profile) =>
profile.room.toRoomIDOrAlias()
);
const policyRooms = this.protectedRoomsSet.watchedPolicyRooms.allRooms.map(
(profile) => profile.room.toRoomIDOrAlias()
);
const roomsToProtect =
this.clientRooms.currentRevision.allJoinedRooms.filter((roomID) => {
return (
+1 -2
View File
@@ -124,8 +124,7 @@ export class RedactionSynchronisationProtection
change.membershipChangeType === MembershipChangeType.Rejoined
) {
const policyRevision =
this.protectedRoomsSet.issuerManager.policyListRevisionIssuer
.currentRevision;
this.protectedRoomsSet.watchedPolicyRooms.currentRevision;
const matchingPolicy = policyRevision.findRuleMatchingEntity(
change.userID,
PolicyRuleType.User,
@@ -15,7 +15,6 @@ import {
MembershipEvent,
Ok,
PermalinkSchema,
PropagationType,
ProtectedRoomsSet,
RoomEvent,
RoomStateRevision,
@@ -215,11 +214,10 @@ export class WatchRoomsOnInvite {
);
return;
}
const addResult = await this.protectedRoomsSet.issuerManager.watchList(
PropagationType.Direct,
resolvedRoom.ok,
{}
);
const addResult =
await this.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly(
resolvedRoom.ok
);
if (isError(addResult)) {
addResult.elaborate(
`Could not watch the policy room: ${resolvedRoom.ok.toPermalink()}`
+4 -9
View File
@@ -10,7 +10,6 @@ import {
MembershipChangeType,
NoticeMessageContent,
PolicyRuleType,
PropagationType,
RoomMessage,
Value,
findProtection,
@@ -86,10 +85,8 @@ describe("Ban propagation test", function () {
100
);
await draupnir.client.joinRoom(policyListId);
await draupnir.protectedRoomsSet.issuerManager.watchList(
PropagationType.Direct,
MatrixRoomReference.fromRoomID(policyListId as StringRoomID),
{}
await draupnir.protectedRoomsSet.watchedPolicyRooms.watchPolicyRoomDirectly(
MatrixRoomReference.fromRoomID(policyListId as StringRoomID)
);
// check for the prompt
@@ -119,8 +116,7 @@ describe("Ban propagation test", function () {
await new Promise((resolve) => setTimeout(resolve, 10000));
const policyListRevisionAfterBan =
draupnir.protectedRoomsSet.issuerManager.policyListRevisionIssuer
.currentRevision;
draupnir.protectedRoomsSet.watchedPolicyRooms.currentRevision;
const rules = policyListRevisionAfterBan.allRulesMatchingEntity(
spamUserID,
PolicyRuleType.User
@@ -154,8 +150,7 @@ describe("Ban propagation test", function () {
);
await new Promise((resolve) => setTimeout(resolve, 10000));
const policyListRevisionAfterUnBan =
draupnir.protectedRoomsSet.issuerManager.policyListRevisionIssuer
.currentRevision;
draupnir.protectedRoomsSet.watchedPolicyRooms.currentRevision;
const rulesAfterUnban =
policyListRevisionAfterUnBan.allRulesMatchingEntity(
+3 -15
View File
@@ -79,13 +79,9 @@ describe("Test the DraupnirBanCommand", function () {
{
policyRoomManager,
roomResolver,
issuerManager: protectedRoomsSet.issuerManager,
watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms,
defaultReasons: ["spam"],
clientUserID: `@draupnir:ourserver.example.com` as StringUserID,
allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) =>
room.toRoomIDOrAlias()
),
protectedRooms: protectedRoomsSet.allProtectedRooms,
},
{},
MatrixUserIDPresentationType.wrap(
@@ -116,13 +112,9 @@ describe("Test the DraupnirBanCommand", function () {
{
policyRoomManager,
roomResolver,
issuerManager: protectedRoomsSet.issuerManager,
watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms,
defaultReasons: ["spam"],
clientUserID: `@draupnir:ourserver.example.com` as StringUserID,
allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) =>
room.toRoomIDOrAlias()
),
protectedRooms: protectedRoomsSet.allProtectedRooms,
},
{},
MatrixUserIDPresentationType.wrap(
@@ -173,13 +165,9 @@ describe("Test the DraupnirBanCommand", function () {
{
policyRoomManager,
roomResolver,
issuerManager: protectedRoomsSet.issuerManager,
watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms,
defaultReasons: ["spam"],
clientUserID: `@draupnir:ourserver.example.com` as StringUserID,
allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) =>
room.toRoomIDOrAlias()
),
protectedRooms: protectedRoomsSet.allProtectedRooms,
},
{
rest: ["spam"],
+1 -5
View File
@@ -132,7 +132,7 @@ describe("Test the DraupnirUnbanCommand", function () {
setMembership: protectedRoomsSet.setRoomMembership,
managementRoomOutput: createMock<ManagementRoomOutput>(),
roomResolver,
issuerManager: protectedRoomsSet.issuerManager,
watchedPolicyRooms: protectedRoomsSet.watchedPolicyRooms,
clientUserID: `@draupnir:ourserver.example.com` as StringUserID,
noop: false,
roomUnbanner,
@@ -142,10 +142,6 @@ describe("Test the DraupnirUnbanCommand", function () {
return Ok(undefined);
},
}),
allJoinedRooms: protectedRoomsSet.allProtectedRooms.map((room) =>
room.toRoomIDOrAlias()
),
protectedRooms: protectedRoomsSet.allProtectedRooms,
},
{
rest: ["spam"],
+8 -11
View File
@@ -10,9 +10,9 @@ import {
import expect from "expect";
import {
Ok,
PolicyListConfig,
PropagationType,
RoomResolver,
WatchedPolicyRooms,
isError,
isOk,
} from "matrix-protection-suite";
@@ -27,10 +27,9 @@ describe("Test the WatchUnwatchCommmands", function () {
const policyRoom = MatrixRoomReference.fromRoomID(
"!room:example.com" as StringRoomID
);
const issuerManager = createMock<PolicyListConfig>({
async watchList(propagation, room, _options) {
const watchedPolicyRooms = createMock<WatchedPolicyRooms>({
async watchPolicyRoomDirectly(room) {
expect(room).toBe(policyRoom);
expect(propagation).toBe(PropagationType.Direct);
return Ok(undefined);
},
});
@@ -45,21 +44,19 @@ describe("Test the WatchUnwatchCommmands", function () {
it("DraupnirWatchCommand", async function () {
const result = await CommandExecutorHelper.execute(
DraupnirWatchPolicyRoomCommand,
{ issuerManager, roomResolver },
{ watchedPolicyRooms, roomResolver },
{},
policyRoom
);
expect(isOk(result)).toBe(true);
});
it("Draupnir watch command should return an error if the room is already being watched", async function () {
const issuerManagerWithWatchedList = createMock<PolicyListConfig>({
allWatchedLists: [
{ room: policyRoom, propagation: PropagationType.Direct, options: {} },
],
const issuerManagerWithWatchedList = createMock<WatchedPolicyRooms>({
allRooms: [{ room: policyRoom, propagation: PropagationType.Direct }],
});
const result = await CommandExecutorHelper.execute(
DraupnirWatchPolicyRoomCommand,
{ issuerManager: issuerManagerWithWatchedList, roomResolver },
{ watchedPolicyRooms: issuerManagerWithWatchedList, roomResolver },
{},
policyRoom
);
@@ -68,7 +65,7 @@ describe("Test the WatchUnwatchCommmands", function () {
it("DraupnirUnwatchCommand", async function () {
const result = await CommandExecutorHelper.execute(
DraupnirUnwatchPolicyRoomCommand,
{ issuerManager, roomResolver },
{ watchedPolicyRooms, roomResolver },
{},
policyRoom
);