mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-10-23 17:32:22 +00:00
Merge pull request #794 from the-draupnir-project/gnuxie/user-suspension
Add commands to suspend/unsuspend users via the synapse admin API - I have no idea how this interacts with MAS - There is no locking available in the synapse admin API.
This commit is contained in:
8 files changed
+182
-21
No files matched your search
+1
-1
@@ -64,7 +64,7 @@
|
||||
"matrix-appservice-bridge": "^10.3.1",
|
||||
"matrix-bot-sdk": "npm:@vector-im/matrix-bot-sdk@^0.7.1-element.6",
|
||||
"matrix-protection-suite": "npm:@gnuxie/matrix-protection-suite@3.1.0",
|
||||
"matrix-protection-suite-for-matrix-bot-sdk": "npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@3.1.0",
|
||||
"matrix-protection-suite-for-matrix-bot-sdk": "npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@3.1.1",
|
||||
"pg": "^8.8.0",
|
||||
"yaml": "^2.3.2"
|
||||
},
|
||||
|
||||
@@ -15,9 +15,9 @@ import {
|
||||
} from "./AliasCommands";
|
||||
import { DraupnirBanCommand } from "./Ban";
|
||||
import { DraupnirListCreateCommand } from "./CreateBanListCommand";
|
||||
import { SynapseAdminDeactivateCommand } from "./DeactivateCommand";
|
||||
import { SynapseAdminDeactivateCommand } from "./server-admin/DeactivateCommand";
|
||||
import { DraupnirHelpCommand } from "./Help";
|
||||
import { SynapseAdminHijackRoomCommand } from "./HijackRoomCommand";
|
||||
import { SynapseAdminHijackRoomCommand } from "./server-admin/HijackRoomCommand";
|
||||
import { DraupnirImportCommand } from "./ImportCommand";
|
||||
import { DraupnirKickCommand } from "./KickCommand";
|
||||
import {
|
||||
@@ -43,7 +43,7 @@ import {
|
||||
} from "./Rules";
|
||||
import { DraupnirDisplaynameCommand } from "./SetDisplayNameCommand";
|
||||
import { DraupnirSetPowerLevelCommand } from "./SetPowerLevelCommand";
|
||||
import { SynapseAdminShutdownRoomCommand } from "./ShutdownRoomCommand";
|
||||
import { SynapseAdminShutdownRoomCommand } from "./server-admin/ShutdownRoomCommand";
|
||||
import { DraupnirStatusCommand } from "./StatusCommand";
|
||||
import { DraupnirUnbanCommand } from "./unban/Unban";
|
||||
import {
|
||||
@@ -55,14 +55,20 @@ import { DraupnirSafeModeCommand } from "./SafeModeCommand";
|
||||
import { DraupnirProtectionsShowCommand } from "./ProtectionsShowCommand";
|
||||
import { DraupnirProtectionsCapabilityCommand } from "./ProtectionsCapabilitiesCommand";
|
||||
import { JoinWaveCommandTable } from "../protections/JoinWaveShortCircuit";
|
||||
import { DraupnirTakedownCommand } from "./Takedown";
|
||||
import { DraupnirTakedownCommand } from "./server-admin/Takedown";
|
||||
import {
|
||||
SynapseAdminSuspendUserCommand,
|
||||
SynapseAdminUnsuspendUserCommand,
|
||||
} from "./server-admin/SuspendCommand";
|
||||
|
||||
// TODO: These commands should all be moved to subdirectories tbh and this
|
||||
// should be split like an index file for each subdirectory.
|
||||
export const SynapseAdminCommands = new StandardCommandTable("synapse admin")
|
||||
.internCommand(SynapseAdminDeactivateCommand, ["deactivate"])
|
||||
.internCommand(SynapseAdminHijackRoomCommand, ["hijack", "room"])
|
||||
.internCommand(SynapseAdminShutdownRoomCommand, ["shutdown", "room"]);
|
||||
.internCommand(SynapseAdminShutdownRoomCommand, ["shutdown", "room"])
|
||||
.internCommand(SynapseAdminSuspendUserCommand, ["suspend"])
|
||||
.internCommand(SynapseAdminUnsuspendUserCommand, ["unsuspend"]);
|
||||
|
||||
const DraupnirCommands = new StandardCommandTable("draupnir")
|
||||
.internCommand(DraupnirAliasMoveCommand, ["alias", "move"])
|
||||
|
||||
@@ -15,8 +15,8 @@ import {
|
||||
tuple,
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { ActionError } from "matrix-protection-suite";
|
||||
import { Draupnir } from "../Draupnir";
|
||||
import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites";
|
||||
import { Draupnir } from "../../Draupnir";
|
||||
import { DraupnirInterfaceAdaptor } from "../DraupnirCommandPrerequisites";
|
||||
|
||||
export const SynapseAdminDeactivateCommand = describeCommand({
|
||||
summary: "Deactivate a user on the homeserver.",
|
||||
@@ -21,8 +21,8 @@ import {
|
||||
describeCommand,
|
||||
tuple,
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { Draupnir } from "../Draupnir";
|
||||
import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites";
|
||||
import { Draupnir } from "../../Draupnir";
|
||||
import { DraupnirInterfaceAdaptor } from "../DraupnirCommandPrerequisites";
|
||||
|
||||
export const SynapseAdminHijackRoomCommand = describeCommand({
|
||||
summary:
|
||||
+2
-2
@@ -15,9 +15,9 @@ import {
|
||||
describeCommand,
|
||||
tuple,
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { Draupnir } from "../Draupnir";
|
||||
import { Draupnir } from "../../Draupnir";
|
||||
import { ActionError } from "matrix-protection-suite";
|
||||
import { DraupnirInterfaceAdaptor } from "./DraupnirCommandPrerequisites";
|
||||
import { DraupnirInterfaceAdaptor } from "../DraupnirCommandPrerequisites";
|
||||
|
||||
export const SynapseAdminShutdownRoomCommand = describeCommand({
|
||||
summary:
|
||||
@@ -0,0 +1,155 @@
|
||||
// SPDX-FileCopyrightText: 2025 Gnuxie <Gnuxie@protonmail.com>
|
||||
//
|
||||
// SPDX-License-Identifier: AFL-3.0
|
||||
|
||||
import {
|
||||
DeadDocumentJSX,
|
||||
describeCommand,
|
||||
MatrixUserIDPresentationType,
|
||||
tuple,
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { Draupnir } from "../../Draupnir";
|
||||
import { isError, Ok, Result, ResultError } from "@gnuxie/typescript-result";
|
||||
import { StringUserID } from "@the-draupnir-project/matrix-basic-types";
|
||||
import { DraupnirInterfaceAdaptor } from "../DraupnirCommandPrerequisites";
|
||||
import { renderMentionPill } from "../interface-manager/MatrixHelpRenderer";
|
||||
|
||||
type SuspensionPreview = {
|
||||
userID: StringUserID;
|
||||
};
|
||||
|
||||
export const SynapseAdminSuspendUserCommand = describeCommand({
|
||||
summary:
|
||||
"Suspend a user on the homeserver, this allows them to login but not interact with anything",
|
||||
parameters: tuple({
|
||||
name: "user",
|
||||
description: "The user to suspend",
|
||||
acceptor: MatrixUserIDPresentationType,
|
||||
}),
|
||||
keywords: {
|
||||
keywordDescriptions: {
|
||||
"no-confirm": {
|
||||
isFlag: true,
|
||||
description:
|
||||
"Runs the command without the preview of the unban and the confirmation prompt.",
|
||||
},
|
||||
},
|
||||
},
|
||||
async executor(
|
||||
draupnir: Draupnir,
|
||||
_info,
|
||||
keywords,
|
||||
_rest,
|
||||
targetUser
|
||||
): Promise<Result<SuspensionPreview>> {
|
||||
const isAdmin = await draupnir.synapseAdminClient?.isSynapseAdmin();
|
||||
if (
|
||||
draupnir.synapseAdminClient === undefined ||
|
||||
isAdmin === undefined ||
|
||||
isError(isAdmin) ||
|
||||
!isAdmin.ok
|
||||
) {
|
||||
return ResultError.Result(
|
||||
"I am not a Synapse administrator, or the endpoint to deactivate a user is blocked"
|
||||
);
|
||||
}
|
||||
const preview = {
|
||||
userID: targetUser.toString(),
|
||||
};
|
||||
const isNoConfirm = keywords.getKeywordValue<boolean>("no-confirm", false);
|
||||
if (!isNoConfirm) {
|
||||
return Ok(preview);
|
||||
}
|
||||
const suspensionResult = await draupnir.synapseAdminClient.suspendUser(
|
||||
targetUser.toString()
|
||||
);
|
||||
if (isError(suspensionResult)) {
|
||||
return suspensionResult;
|
||||
} else {
|
||||
return Ok(preview);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
DraupnirInterfaceAdaptor.describeRenderer(SynapseAdminSuspendUserCommand, {
|
||||
isAlwaysSupposedToUseDefaultRenderer: true,
|
||||
confirmationPromptJSXRenderer(commandResult) {
|
||||
if (isError(commandResult)) {
|
||||
return Ok(undefined);
|
||||
}
|
||||
return Ok(
|
||||
<root>
|
||||
You are about to suspend the user{" "}
|
||||
{renderMentionPill(commandResult.ok.userID, commandResult.ok.userID)}{" "}
|
||||
<code>{commandResult.ok.userID}</code>. Doing so will prevent further
|
||||
activity from their account. However, they will still be able to login,
|
||||
manage their account, and redact messages. See
|
||||
https://spec.matrix.org/v1.14/client-server-api/#account-suspension for
|
||||
a complete explanation.
|
||||
</root>
|
||||
);
|
||||
},
|
||||
JSXRenderer(commandResult) {
|
||||
if (isError(commandResult)) {
|
||||
return Ok(undefined);
|
||||
}
|
||||
return Ok(
|
||||
<root>
|
||||
The user <code>{commandResult.ok.userID}</code> has been suspended.
|
||||
</root>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export const SynapseAdminUnsuspendUserCommand = describeCommand({
|
||||
summary: "Unsuspend a user on the homeserver that was previously suspended",
|
||||
parameters: tuple({
|
||||
name: "user",
|
||||
description: "The user to unsuspend",
|
||||
acceptor: MatrixUserIDPresentationType,
|
||||
}),
|
||||
async executor(
|
||||
draupnir: Draupnir,
|
||||
_info,
|
||||
_keywords,
|
||||
_rest,
|
||||
targetUser
|
||||
): Promise<Result<SuspensionPreview>> {
|
||||
const isAdmin = await draupnir.synapseAdminClient?.isSynapseAdmin();
|
||||
if (
|
||||
draupnir.synapseAdminClient === undefined ||
|
||||
isAdmin === undefined ||
|
||||
isError(isAdmin) ||
|
||||
!isAdmin.ok
|
||||
) {
|
||||
return ResultError.Result(
|
||||
"I am not a Synapse administrator, or the endpoint to deactivate a user is blocked"
|
||||
);
|
||||
}
|
||||
const preview = {
|
||||
userID: targetUser.toString(),
|
||||
};
|
||||
const suspensionResult = await draupnir.synapseAdminClient.unsuspendUser(
|
||||
targetUser.toString()
|
||||
);
|
||||
if (isError(suspensionResult)) {
|
||||
return suspensionResult;
|
||||
} else {
|
||||
return Ok(preview);
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
DraupnirInterfaceAdaptor.describeRenderer(SynapseAdminUnsuspendUserCommand, {
|
||||
isAlwaysSupposedToUseDefaultRenderer: true,
|
||||
JSXRenderer(commandResult) {
|
||||
if (isError(commandResult)) {
|
||||
return Ok(undefined);
|
||||
}
|
||||
return Ok(
|
||||
<root>
|
||||
The user <code>{commandResult.ok.userID}</code> has been unsuspended.
|
||||
</root>
|
||||
);
|
||||
},
|
||||
});
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
tuple,
|
||||
union,
|
||||
} from "@the-draupnir-project/interface-manager";
|
||||
import { findPolicyRoomEditorFromRoomReference } from "./Ban";
|
||||
import { findPolicyRoomEditorFromRoomReference } from "../Ban";
|
||||
import {
|
||||
isError,
|
||||
Logger,
|
||||
@@ -38,10 +38,10 @@ import {
|
||||
import {
|
||||
DraupnirContextToCommandContextTranslator,
|
||||
DraupnirInterfaceAdaptor,
|
||||
} from "./DraupnirCommandPrerequisites";
|
||||
import { renderRoomPill } from "./interface-manager/MatrixHelpRenderer";
|
||||
import { RoomDetailsProvider } from "../capabilities/RoomTakedownCapability";
|
||||
import { SynapseAdminRoomDetailsProvider } from "../capabilities/SynapseAdminRoomTakedown/SynapseAdminRoomTakedown";
|
||||
} from "../DraupnirCommandPrerequisites";
|
||||
import { renderRoomPill } from "../interface-manager/MatrixHelpRenderer";
|
||||
import { RoomDetailsProvider } from "../../capabilities/RoomTakedownCapability";
|
||||
import { SynapseAdminRoomDetailsProvider } from "../../capabilities/SynapseAdminRoomTakedown/SynapseAdminRoomTakedown";
|
||||
|
||||
const log = new Logger("DraupnirTakedownCommand");
|
||||
|
||||
@@ -2593,10 +2593,10 @@ matrix-appservice@^2.0.0:
|
||||
request-promise "^4.2.6"
|
||||
sanitize-html "^2.11.0"
|
||||
|
||||
"matrix-protection-suite-for-matrix-bot-sdk@npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@3.1.0":
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@gnuxie/matrix-protection-suite-for-matrix-bot-sdk/-/matrix-protection-suite-for-matrix-bot-sdk-3.1.0.tgz#36ed640f6425f568e85c880b6e3da87019e06db5"
|
||||
integrity sha512-dgagHqAupTj7L/MAdXxwXFxNNceGALuMUr05WfnfBUfkbeI0xiC2rPtwKzh3xO2crjSYx52UE+59V73koHzDpQ==
|
||||
"matrix-protection-suite-for-matrix-bot-sdk@npm:@gnuxie/matrix-protection-suite-for-matrix-bot-sdk@3.1.1":
|
||||
version "3.1.1"
|
||||
resolved "https://registry.yarnpkg.com/@gnuxie/matrix-protection-suite-for-matrix-bot-sdk/-/matrix-protection-suite-for-matrix-bot-sdk-3.1.1.tgz#1bdfadd16a3e69677a6dd694d6288fd967764a2d"
|
||||
integrity sha512-jzOFhKt24FiSmK5Ej0khaPfBder607yFX1vg5dvDSv6q/GrHrkFB5poq4TGtu+x+gRIDNAe2zfEOriK1p/qyoQ==
|
||||
dependencies:
|
||||
"@gnuxie/typescript-result" "^1.0.0"
|
||||
await-lock "^2.2.2"
|
||||
|
||||
Reference in new issue
Block a user