Files
Draupnir/apps/draupnir/src/appservice/AccessControl.ts
T
2026-05-05 12:31:43 +02:00

108 lines
3.0 KiB
TypeScript

// Copyright 2022 Gnuxie <Gnuxie@protonmail.com>
// Copyright 2022 The Matrix.org Foundation C.I.C.
//
// SPDX-License-Identifier: Apache-2.0
//
// SPDX-FileAttributionText: <text>
// This modified file incorporates work from mjolnir
// https://github.com/matrix-org/mjolnir
// </text>
import {
MatrixRoomID,
StringUserID,
} from "@the-draupnir-project/matrix-basic-types";
import {
ActionResult,
EntityAccess,
Ok,
PolicyListRevisionIssuer,
PolicyRoomManager,
isError,
AccessControl as MPSAccess,
PolicyRoomEditor,
PolicyRuleType,
Recommendation,
RoomJoiner,
} from "matrix-protection-suite";
/**
* Utility to manage which users have access to the application service,
* meaning whether a user is able to provision a draupnir or continue to use one.
* Internally we use a policy list within matrix to determine who has access via the `AccessControlUnit`.
*/
export class AccessControl {
private constructor(
private readonly accessControlRevisionIssuer: PolicyListRevisionIssuer,
private readonly editor: PolicyRoomEditor
) {
// nothing to do.
}
/**
* Construct and initialize access control for the `MjolnirAppService`.
* @param accessControlListId The room id of a policy list used to manage access to the appservice (who can provision & use draupnir)
* @param bridge The matrix-appservice-bridge, used to get the appservice bot.
* @returns A new instance of `AccessControl` to be used by `MjolnirAppService`.
*/
public static async setupAccessControlForRoom(
/** The room id for the access control list. */
accessControlRoom: MatrixRoomID,
policyRoomManager: PolicyRoomManager,
bridgeBotJoiner: RoomJoiner
): Promise<ActionResult<AccessControl>> {
const joinResult = await bridgeBotJoiner.joinRoom(
accessControlRoom.toRoomIDOrAlias()
);
if (isError(joinResult)) {
return joinResult;
}
const revisionIssuer =
await policyRoomManager.getPolicyRoomRevisionIssuer(accessControlRoom);
if (isError(revisionIssuer)) {
return revisionIssuer;
}
const editor =
await policyRoomManager.getPolicyRoomEditor(accessControlRoom);
if (isError(editor)) {
return editor;
}
return Ok(new AccessControl(revisionIssuer.ok, editor.ok));
}
public getUserAccess(mxid: StringUserID): EntityAccess {
return MPSAccess.getAccessForUser(
this.accessControlRevisionIssuer.currentRevision,
mxid,
"CHECK_SERVER"
);
}
public async allow(
mxid: StringUserID,
reason = "<no reason supplied>"
): Promise<ActionResult<void>> {
const result = await this.editor.createPolicy(
PolicyRuleType.User,
Recommendation.Allow,
mxid,
reason,
{}
);
if (isError(result)) {
return result;
} else {
return Ok(undefined);
}
}
public async remove(mxid: StringUserID): Promise<ActionResult<void>> {
const result = await this.editor.unbanEntity(PolicyRuleType.User, mxid);
if (isError(result)) {
return result;
} else {
return Ok(undefined);
}
}
}