mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-10-22 09:01:59 +00:00
Appservice convenience (#47)
Canonicalise the existence of the "admin room" for managing the appservice and Draupnir instances * Add utilities for managing users in the admin room * Merge the appservice admin room and access control list. The majority of admins will need to use the draupnir admin commands to manage the list. * Utility methods for creating generic rules in PolicyLists. * Commands for managing appservice users.
This commit is contained in:
1 parent
449e48b486
commit
99e6f168ca
9 files changed
+91
-15
No files matched your search
@@ -28,6 +28,7 @@ limitations under the License.
|
||||
import { Bridge } from "matrix-appservice-bridge";
|
||||
import { Permalinks } from "../commands/interface-manager/Permalinks";
|
||||
import AccessControlUnit, { EntityAccess } from "../models/AccessControlUnit";
|
||||
import { EntityType, Recommendation } from "../models/ListRule";
|
||||
import PolicyList from "../models/PolicyList";
|
||||
|
||||
/**
|
||||
@@ -74,4 +75,12 @@ export class AccessControl {
|
||||
public getUserAccess(mxid: string): EntityAccess {
|
||||
return this.accessControlUnit.getAccessForUser(mxid, "CHECK_SERVER");
|
||||
}
|
||||
|
||||
public async allow(mxid: string): Promise<void> {
|
||||
await this.accessControlList.createPolicy(EntityType.RULE_USER, Recommendation.Allow, mxid);
|
||||
}
|
||||
|
||||
public async remove(mxid: string): Promise<void> {
|
||||
await this.accessControlList.unbanEntity(EntityType.RULE_USER, mxid);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ export class MjolnirAppService {
|
||||
public readonly config: IConfig,
|
||||
public readonly bridge: Bridge,
|
||||
public readonly mjolnirManager: MjolnirManager,
|
||||
private readonly accessControl: AccessControl,
|
||||
public readonly accessControl: AccessControl,
|
||||
private readonly dataStore: DataStore,
|
||||
) {
|
||||
this.api = new Api(config.homeserver.url, mjolnirManager);
|
||||
@@ -81,7 +81,7 @@ export class MjolnirAppService {
|
||||
suppressEcho: false,
|
||||
});
|
||||
await bridge.initialise();
|
||||
const accessControlListId = await bridge.getBot().getClient().resolveRoom(config.accessControlList);
|
||||
const accessControlListId = await bridge.getBot().getClient().resolveRoom(config.adminRoom);
|
||||
const accessControl = await AccessControl.setupAccessControl(accessControlListId, bridge);
|
||||
const mjolnirManager = await MjolnirManager.makeMjolnirManager(dataStore, bridge, accessControl);
|
||||
const appService = new MjolnirAppService(
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/**
|
||||
* Copyright (C) 2022 Gnuxie <Gnuxie@protonmail.com>
|
||||
* All rights reserved.
|
||||
*/
|
||||
|
||||
import { defineInterfaceCommand, findTableCommand } from "../../commands/interface-manager/InterfaceCommand";
|
||||
import { findPresentationType, parameters, ParsedKeywords } from "../../commands/interface-manager/ParameterParsing";
|
||||
import { CommandResult } from "../../commands/interface-manager/Validation";
|
||||
import { AppserviceContext } from "./AppserviceCommandHandler";
|
||||
import { UserID } from "matrix-bot-sdk";
|
||||
import { defineMatrixInterfaceAdaptor } from "../../commands/interface-manager/MatrixInterfaceAdaptor";
|
||||
import { tickCrossRenderer } from "../../commands/interface-manager/MatrixHelpRenderer";
|
||||
|
||||
defineInterfaceCommand({
|
||||
designator: ["allow"],
|
||||
table: "appservice bot",
|
||||
parameters: parameters([
|
||||
{
|
||||
name: 'user',
|
||||
acceptor: findPresentationType('UserID'),
|
||||
}
|
||||
]),
|
||||
command: async function (this: AppserviceContext, _keywords: ParsedKeywords, user: UserID): Promise<CommandResult<void>> {
|
||||
await this.appservice.accessControl.allow(user.toString());
|
||||
return CommandResult.Ok(undefined);
|
||||
},
|
||||
summary: "Allow a user to provision themselves a draupnir using the appservice."
|
||||
})
|
||||
|
||||
defineMatrixInterfaceAdaptor({
|
||||
interfaceCommand: findTableCommand("appservice bot", "allow"),
|
||||
renderer: tickCrossRenderer,
|
||||
});
|
||||
|
||||
defineInterfaceCommand({
|
||||
designator: ["remove"],
|
||||
table: "appservice bot",
|
||||
parameters: parameters([
|
||||
{
|
||||
name: 'user',
|
||||
acceptor: findPresentationType('UserID'),
|
||||
}
|
||||
]),
|
||||
command: async function (this: AppserviceContext, _keywords: ParsedKeywords, user: UserID): Promise<CommandResult<void>> {
|
||||
await this.appservice.accessControl.remove(user.toString());
|
||||
return CommandResult.Ok(undefined);
|
||||
},
|
||||
summary: "Stop a user from using any provisioned draupnir in the appservice."
|
||||
})
|
||||
|
||||
defineMatrixInterfaceAdaptor({
|
||||
interfaceCommand: findTableCommand("appservice bot", "remove"),
|
||||
renderer: tickCrossRenderer,
|
||||
});
|
||||
@@ -22,6 +22,7 @@ export type AppserviceBaseExecutor = (this: AppserviceContext, ...args: any[]) =
|
||||
|
||||
import '../../commands/interface-manager/MatrixPresentations';
|
||||
import './ListCommand';
|
||||
import './AccessCommands';
|
||||
import { AppserviceBotEmitter } from './AppserviceBotEmitter';
|
||||
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ db:
|
||||
|
||||
# A room you have created that scopes who can access the appservice.
|
||||
# See docs/access_control.md
|
||||
accessControlList: "#access-control-list:localhost:9999"
|
||||
adminRoom: "#draupnir-admin:localhost:9999"
|
||||
|
||||
# This is a web api that the widget connects to in order to interact with the appservice.
|
||||
webAPI:
|
||||
|
||||
@@ -7,8 +7,7 @@ db:
|
||||
engine: "postgres"
|
||||
connectionString: "postgres://mjolnir-tester:mjolnir-test@localhost:8083/mjolnir-test-db"
|
||||
|
||||
accessControlList: "#access-control-list:localhost:9999"
|
||||
adminRoom: "#access-control-list:localhost:9999"
|
||||
adminRoom: "#draupnir-admin:localhost:9999"
|
||||
|
||||
webAPI:
|
||||
port: 9001
|
||||
@@ -46,8 +46,6 @@ export interface IConfig {
|
||||
webAPI: {
|
||||
port: number
|
||||
},
|
||||
/** A policy room for controlling access to the appservice -- just replace with mangement room tbh bloody hell m8 */
|
||||
accessControlList: string,
|
||||
/** The admin room for the appservice bot. Not called managementRoom like mjolnir on purpose, so they're not mixed in code somehow. */
|
||||
adminRoom: string,
|
||||
/** configuration for matrix-appservice-bridge's Logger */
|
||||
|
||||
@@ -314,21 +314,36 @@ export class PolicyList extends EventEmitter {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new policy rule in the list.
|
||||
* @param entityType The type of entity the rule applies to e.g. RULE_USER for users.
|
||||
* @param recommendation The recommendation e.g. `Recommendation.Ban` that the policy represents.
|
||||
* @param entity The entity to be added to the policy list.
|
||||
* @param additionalProperties Any other properties to embed in the rule such as a reason.
|
||||
* @returns The event id of the policy.
|
||||
*/
|
||||
public async createPolicy(entityType: EntityType, recommendation: Recommendation, entity: string, additionalProperties = {}): Promise<string> {
|
||||
// '@' at the beginning of state keys is reserved.
|
||||
const stateKey = entityType === RULE_USER ? '_' + entity.substring(1) : entity;
|
||||
const eventId = await this.client.sendStateEvent(this.roomId, entityType, stateKey, {
|
||||
recommendation,
|
||||
entity,
|
||||
...additionalProperties
|
||||
});
|
||||
this.updateForEvent(eventId);
|
||||
return eventId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ban an entity with Recommendation.Ban from the list.
|
||||
* @param ruleType The type of rule e.g. RULE_USER.
|
||||
* @param entity The entity to ban.
|
||||
* @param reason A reason we are banning them.
|
||||
*/
|
||||
public async banEntity(ruleType: string, entity: string, reason?: string): Promise<void> {
|
||||
// '@' at the beginning of state keys is reserved.
|
||||
const stateKey = ruleType === RULE_USER ? '_' + entity.substring(1) : entity;
|
||||
const event_id = await this.client.sendStateEvent(this.roomId, ruleType, stateKey, {
|
||||
entity,
|
||||
recommendation: Recommendation.Ban,
|
||||
public async banEntity(ruleType: EntityType, entity: string, reason?: string): Promise<void> {
|
||||
await this.createPolicy(ruleType, Recommendation.Ban, entity, {
|
||||
reason: reason || '<no reason supplied>',
|
||||
});
|
||||
this.updateForEvent(event_id);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -13,7 +13,7 @@ export function readTestConfig(): IConfig {
|
||||
export async function setupHarness(): Promise<MjolnirAppService> {
|
||||
const config = readTestConfig();
|
||||
const utilityUser = await newTestUser(config.homeserver.url, { name: { contains: "utility" }});
|
||||
await ensureAliasedRoomExists(utilityUser, config.accessControlList);
|
||||
await ensureAliasedRoomExists(utilityUser, config.adminRoom);
|
||||
return await MjolnirAppService.run(9000, config, "mjolnir-registration.yaml");
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user