From 1aa97b7c09dc118552ad2ea2a93d59656a78810e Mon Sep 17 00:00:00 2001 From: gnuxie Date: Tue, 21 Feb 2023 13:08:23 +0000 Subject: [PATCH] Add AliasCommands to Synapse admin table Not sure whether this will be their home in the long term but for now it'll do. --- src/commands/AliasCommands.ts | 163 +++++++++++++++++++-------------- src/commands/CommandHandler.ts | 15 +-- src/commands/ResolveAlias.ts | 43 +++++++++ 3 files changed, 143 insertions(+), 78 deletions(-) create mode 100644 src/commands/ResolveAlias.ts diff --git a/src/commands/AliasCommands.ts b/src/commands/AliasCommands.ts index c2455824..ec58ae46 100644 --- a/src/commands/AliasCommands.ts +++ b/src/commands/AliasCommands.ts @@ -25,78 +25,105 @@ 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 { htmlEscape } from "../utils"; +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 { defineMatrixInterfaceAdaptor } from "./interface-manager/MatrixInterfaceAdaptor"; +import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer"; -// !mjolnir move -export async function execMoveAliasCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { - const movingAlias = parts[2]; - const targetRoom = parts[3]; +// TODO: we should probably add an --admin keyword to these commands +// since they don't actually need admin. Mjolnir had them as admin though. +// then we'd have to call the table "alias table" or something. - const isAdmin = await mjolnir.isSynapseAdmin(); - if (!isAdmin) { - 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); - return; - } +defineInterfaceCommand({ + table: "synapse admin", + designator: ["alias", "move"], + summary: "Move an alias from one room to another.", + parameters: parameters([ + { + name: 'alias', + acceptor: findPresentationType("MatrixRoomAlias"), + description: 'The alias that should be moved.' + }, + { + name: 'new room', + acceptor: findPresentationType("MatrixRoomReference"), + description: 'The room to move the alias to.' + } + ]), + command: async function (this: MjolnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise> { + 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'); + } + 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); + }, +}) - await mjolnir.client.deleteRoomAlias(movingAlias); - const newRoomId = await mjolnir.client.resolveRoom(targetRoom); - await mjolnir.client.createRoomAlias(movingAlias, newRoomId); +defineMatrixInterfaceAdaptor({ + interfaceCommand: findTableCommand("synapse admin", "alias", "move"), + renderer: tickCrossRenderer, +}) - await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅'); -} +defineInterfaceCommand({ + table: "synapse admin", + designator: ["alias", "add"], + summary: "Add a new alias to a room.", + parameters: parameters([ + { + name: 'alias', + acceptor: findPresentationType("MatrixRoomAlias"), + description: 'The alias that should be created.' + }, + { + name: 'target room', + acceptor: findPresentationType("MatrixRoomReference"), + description: 'The room to add the alias to.' + } + ]), + command: async function (this: MjolnirContext, _keywords: ParsedKeywords, movingAlias: MatrixRoomAlias, room: MatrixRoomReference): Promise> { + 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'); + } + const roomId = await room.resolve(this.mjolnir.client); + await this.mjolnir.client.createRoomAlias(movingAlias.toRoomIdOrAlias(), roomId.toRoomIdOrAlias()); + return CommandResult.Ok(undefined); + }, +}) -// !mjolnir alias add -export async function execAddAliasCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { - const aliasToAdd = parts[3]; - const targetRoom = parts[4]; +defineMatrixInterfaceAdaptor({ + interfaceCommand: findTableCommand("synapse admin", "alias", "add"), + renderer: tickCrossRenderer, +}) - const isAdmin = await mjolnir.isSynapseAdmin(); - if (!isAdmin) { - 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); - return; - } +defineInterfaceCommand({ + table: "synapse admin", + designator: ["alias", "remove"], + summary: "Removes an alias from a room.", + parameters: parameters([ + { + name: 'alias', + acceptor: findPresentationType("MatrixRoomAlias"), + description: 'The alias that should be deleted.' + } + ]), + command: async function (this: MjolnirContext, _keywords: ParsedKeywords, alias: MatrixRoomAlias): Promise> { + 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'); + } + await this.mjolnir.client.deleteRoomAlias(alias.toRoomIdOrAlias()); + return CommandResult.Ok(undefined); + }, +}) - const newRoomId = await mjolnir.client.resolveRoom(targetRoom); - await mjolnir.client.createRoomAlias(aliasToAdd, newRoomId); - - await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅'); -} - -// !mjolnir alias remove -export async function execRemoveAliasCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { - const aliasToRemove = parts[3]; - - const isAdmin = await mjolnir.isSynapseAdmin(); - if (!isAdmin) { - 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); - return; - } - - await mjolnir.client.deleteRoomAlias(aliasToRemove); - - await mjolnir.client.unstableApis.addReactionToEvent(roomId, event['event_id'], '✅'); -} - -// !mjolnir resolve -export async function execResolveCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { - const toResolve = parts[2]; - - const resolvedRoomId = await mjolnir.client.resolveRoom(toResolve); - - const message = `Room ID for ${toResolve} is ${resolvedRoomId}`; - const html = `Room ID for ${htmlEscape(toResolve)} is ${htmlEscape(resolvedRoomId)}`; - const reply = RichReply.createFor(roomId, event, message, html); - reply["msgtype"] = "m.notice"; - await mjolnir.client.sendMessage(roomId, reply); -} +defineMatrixInterfaceAdaptor({ + interfaceCommand: findTableCommand("synapse admin", "alias", "remove"), + renderer: tickCrossRenderer, +}) diff --git a/src/commands/CommandHandler.ts b/src/commands/CommandHandler.ts index 9a676fe1..e31c7c98 100644 --- a/src/commands/CommandHandler.ts +++ b/src/commands/CommandHandler.ts @@ -42,17 +42,18 @@ import { import { execListProtectedRooms } from "./ListProtectedRoomsCommand"; import { execAddProtectedRoom, execRemoveProtectedRoom } from "./AddRemoveProtectedRoomsCommand"; import { execSetPowerLevelCommand } from "./SetPowerLevelCommand"; -import { execAddAliasCommand, execMoveAliasCommand, execRemoveAliasCommand, execResolveCommand } from "./AliasCommands"; +import { execResolveCommand } from "./ResolveAlias"; import { execKickCommand } from "./KickCommand"; import { parse as tokenize } from "shell-quote"; import { execSinceCommand } from "./SinceCommand"; import { readCommand } from "./interface-manager/CommandReader"; -import { BaseFunction, CommandTable, defineCommandTable, findTableCommand } from "./interface-manager/InterfaceCommand"; +import { BaseFunction, CommandTable, defineCommandTable, findCommandTable, findTableCommand } from "./interface-manager/InterfaceCommand"; import { findMatrixInterfaceAdaptor, MatrixContext } from "./interface-manager/MatrixInterfaceAdaptor"; import { ArgumentStream } from "./interface-manager/ParameterParsing"; import { CommandResult } from "./interface-manager/Validation"; import { CommandException } from "./interface-manager/CommandException"; import { tickCrossRenderer } from "./interface-manager/MatrixHelpRenderer"; +import "./interface-manager/MatrixPresentations"; export interface MjolnirContext extends MatrixContext { mjolnir: Mjolnir, @@ -65,9 +66,9 @@ import "./HijackRoomCommand"; import "./ShutdownRoomCommand"; import "./DeactivateCommand"; import "./AddRemoveProtectedRoomsCommand"; +import "./AliasCommands"; -defineCommandTable("mjolnir"); -import "./interface-manager/MatrixPresentations"; +defineCommandTable("mjolnir").importTable(findCommandTable("synapse admin")); import "./Ban"; import "./Unban"; import "./StatusCommand"; @@ -123,12 +124,6 @@ export async function handleCommand(roomId: string, event: { content: { body: st return await execRemoveProtectedRoom(roomId, event, mjolnir, parts); } else if (parts[1] === 'rooms' && parts.length === 2) { return await execListProtectedRooms(roomId, event, mjolnir); - } else if (parts[1] === 'move' && parts.length > 3) { - return await execMoveAliasCommand(roomId, event, mjolnir, parts); - } else if (parts[1] === 'alias' && parts.length > 4 && parts[2] === 'add') { - return await execAddAliasCommand(roomId, event, mjolnir, parts); - } else if (parts[1] === 'alias' && parts.length > 3 && parts[2] === 'remove') { - return await execRemoveAliasCommand(roomId, event, mjolnir, parts); } else if (parts[1] === 'resolve' && parts.length > 2) { return await execResolveCommand(roomId, event, mjolnir, parts); } else if (parts[1] === 'powerlevel' && parts.length > 3) { diff --git a/src/commands/ResolveAlias.ts b/src/commands/ResolveAlias.ts new file mode 100644 index 00000000..e1d9806d --- /dev/null +++ b/src/commands/ResolveAlias.ts @@ -0,0 +1,43 @@ +/** + * Copyright (C) 2022 Gnuxie + * All rights reserved. + * + * This file is modified and is NOT licensed under the Apache License. + * This modified file incorperates work from mjolnir + * https://github.com/matrix-org/mjolnir + * which included the following license notice: + +Copyright 2020 The Matrix.org Foundation C.I.C. + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. + * + * However, this file is modified and the modifications in this file + * are NOT distributed, contributed, committed, or licensed under the Apache License. + */ + +import { Mjolnir } from "../Mjolnir"; +import { RichReply } from "matrix-bot-sdk"; +import { htmlEscape } from "../utils"; + +// !mjolnir resolve +export async function execResolveCommand(roomId: string, event: any, mjolnir: Mjolnir, parts: string[]) { + const toResolve = parts[2]; + + const resolvedRoomId = await mjolnir.client.resolveRoom(toResolve); + + const message = `Room ID for ${toResolve} is ${resolvedRoomId}`; + const html = `Room ID for ${htmlEscape(toResolve)} is ${htmlEscape(resolvedRoomId)}`; + const reply = RichReply.createFor(roomId, event, message, html); + reply["msgtype"] = "m.notice"; + await mjolnir.client.sendMessage(roomId, reply); +}