From 99bbbf5b01432266335a3d7189241175e651c7d2 Mon Sep 17 00:00:00 2001 From: gnuxie Date: Fri, 11 Apr 2025 11:57:36 +0100 Subject: [PATCH] Update the deactivate command to use the audit log and purging deactivate. --- src/Draupnir.ts | 9 ++++ .../server-admin/DeactivateCommand.ts | 53 ++++++++++++++++--- 2 files changed, 55 insertions(+), 7 deletions(-) diff --git a/src/Draupnir.ts b/src/Draupnir.ts index 28bb782a..7f29f9b8 100644 --- a/src/Draupnir.ts +++ b/src/Draupnir.ts @@ -83,6 +83,7 @@ import { } from "./commands/interface-manager/MatrixPromptForConfirmation"; import { SynapseHttpAntispam } from "./webapis/SynapseHTTPAntispam/SynapseHttpAntispam"; import { DraupnirStores } from "./backingstore/DraupnirStores"; +import { HomeserverUserPurgingDeactivate } from "./protections/HomeserverUserPolicyApplication/HomeserverUserPurgingDeactivate"; const log = new Logger("Draupnir"); // webAPIS should not be included on the Draupnir class. @@ -116,6 +117,14 @@ export class Draupnir implements Client, MatrixAdaptorContext { public readonly reactionHandler: MatrixReactionHandler; + public readonly purgingDeactivate = + this.synapseAdminClient && this.stores.restrictionAuditLog + ? new HomeserverUserPurgingDeactivate( + this.synapseAdminClient, + this.stores.restrictionAuditLog + ) + : undefined; + private readonly timelineEventListener = this.handleTimelineEvent.bind(this); public readonly capabilityMessageRenderer: RendererMessageCollector; diff --git a/src/commands/server-admin/DeactivateCommand.ts b/src/commands/server-admin/DeactivateCommand.ts index fa54f031..a7e1e355 100644 --- a/src/commands/server-admin/DeactivateCommand.ts +++ b/src/commands/server-admin/DeactivateCommand.ts @@ -1,4 +1,4 @@ -// Copyright 2022 Gnuxie +// Copyright 2022 - 2025 Gnuxie // Copyright 2019 The Matrix.org Foundation C.I.C. // // SPDX-License-Identifier: AFL-3.0 AND Apache-2.0 @@ -8,8 +8,9 @@ // https://github.com/matrix-org/mjolnir // -import { Ok, Result, isError } from "@gnuxie/typescript-result"; +import { Result, ResultError, isError } from "@gnuxie/typescript-result"; import { + BasicInvocationInformation, MatrixUserIDPresentationType, describeCommand, tuple, @@ -17,6 +18,7 @@ import { import { ActionError } from "matrix-protection-suite"; import { Draupnir } from "../../Draupnir"; import { DraupnirInterfaceAdaptor } from "../DraupnirCommandPrerequisites"; +import { deactivateUser } from "../../protections/HomeserverUserPolicyApplication/deactivateUser"; export const SynapseAdminDeactivateCommand = describeCommand({ summary: "Deactivate a user on the homeserver.", @@ -25,24 +27,61 @@ export const SynapseAdminDeactivateCommand = describeCommand({ description: "The user to deactivate", acceptor: MatrixUserIDPresentationType, }), + keywords: { + keywordDescriptions: { + "purge-messages": { + isFlag: true, + description: + "Restrict access to the account until Draupnir removes all of their messages, and then finally deactivate.", + }, + }, + }, async executor( draupnir: Draupnir, - _info, - _keywords, + info: BasicInvocationInformation, + keywords, _rest, targetUser ): Promise> { const isAdmin = await draupnir.synapseAdminClient?.isSynapseAdmin(); - if (isAdmin === undefined || isError(isAdmin) || !isAdmin.ok) { + if ( + isAdmin === undefined || + isError(isAdmin) || + !isAdmin.ok || + !draupnir.purgingDeactivate + ) { return ActionError.Result( "I am not a Synapse administrator, or the endpoint to deactivate a user is blocked" ); } + if (draupnir.stores.restrictionAuditLog === undefined) { + return ResultError.Result( + "The user restriction audit log is not configured" + ); + } if (draupnir.synapseAdminClient === undefined) { throw new TypeError("Shouldn't be happening at this point"); } - await draupnir.synapseAdminClient.deactivateUser(targetUser.toString()); - return Ok(undefined); + const isPurgingDeactivate = keywords.getKeywordValue( + "purge-messages", + false + ); + const deactivateResult = await (() => + isPurgingDeactivate + ? draupnir.purgingDeactivate.beginPurgeUser(targetUser.toString(), { + sender: info.commandSender, + rule: null, + }) + : deactivateUser( + targetUser.toString(), + draupnir.synapseAdminClient, + draupnir.stores.restrictionAuditLog, + { + sender: info.commandSender, + rule: null, + } + ))(); + return deactivateResult; }, });