Begin moving most commands to interface-manager and MPS.

This commit is contained in:
gnuxie
2024-04-06 20:03:33 +01:00
parent 67b4c31cce
commit 89bede86c3
15 changed files with 434 additions and 316 deletions
+30 -24
View File
@@ -27,11 +27,11 @@ limitations under the License.
import { findPresentationType, parameters, ParsedKeywords } from "./interface-manager/ParameterParsing";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { MjolnirContext } from "./CommandHandler";
import { MatrixRoomAlias, MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { DraupnirContext } from "./CommandHandler";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { ActionError, ActionResult, isError, MatrixRoomAlias, MatrixRoomReference, Ok } from "matrix-protection-suite";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
// TODO: we should probably add an --admin keyword to these commands
// since they don't actually need admin. Mjolnir had them as admin though.
@@ -53,15 +53,18 @@ defineInterfaceCommand({
description: 'The room to move the alias to.'
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise<CommandResult<void>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise<ActionResult<void>> {
const isAdminResult = await this.draupnir.synapseAdminClient?.isSynapseAdmin();
if (isAdminResult === undefined || isError(isAdminResult) || !isAdminResult.ok) {
return ActionError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
const newRoomId = await room.resolve(this.mjolnir.client);
await this.mjolnir.client.deleteRoomAlias(movingAlias.toRoomIdOrAlias());
await this.mjolnir.client.createRoomAlias(movingAlias.toRoomIdOrAlias(), newRoomId.toRoomIdOrAlias());
return CommandResult.Ok(undefined);
const newRoomID = await resolveRoomReferenceSafe(this.client, room);
if (isError(newRoomID)) {
return newRoomID;
}
await this.draupnir.client.deleteRoomAlias(movingAlias.toRoomIDOrAlias());
await this.draupnir.client.createRoomAlias(movingAlias.toRoomIDOrAlias(), newRoomID.ok.toRoomIDOrAlias());
return Ok(undefined);
},
})
@@ -86,14 +89,17 @@ defineInterfaceCommand({
description: 'The room to add the alias to.'
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise<CommandResult<void>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise<ActionResult<void>> {
const isAdmin = await this.draupnir.synapseAdminClient?.isSynapseAdmin();
if (isAdmin === undefined || isError(isAdmin) || !isAdmin.ok) {
return ActionError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
const roomId = await room.resolve(this.mjolnir.client);
await this.mjolnir.client.createRoomAlias(movingAlias.toRoomIdOrAlias(), roomId.toRoomIdOrAlias());
return CommandResult.Ok(undefined);
const roomID = await resolveRoomReferenceSafe(this.draupnir.client, room);
if (isError(roomID)) {
return roomID;
}
await this.draupnir.client.createRoomAlias(movingAlias.toRoomIDOrAlias(), roomID.ok.toRoomIDOrAlias());
return Ok(undefined);
},
})
@@ -113,13 +119,13 @@ defineInterfaceCommand({
description: 'The alias that should be deleted.'
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, alias: MatrixRoomAlias): Promise<CommandResult<void>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, alias: MatrixRoomAlias): Promise<ActionResult<void>> {
const isAdmin = await this.draupnir.synapseAdminClient?.isSynapseAdmin();
if (isAdmin === undefined || isError(isAdmin) || !isAdmin.ok) {
return ActionError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
await this.mjolnir.client.deleteRoomAlias(alias.toRoomIdOrAlias());
return CommandResult.Ok(undefined);
await this.draupnir.client.deleteRoomAlias(alias.toRoomIDOrAlias());
return Ok(undefined);
},
})
+40 -70
View File
@@ -25,88 +25,57 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { UserID } from "matrix-bot-sdk";
import { MjolnirContext } from "./CommandHandler";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { Mjolnir } from "../Mjolnir";
import { RULE_ROOM, RULE_SERVER, RULE_USER } from "../models/ListRule";
import PolicyList from "../models/PolicyList";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, makePresentationType, ParameterDescription, parameters, ParsedKeywords, RestDescription, simpleTypeValidator, union } from "./interface-manager/ParameterParsing";
import { DraupnirContext } from "./CommandHandler";
import { defineInterfaceCommand,findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, ParameterDescription, parameters, ParsedKeywords, RestDescription, union } from "./interface-manager/ParameterParsing";
import "./interface-manager/MatrixPresentations";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { PromptOptions } from "./interface-manager/PromptForAccept";
import { definePresentationRenderer } from "./interface-manager/DeadDocumentPresentation";
import { DocumentNode } from "./interface-manager/DeadDocument";
import { JSXFactory } from "./interface-manager/JSXFactory";
makePresentationType({
name: "PolicyList",
validator: simpleTypeValidator("PolicyList", (readItem: unknown) => readItem instanceof PolicyList)
})
definePresentationRenderer(findPresentationType("PolicyList"), function(list: PolicyList): DocumentNode {
return <p>
{list.listShortcode} <a href={list.roomRef}>{list.roomId}</a>
</p>
})
import { Draupnir } from "../Draupnir";
import { ActionResult, MatrixRoomReference, PolicyRoomEditor, PolicyRuleType, isError } from "matrix-protection-suite";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
export async function findPolicyListFromRoomReference(mjolnir: Mjolnir, policyListReference: MatrixRoomReference): Promise<CommandResult<PolicyList, CommandError>> {
const policyListRoomId = (await policyListReference.resolve(mjolnir.client)).toRoomIdOrAlias();
const policyList = mjolnir.policyListManager.lists.find(list => list.roomId === policyListRoomId);
if (policyList !== undefined) {
return CommandResult.Ok(policyList);
} else {
// Would it be acceptable to create an anonymous policy list that is not being watched
// by mjolnir for the purposes of banning / unbanning? unbanning requires loading the rules
// but banning doesn't.. so this means you'd want two types of lists
// one of which can only be made by a factory which watches them via sync
// and makes sure mjolnir is joined.
// This refactor would be important for previewing lists regardless.
return CommandError.Result(`There is no policy list that Mjolnir is watching for ${policyListReference.toPermalink()}`);
}
}
export async function findPolicyListFromShortcode(mjolnir: Mjolnir, designator: string): Promise<CommandResult<PolicyList, CommandError>> {
const list = mjolnir.policyListManager.resolveListShortcode(designator);
if (list !== undefined) {
return CommandResult.Ok(list);
} else {
return CommandError.Result(`There is no policy list with the shortcode ${designator} and a default list couldn't be found`);
export async function findPolicyRoomEditorFromRoomReference(draupnir: Draupnir, policyRoomReference: MatrixRoomReference): Promise<ActionResult<PolicyRoomEditor>> {
const policyRoomID = await resolveRoomReferenceSafe(draupnir.client, policyRoomReference);
if (isError(policyRoomID)) {
return policyRoomID;
}
return await draupnir.managerManager.policyRoomManager.getPolicyRoomEditor(policyRoomID.ok);
}
async function ban(
this: MjolnirContext,
this: DraupnirContext,
_keywords: ParsedKeywords,
entity: UserID|MatrixRoomReference|string,
policyListReference: MatrixRoomReference|string|PolicyList,
policyRoomReference: MatrixRoomReference,
...reasonParts: string[]
): Promise<CommandResult<any, CommandError>> {
// first step is to resolve the policy list
const policyListResult = typeof policyListReference === 'string'
? await findPolicyListFromShortcode(this.mjolnir, policyListReference)
: policyListReference instanceof PolicyList
? CommandResult.Ok(policyListReference)
: await findPolicyListFromRoomReference(this.mjolnir, policyListReference);
if (policyListResult.isErr()) {
return policyListResult;
): Promise<ActionResult<string>> {
const policyListEditorResult = await findPolicyRoomEditorFromRoomReference(
this.draupnir,
policyRoomReference
);
if (isError(policyListEditorResult)) {
return policyListEditorResult;
}
const policyList = policyListResult.ok;
const policyListEditor = policyListEditorResult.ok;
const reason = reasonParts.join(' ');
if (entity instanceof UserID) {
await policyList.banEntity(RULE_USER, entity.toString(), reason);
} else if (entity instanceof MatrixRoomReference) {
await policyList.banEntity(RULE_ROOM, entity.toRoomIdOrAlias(), reason);
return await policyListEditor.banEntity(PolicyRuleType.User, entity.toString(), reason);
} else if (typeof entity === 'string') {
return await policyListEditor.banEntity(PolicyRuleType.Server,entity, reason);
} else {
await policyList.banEntity(RULE_SERVER, entity, reason);
const resolvedRoomReference = await resolveRoomReferenceSafe(
this.draupnir.client,
entity
);
if (isError(resolvedRoomReference)) {
return resolvedRoomReference;
}
return await policyListEditor.banEntity(PolicyRuleType.Server, resolvedRoomReference.ok.toRoomIDOrAlias(), reason);
}
return CommandResult.Ok(undefined);
}
defineInterfaceCommand({
@@ -124,23 +93,24 @@ defineInterfaceCommand({
{
name: "list",
acceptor: union(
findPresentationType("MatrixRoomReference"),
findPresentationType("string"),
findPresentationType("PolicyList"),
findPresentationType("MatrixRoomReference")
),
prompt: async function (this: MjolnirContext, parameter: ParameterDescription): Promise<PromptOptions> {
prompt: async function (this: DraupnirContext, _parameter: ParameterDescription): Promise<PromptOptions> {
return {
suggestions: this.mjolnir.policyListManager.lists
suggestions: this.draupnir.managerManager.policyRoomManager.getEditablePolicyRoomIDs(
this.draupnir.clientUserID,
PolicyRuleType.User
)
};
}
},
],
new RestDescription<MjolnirContext>(
new RestDescription<DraupnirContext>(
"reason",
findPresentationType("string"),
async function(_parameter) {
return {
suggestions: this.mjolnir.config.commands.ban.defaultReasons
suggestions: this.draupnir.config.commands.ban.defaultReasons
}
}),
),
+48 -24
View File
@@ -25,31 +25,55 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { Mjolnir } from "../Mjolnir";
import PolicyList from "../models/PolicyList";
import { RichReply } from "matrix-bot-sdk";
import { Permalinks } from "./interface-manager/Permalinks";
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { ActionResult, MatrixRoomAlias, MatrixRoomID, PropagationType, isError } from "matrix-protection-suite";
import { DraupnirContext } from "./CommandHandler";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { ParsedKeywords, findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
// !mjolnir list create <shortcode> <alias localpart>
export async function execCreateListCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const shortcode = parts[3];
const aliasLocalpart = parts[4];
const listRoomId = await PolicyList.createList(
mjolnir.client,
export async function createList(
this: DraupnirContext,
_keywords: ParsedKeywords,
shortcode: string,
alias: MatrixRoomAlias,
...reasonParts: string[]
): Promise<ActionResult<MatrixRoomID>> {
const newList = await this.draupnir.managerManager.policyRoomManager.createPolicyRoom(
shortcode,
[event['sender']],
{ room_alias_name: aliasLocalpart }
[this.event.sender],
{
room_alias_name: alias.toRoomIDOrAlias()
}
);
const roomRef = MatrixRoomReference.fromPermalink(Permalinks.forRoom(listRoomId));
await mjolnir.policyListManager.watchList(roomRef);
await mjolnir.addProtectedRoom(listRoomId);
const html = `Created new list (<a href="${roomRef}">${listRoomId}</a>). This list is now being watched.`;
const text = `Created new list (${roomRef}). This list is now being watched.`;
const reply = RichReply.createFor(roomId, event, text, html);
reply["msgtype"] = "m.notice";
await mjolnir.client.sendMessage(roomId, reply);
if (isError(newList)) {
return newList;
}
const watchResult = await this.draupnir.protectedRoomsSet.issuerManager.watchList(PropagationType.Direct, newList.ok, {});
if (isError(watchResult)) {
return watchResult;
}
return newList;
}
defineInterfaceCommand({
designator: ["list", "create"],
table: "mjolnir",
parameters: parameters([
{
name: "shortcode",
acceptor: findPresentationType("string"),
},
{
name: "alias",
acceptor: findPresentationType("MatrixRoomAlias"),
},
]),
command: createList,
summary: "Create a new Policy Room which can be used to ban users, rooms and servers from your protected rooms"
})
defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("mjolnir", "list", "create"),
renderer: tickCrossRenderer
})
+11 -9
View File
@@ -25,13 +25,12 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { UserID } from "matrix-bot-sdk";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters, ParsedKeywords } from "./interface-manager/ParameterParsing";
import { MjolnirContext } from "./CommandHandler";
import { DraupnirContext } from "./CommandHandler";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { CommandResult, CommandError } from "./interface-manager/Validation";
import { ActionError, ActionResult, Ok, UserID, isError } from "matrix-protection-suite";
defineInterfaceCommand({
table: "synapse admin",
@@ -43,13 +42,16 @@ defineInterfaceCommand({
acceptor: findPresentationType("UserID"),
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, targetUser: UserID): Promise<CommandResult<void, CommandError>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, targetUser: UserID): Promise<ActionResult<void>> {
const isAdmin = await this.draupnir.synapseAdminClient?.isSynapseAdmin();
if (isAdmin === undefined || isError(isAdmin) || !isAdmin.ok) {
return ActionError.Result('I am not a Synapse administrator, or the endpoint to deactivate a user is blocked');
}
await this.mjolnir.deactivateSynapseUser(targetUser.toString());
return CommandResult.Ok(undefined);
if (this.draupnir.synapseAdminClient === undefined) {
throw new TypeError("Shouldn't be happening at this point");
}
await this.draupnir.synapseAdminClient.deactivateUser(targetUser.toString());
return Ok(undefined);
},
})
+18 -12
View File
@@ -27,25 +27,31 @@ limitations under the License.
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { MjolnirBaseExecutor, MjolnirContext } from "./CommandHandler";
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { UserID } from "matrix-bot-sdk";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { DraupnirBaseExecutor, DraupnirContext } from "./CommandHandler";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { ActionError, ActionResult, MatrixRoomReference, Ok, UserID, isError } from "matrix-protection-suite";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
async function hijackRoomCommand(
this: MjolnirContext, _keywords: void, room: MatrixRoomReference, user: UserID
): Promise<CommandResult<void, CommandError>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!this.mjolnir.config.admin?.enableMakeRoomAdminCommand || !isAdmin) {
return CommandError.Result("Either the command is disabled or Mjolnir is not running as homeserver administrator.")
this: DraupnirContext, _keywords: void, room: MatrixRoomReference, user: UserID
): Promise<ActionResult<void>> {
const isAdmin = await this.draupnir.synapseAdminClient?.isSynapseAdmin();
if (!this.draupnir.config.admin?.enableMakeRoomAdminCommand || isAdmin === undefined || isError(isAdmin) || !isAdmin.ok) {
return ActionError.Result("Either the command is disabled or Mjolnir is not running as homeserver administrator.")
}
await this.mjolnir.makeUserRoomAdmin(room.toRoomIdOrAlias(), user.toString());
return CommandResult.Ok(undefined);
if (this.draupnir.synapseAdminClient === undefined) {
throw new TypeError('Should be impossible at this point');
}
const resolvedRoom = await resolveRoomReferenceSafe(this.client, room);
if (isError(resolvedRoom)) {
return resolvedRoom;
}
await this.draupnir.synapseAdminClient?.makeUserRoomAdmin(resolvedRoom.ok.toRoomIDOrAlias(), user.toString());
return Ok(undefined);
}
defineInterfaceCommand<MjolnirBaseExecutor>({
defineInterfaceCommand<DraupnirBaseExecutor>({
designator: ["hijack", "room"],
table: "synapse admin",
parameters: parameters([
+59 -32
View File
@@ -25,26 +25,36 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { Mjolnir } from "../Mjolnir";
import { RichReply } from "matrix-bot-sdk";
import { EntityType } from "../models/ListRule";
import PolicyList from "../models/PolicyList";
import { DraupnirBaseExecutor, DraupnirContext } from "./CommandHandler";
import { ActionResult, MatrixRoomReference, MultipleErrors, PolicyRuleType, RoomActionError, RoomUpdateError, isError } from "matrix-protection-suite";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
// !mjolnir import <room ID> <shortcode>
export async function execImportCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const importRoomId = await mjolnir.client.resolveRoom(parts[2]);
const list = mjolnir.policyListManager.lists.find(b => b.listShortcode === parts[3]) as PolicyList;
if (!list) {
const errMessage = "Unable to find list - check your shortcode.";
const errReply = RichReply.createFor(roomId, event, errMessage, errMessage);
errReply["msgtype"] = "m.notice";
mjolnir.client.sendMessage(roomId, errReply);
return;
export async function importCommand(
this: DraupnirContext,
_keywords: void,
importFromRoomReference: MatrixRoomReference,
policyRoomReference: MatrixRoomReference
): Promise<ActionResult<void>> {
const importFromRoom = await resolveRoomReferenceSafe(this.client, importFromRoomReference);
if (isError(importFromRoom)) {
return importFromRoom;
}
let importedRules = 0;
const state = await mjolnir.client.getRoomState(importRoomId);
const policyRoom = await resolveRoomReferenceSafe(this.client, policyRoomReference);
if (isError(policyRoom)) {
return policyRoom;
}
const policyRoomEditor = await this.draupnir.managerManager.policyRoomManager.getPolicyRoomEditor(
policyRoom.ok
);
if (isError(policyRoomEditor)) {
return policyRoomEditor;
}
const state = await this.client.getRoomState(importFromRoom.ok.toRoomIDOrAlias());
const errors: RoomUpdateError[] = [];
for (const stateEvent of state) {
const content = stateEvent['content'] || {};
if (!content || Object.keys(content).length === 0) continue;
@@ -53,27 +63,44 @@ export async function execImportCommand(roomId: string, event: any, mjolnir: Mjo
// Member event - check for ban
if (content['membership'] === 'ban') {
const reason = content['reason'] || '<no reason>';
await mjolnir.client.sendNotice(mjolnir.managementRoomId, `Adding user ${stateEvent['state_key']} to ban list`);
await list.banEntity(EntityType.RULE_USER, stateEvent['state_key'], reason);
importedRules++;
const result = await policyRoomEditor.ok.banEntity(PolicyRuleType.User, stateEvent['state_key'], reason);
if (isError(result)) {
errors.push(RoomActionError.fromActionError(policyRoom.ok, result.error));
}
}
} else if (stateEvent['type'] === 'm.room.server_acl' && stateEvent['state_key'] === '') {
// ACL event - ban denied servers
if (!content['deny']) continue;
for (const server of content['deny']) {
const reason = "<no reason>";
await mjolnir.client.sendNotice(mjolnir.managementRoomId, `Adding server ${server} to ban list`);
await list.banEntity(EntityType.RULE_SERVER, server, reason);
importedRules++;
const result = await policyRoomEditor.ok.banEntity(PolicyRuleType.Server, server, reason);
if (isError(result)) {
errors.push(RoomActionError.fromActionError(policyRoom.ok, result.error));
}
}
}
}
const message = `Imported ${importedRules} rules to ban list`;
const reply = RichReply.createFor(roomId, event, message, message);
reply['msgtype'] = "m.notice";
await mjolnir.client.sendMessage(roomId, reply);
return MultipleErrors.Result(`There were multiple errors when importing bans from the room ${importFromRoomReference.toPermalink()} to ${policyRoomReference.toPermalink()}`, { errors });
}
defineInterfaceCommand<DraupnirBaseExecutor>({
designator: ["import"],
table: "mjolnir",
parameters: parameters([
{
name: "import from room",
acceptor: findPresentationType("MatrixRoomReference")
},
{
name: "policy room",
acceptor: findPresentationType("MatrixRoomReference")
}
]),
command: importCommand,
summary: "Import user and server bans from a Matrix room and add them to a policy room."
})
defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("mjolnir", "import"),
renderer: tickCrossRenderer
})
+91 -36
View File
@@ -25,43 +25,98 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { Mjolnir } from "../Mjolnir";
import { ActionResult, MatrixEventReference, MatrixEventViaAlias, MatrixEventViaRoomID, MatrixRoomReference, Ok, UserID, isError } from "matrix-protection-suite";
import { redactUserMessagesIn } from "../utils";
import { Permalinks } from "./interface-manager/Permalinks";
import { KeywordsDescription, ParsedKeywords, RestDescription, findPresentationType, parameters, union } from "./interface-manager/ParameterParsing";
import { DraupnirContext } from "./CommandHandler";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
import { Draupnir } from "../Draupnir";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
// !mjolnir redact <user ID> [room alias] [limit]
export async function execRedactCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const userId = parts[2];
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]);
if (parts.length > 4) {
limit = Number.parseInt(parts[4], 10);
}
export async function redactEvent(
draupnir: Draupnir,
reference: MatrixEventReference,
reason: string
): Promise<ActionResult<void>> {
const resolvedRoom = await resolveRoomReferenceSafe(draupnir.client, reference.reference);
if (isError(resolvedRoom)) {
return resolvedRoom;
}
// 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');
if (userId[0] !== '@') {
// Assume it's a permalink
const parsed = Permalinks.parseUrl(parts[2]);
if (parsed.roomIdOrAlias === undefined || parsed.eventId === undefined) {
throw new TypeError(`Got a malformed permalink ${parsed}`)
}
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');
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 draupnir.client.redactEvent(resolvedRoom.ok.toRoomIDOrAlias(), reference.eventID, reason);
return Ok(undefined);
}
export async function redactCommand(
this: DraupnirContext,
keywords: ParsedKeywords,
reference: UserID | MatrixEventReference,
...reasonParts: string[]
): Promise<ActionResult<void>> {
const reason = reasonParts.join(' ');
if (reference instanceof MatrixEventViaAlias || reference instanceof MatrixEventViaRoomID) {
return await redactEvent(this.draupnir, reference, reason);
}
const rawLimit = keywords.getKeyword<string>('limit', undefined);
const limit = rawLimit === undefined ? undefined : Number.parseInt(rawLimit, 10);
const restrictToRoomReference = keywords.getKeyword<MatrixRoomReference>("room", undefined);
const restrictToRoom = restrictToRoomReference ? await resolveRoomReferenceSafe(this.client, restrictToRoomReference) : undefined;
if (restrictToRoom !== undefined && isError(restrictToRoom)) {
return restrictToRoom;
}
const roomsToRedactWithin = restrictToRoom === undefined ? this.draupnir.protectedRoomsSet.protectedRoomsConfig.allRooms : [restrictToRoom.ok];
await redactUserMessagesIn(
this.client,
this.draupnir.managementRoomOutput,
reference.toString(),
roomsToRedactWithin.map((room) => room.toRoomIDOrAlias()),
limit,
this.draupnir.config.noop
);
return Ok(undefined);
}
defineInterfaceCommand({
designator: ["redact"],
table: "mjolnir",
parameters: parameters([
{
name: "entity",
acceptor: union(
findPresentationType("UserID"),
findPresentationType("MatrixEventReference")
),
}],
new RestDescription<DraupnirContext>(
"reason",
findPresentationType("string"),
async function(_parameter) {
return {
suggestions: this.draupnir.config.commands.ban.defaultReasons
}
}
),
new KeywordsDescription({
limit: {
name: "limit",
isFlag: false,
acceptor: findPresentationType("string"),
description: 'Limit the number of messages to be redacted per room.'
},
room: {
name: 'room',
isFlag: false,
acceptor: findPresentationType("MatrixRoomReference"),
description: 'Allows the command to be scoped to just one protected room.'
}
}),
),
command: redactCommand,
summary: "Redacts either a users's recent messagaes within protected rooms or a specific message shared with the bot."
});
defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("mjolnir", "redact"),
renderer: tickCrossRenderer
})
+4 -4
View File
@@ -27,7 +27,7 @@ limitations under the License.
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { MjolnirContext } from "./CommandHandler";
import { DraupnirContext } from "./CommandHandler";
import { MatrixRoomID, MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { CommandResult } from "./interface-manager/Validation";
import { CommandException, CommandExceptionKind } from "./interface-manager/CommandException";
@@ -43,7 +43,7 @@ defineInterfaceCommand({
designator: ["rooms"],
summary: "List all of the protected rooms.",
parameters: parameters([]),
command: async function (this: MjolnirContext, _keywrods): Promise<CommandResult<string[]>> {
command: async function (this: DraupnirContext, _keywrods): Promise<CommandResult<string[]>> {
return CommandResult.Ok(this.mjolnir.protectedRoomsTracker.getProtectedRooms());
}
})
@@ -84,7 +84,7 @@ defineInterfaceCommand({
description: 'The room to protect.'
}
]),
command: async function (this: MjolnirContext, _keywords, roomRef: MatrixRoomReference): Promise<CommandResult<void>> {
command: async function (this: DraupnirContext, _keywords, roomRef: MatrixRoomReference): Promise<CommandResult<void>> {
const roomIDOrError = await (async () => {
try {
return CommandResult.Ok(await roomRef.joinClient(this.mjolnir.client));
@@ -115,7 +115,7 @@ defineInterfaceCommand({
description: 'The room to stop protecting.'
}
]),
command: async function (this: MjolnirContext, _keywords, roomRef: MatrixRoomReference): Promise<CommandResult<void>> {
command: async function (this: DraupnirContext, _keywords, roomRef: MatrixRoomReference): Promise<CommandResult<void>> {
const roomID = await roomRef.resolve(this.mjolnir.client);
await this.mjolnir.removeProtectedRoom(roomID.toRoomIdOrAlias());
try {
+3 -3
View File
@@ -25,7 +25,7 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { MjolnirContext } from "./CommandHandler";
import { DraupnirContext } from "./CommandHandler";
import { renderMatrixAndSend } from "./interface-manager/DeadDocumentMatrix";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { JSXFactory } from "./interface-manager/JSXFactory";
@@ -87,7 +87,7 @@ defineInterfaceCommand({
designator: ["rules"],
table: "mjolnir",
parameters: parameters([]),
command: async function (this: MjolnirContext) {
command: async function (this: DraupnirContext) {
return CommandResult.Ok(
this.mjolnir.policyListManager.lists
.map(list => {
@@ -122,7 +122,7 @@ defineInterfaceCommand({
}
]),
command: async function (
this: MjolnirContext, _keywords, entity: string|UserID|MatrixRoomReference
this: DraupnirContext, _keywords, entity: string|UserID|MatrixRoomReference
): Promise<CommandResult<ListMatches[]>> {
return CommandResult.Ok(
this.mjolnir.policyListManager.lists
+6 -6
View File
@@ -1,9 +1,9 @@
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { ParsedKeywords, RestDescription, findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { MjolnirContext } from "./CommandHandler";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { DraupnirContext } from "./CommandHandler";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { ActionError, ActionResult, Ok } from "matrix-protection-suite";
defineInterfaceCommand({
@@ -12,7 +12,7 @@ defineInterfaceCommand({
summary: "Sets the displayname of the draupnir instance to the specified value in all rooms.",
parameters: parameters(
[],
new RestDescription<MjolnirContext>(
new RestDescription<DraupnirContext>(
"displayname",
findPresentationType("string"),
),
@@ -21,16 +21,16 @@ defineInterfaceCommand({
})
// !draupnir displayname <displayname>
export async function execSetDisplayNameCommand(this: MjolnirContext, _keywords: ParsedKeywords, ...displaynameParts: string[]): Promise<CommandResult<any>> {
export async function execSetDisplayNameCommand(this: DraupnirContext, _keywords: ParsedKeywords, ...displaynameParts: string[]): Promise<ActionResult<void>> {
const displayname = displaynameParts.join(' ');
try {
await this.client.setDisplayName(displayname);
} catch (e) {
const message = e.message || (e.body ? e.body.error : '<no message>');
return CommandError.Result(`Failed to set displayname to ${displayname}: ${message}`)
return ActionError.Result(`Failed to set displayname to ${displayname}: ${message}`)
}
return CommandResult.Ok(undefined);
return Ok(undefined);
}
defineMatrixInterfaceAdaptor({
+43 -19
View File
@@ -25,26 +25,50 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { Mjolnir } from "../Mjolnir";
import { LogLevel, LogService } from "matrix-bot-sdk";
import { ActionResult, MatrixRoomID, MatrixRoomReference, Ok, UserID, isError } from "matrix-protection-suite";
import { DraupnirContext } from "./CommandHandler";
import { ParsedKeywords, RestDescription, findPresentationType, parameters } from "./interface-manager/ParameterParsing";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
import { defineInterfaceCommand } from "./interface-manager/InterfaceCommand";
// !mjolnir powerlevel <user ID> <level> [room]
export async function execSetPowerLevelCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) {
const victim = parts[2];
const level = Math.round(Number(parts[3]));
const inRoom = parts[4];
let targetRooms = inRoom ? [await mjolnir.client.resolveRoom(inRoom)] : mjolnir.protectedRoomsTracker.getProtectedRooms();
for (const targetRoomId of targetRooms) {
try {
await mjolnir.client.setUserPowerLevel(victim, targetRoomId, level);
} catch (e) {
const message = e.message || (e.body ? e.body.error : '<no message>');
LogService.error("SetPowerLevelCommand", e);
await mjolnir.managementRoomOutput.logMessage(LogLevel.ERROR, "SetPowerLevelCommand", `Failed to set power level of ${victim} to ${level} in ${targetRoomId}: ${message}`, targetRoomId);
async function setPowerLevelCommand(
this: DraupnirContext,
_keywords: ParsedKeywords,
user: UserID,
powerLevel: string,
...givenRooms: MatrixRoomReference[]
): Promise<ActionResult<void>> {
const parsedLevel = Number.parseInt(powerLevel, 10);
const resolvedGivenRooms: MatrixRoomID[] = [];
for (const room of givenRooms) {
const resolvedResult = await resolveRoomReferenceSafe(this.client, room);
if (isError(resolvedResult)) {
return resolvedResult;
} else {
resolvedGivenRooms.push(resolvedResult.ok);
}
}
await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅');
const rooms = givenRooms.length === 0 ? this.draupnir.protectedRoomsSet.protectedRoomsConfig.allRooms : resolvedGivenRooms;
for (const room of rooms) {
await this.draupnir.client.setUserPowerLevel(user.toString(), room.toRoomIDOrAlias(), parsedLevel);
}
return Ok(undefined);
}
defineInterfaceCommand({
table: "",
designator: [],
parameters: parameters([
{
name: "user",
acceptor: findPresentationType("UserID")
},
{
name: "power level",
acceptor: findPresentationType("string")
}
],
new RestDescription("rooms", findPresentationType("MatrixRoomReference"))),
command: setPowerLevelCommand,
summary: "Set the power level of a user across the protected rooms set, or within the provided rooms"
})
+25 -10
View File
@@ -27,11 +27,11 @@ limitations under the License.
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters, ParsedKeywords, RestDescription } from "./interface-manager/ParameterParsing";
import { CommandResult, CommandError } from "./interface-manager/Validation";
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { MjolnirContext } from "./CommandHandler";
import { DraupnirContext } from "./CommandHandler";
import { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { ActionError, ActionResult, MatrixRoomReference, Ok, isError } from "matrix-protection-suite";
import { resolveRoomReferenceSafe } from "matrix-protection-suite-for-matrix-bot-sdk";
defineInterfaceCommand({
table: "synapse admin",
@@ -41,17 +41,32 @@ defineInterfaceCommand({
{
name: 'room',
acceptor: findPresentationType("MatrixRoomReference"),
}
},
],
new RestDescription("reason", findPresentationType("string"))),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, targetRoom: MatrixRoomReference, ...reasonParts: string[]): Promise<CommandResult<void, CommandError>> {
const isAdmin = await this.mjolnir.isSynapseAdmin();
if (!isAdmin) {
return CommandError.Result('I am not a Synapse administrator, or the endpoint to shutdown a room is blocked');
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, targetRoom: MatrixRoomReference, ...reasonParts: string[]): Promise<ActionResult<void>> {
const isAdmin = await this.draupnir.synapseAdminClient?.isSynapseAdmin();
if (isAdmin === undefined || isError(isAdmin) || !isAdmin.ok) {
return ActionError.Result('I am not a Synapse administrator, or the endpoint to shutdown a room is blocked');
}
if (this.draupnir.synapseAdminClient === undefined) {
throw new TypeError(`Should be impossible at this point.`);
}
const resolvedRoom = await resolveRoomReferenceSafe(this.client, targetRoom);
if (isError(resolvedRoom)) {
return resolvedRoom;
}
const reason = reasonParts.join(" ");
await this.mjolnir.shutdownSynapseRoom((await targetRoom.resolve(this.client)).toRoomIdOrAlias(), reason);
return CommandResult.Ok(undefined);
await this.draupnir.synapseAdminClient.deleteRoom(
resolvedRoom.ok.toRoomIDOrAlias(),
{
message: reason,
new_room_user_id: this.draupnir.clientUserID,
block: true,
}
);
return Ok(undefined);
},
})
+50 -61
View File
@@ -25,40 +25,34 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { STATE_CHECKING_PERMISSIONS, STATE_NOT_STARTED, STATE_RUNNING, STATE_SYNCING } from "../Mjolnir";
import { RichReply } from "matrix-bot-sdk";
import PolicyList from "../models/PolicyList";
import { PACKAGE_JSON, SOFTWARE_VERSION } from "../config";
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters, RestDescription } from "./interface-manager/ParameterParsing";
import { MjolnirContext } from "./CommandHandler";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { DraupnirContext } from "./CommandHandler";
import { defineMatrixInterfaceAdaptor, MatrixContext, MatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor";
import { MatrixSendClient } from "../MatrixEmitter";
import { JSXFactory } from "./interface-manager/JSXFactory";
import { Protection } from "../protections/Protection";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
import { renderMatrixAndSend } from "./interface-manager/DeadDocumentMatrix";
import { ActionResult, Ok, PolicyRoomRevision, PolicyRoomWatchProfile, PolicyRuleType, isError } from "matrix-protection-suite";
import { Draupnir } from "../Draupnir";
defineInterfaceCommand({
designator: ["status"],
table: "mjolnir",
parameters: parameters([]),
command: async function () { return CommandResult.Ok(mjolnirStatusInfo.call(this)) },
command: async function (this: DraupnirContext) {
return Ok(draupnirStatusInfo(this.draupnir))
},
summary: "Show the status of the bot."
})
export interface ListInfo {
shortcode: string,
roomRef: string,
roomId: string,
serverRules: number,
userRules: number,
roomRules: number,
watchedListProfile: PolicyRoomWatchProfile,
revision: PolicyRoomRevision
}
export interface StatusInfo {
state: string, // a small description of the state of Mjolnir
numberOfProtectedRooms: number,
subscribedLists: ListInfo[],
subscribedAndProtectedLists: ListInfo[],
@@ -66,27 +60,36 @@ export interface StatusInfo {
repository: string
}
function mjolnirStatusInfo(this: MjolnirContext): StatusInfo {
const listInfo = (list: PolicyList): ListInfo => {
return {
shortcode: list.listShortcode,
roomRef: list.roomRef,
roomId: list.roomId,
serverRules: list.serverRules.length,
userRules: list.userRules.length,
roomRules: list.roomRules.length,
async function listInfo(draupnir: Draupnir): Promise<ListInfo[]> {
const watchedListProfiles = draupnir.protectedRoomsSet.issuerManager.allWatchedLists;
const issuerResults = await Promise.all(watchedListProfiles.map((profile) =>
draupnir.managerManager.policyRoomManager.getPolicyRoomRevisionIssuer(profile.room)
));
return issuerResults.map((result) => {
if (isError(result)) {
throw result.error;
}
}
const revision = result.ok.currentRevision;
const associatedProfile = watchedListProfiles.find((profile) => profile.room.toRoomIDOrAlias() === revision.room.toRoomIDOrAlias())
if (associatedProfile === undefined) {
throw new TypeError(`Shouldn't be possible to have got a result for a list profile we don't have`)
}
return {
watchedListProfile: associatedProfile,
revision: revision
}
})
}
// FIXME: need a shoutout to dependencies in here and NOTICE info.
async function draupnirStatusInfo(draupnir: Draupnir): Promise<StatusInfo> {
const watchedListInfo = await listInfo(draupnir);
const protectedWatchedLists = watchedListInfo.filter((info) => draupnir.protectedRoomsSet.isProtectedRoom(info.revision.room.toRoomIDOrAlias()));
const unprotectedListProfiles = watchedListInfo.filter((info) => !draupnir.protectedRoomsSet.isProtectedRoom(info.revision.room.toRoomIDOrAlias()));
return {
state: this.mjolnir.state,
numberOfProtectedRooms: this.mjolnir.protectedRoomsTracker.getProtectedRooms().length,
subscribedLists: this.mjolnir.policyListManager.lists
.filter(list => !this.mjolnir.explicitlyProtectedRooms.includes(list.roomId))
.map(listInfo),
subscribedAndProtectedLists: this.mjolnir.policyListManager.lists
.filter(list => this.mjolnir.explicitlyProtectedRooms.includes(list.roomId))
.map(listInfo),
numberOfProtectedRooms: draupnir.protectedRoomsSet.protectedRoomsConfig.allRooms.length,
subscribedLists: unprotectedListProfiles,
subscribedAndProtectedLists: protectedWatchedLists,
version: SOFTWARE_VERSION,
repository: PACKAGE_JSON['repository'] ?? 'Unknown'
}
@@ -94,49 +97,35 @@ function mjolnirStatusInfo(this: MjolnirContext): StatusInfo {
defineMatrixInterfaceAdaptor({
interfaceCommand: findTableCommand("mjolnir", "status"),
renderer: async function (this: MatrixInterfaceAdaptor<MatrixContext>, client: MatrixSendClient, commandRoomId: string, event: any, result: CommandResult<StatusInfo>): Promise<void> {
const renderState = (state: StatusInfo['state']) => {
const notRunning = (text: string) => {
return <fragment><b>Running: </b> (${text})<br/></fragment>
};
switch (state) {
case STATE_NOT_STARTED:
return notRunning('not started');
case STATE_CHECKING_PERMISSIONS:
return notRunning('checking own permission');
case STATE_SYNCING:
return notRunning('syncing lists');
case STATE_RUNNING:
return <fragment><b>Running: </b><br/></fragment>
default:
return notRunning('unknown state');
}
};
renderer: async function (this, client, commandRoomID, event, result: ActionResult<StatusInfo>): Promise<void> {
const renderPolicyLists = (header: string, lists: ListInfo[]) => {
const listInfo = lists.map(list => {
const renderedLists = lists.map(list => {
return <li>
{list.shortcode} @ <a href={list.roomRef}>{list.roomId}</a>
(rules: {list.serverRules} servers, {list.userRules} users, {list.roomRules} rooms)
<a href={list.revision.room.toPermalink()}>{list.revision.room.toRoomIDOrAlias()}</a> propagation: {list.watchedListProfile.propagation}
(rules: {list.revision.allRulesOfType(PolicyRuleType.Server).length} servers, {list.revision.allRulesOfType(PolicyRuleType.User)} users, {list.revision.allRulesOfType(PolicyRuleType.Room).length} rooms)
</li>
});
return <fragment>
<b>{header}</b><br/>
<ul>
{listInfo.length === 0 ? <li><i>None</i></li> : listInfo}
{renderedLists.length === 0 ? <li><i>None</i></li> : renderedLists}
</ul>
</fragment>
};
if (isError(result)) {
await tickCrossRenderer.call(this, client, commandRoomID, event, result);
return;
}
const info = result.ok;
await renderMatrixAndSend(<root>
{renderState(info.state)}
<b>Protected Rooms: </b>{info.numberOfProtectedRooms}<br/>
{renderPolicyLists('Subscribed policy lists', info.subscribedLists)}
{renderPolicyLists('Subscribed and protected policy lists', info.subscribedAndProtectedLists)}
{renderPolicyLists('Subscribed policy rooms', info.subscribedLists)}
{renderPolicyLists('Subscribed and protected policy rooms', info.subscribedAndProtectedLists)}
<b>Version: </b><code>{info.version}</code><br/>
<b>Repository: </b><code>{info.repository}</code><br/>
</root>,
commandRoomId,
commandRoomID,
event,
client);
}
@@ -151,12 +140,12 @@ defineInterfaceCommand({
acceptor: findPresentationType("string")
},
],
new RestDescription<MjolnirContext>(
new RestDescription<DraupnirContext>(
"subcommand",
findPresentationType("any")
)),
command: async function (
this: MjolnirContext, _keywords, protectionName: string, ...subcommands: string[]
this: DraupnirContext, _keywords, protectionName: string, ...subcommands: string[]
): Promise<CommandResult<Awaited<ReturnType<Protection['statusCommand']>>>> {
const protection = this.mjolnir.protectionManager.getProtection(protectionName);
if (!protection) {
+3 -3
View File
@@ -25,7 +25,7 @@ limitations under the License.
* are NOT distributed, contributed, committed, or licensed under the Apache License.
*/
import { MjolnirContext } from "./CommandHandler";
import { DraupnirContext } from "./CommandHandler";
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { findPresentationType, KeywordsDescription, parameters, ParsedKeywords, union } from "./interface-manager/ParameterParsing";
import { UserID, MatrixGlob, LogLevel } from "matrix-bot-sdk";
@@ -68,7 +68,7 @@ async function unbanUserFromRooms(mjolnir: Mjolnir, rule: MatrixGlob) {
}
async function unban(
this: MjolnirContext,
this: DraupnirContext,
keywords: ParsedKeywords,
entity: UserID|MatrixRoomReference|string,
policyListReference: MatrixRoomReference|string,
@@ -126,7 +126,7 @@ defineInterfaceCommand({
findPresentationType("string"),
findPresentationType("PolicyList"),
),
prompt: async function (this: MjolnirContext) {
prompt: async function (this: DraupnirContext) {
return {
suggestions: this.mjolnir.policyListManager.lists
};
+3 -3
View File
@@ -27,7 +27,7 @@ limitations under the License.
import { defineInterfaceCommand, findTableCommand } from "./interface-manager/InterfaceCommand";
import { findPresentationType, parameters, ParsedKeywords } from "./interface-manager/ParameterParsing";
import { MjolnirContext } from "./CommandHandler";
import { DraupnirContext } from "./CommandHandler";
import { MatrixRoomReference } from "./interface-manager/MatrixRoomReference";
import { CommandError, CommandResult } from "./interface-manager/Validation";
import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer";
@@ -43,7 +43,7 @@ defineInterfaceCommand({
acceptor: findPresentationType("MatrixRoomReference"),
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, list: MatrixRoomReference): Promise<CommandResult<void, CommandError>> {
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, list: MatrixRoomReference): Promise<CommandResult<void, CommandError>> {
await this.mjolnir.policyListManager.watchList(list);
return CommandResult.Ok(undefined);
},
@@ -64,7 +64,7 @@ defineInterfaceCommand({
acceptor: findPresentationType("MatrixRoomReference"),
}
]),
command: async function (this: MjolnirContext, _keywords: ParsedKeywords, list: MatrixRoomReference): Promise<CommandResult<void, CommandError>> {
command: async function (this: DraupnirContext, _keywords: ParsedKeywords, list: MatrixRoomReference): Promise<CommandResult<void, CommandError>> {
await this.mjolnir.policyListManager.unwatchList(list);
return CommandResult.Ok(undefined);
},