mirror of
https://github.com/the-draupnir-project/Draupnir.git
synced 2026-05-14 03:15:11 +00:00
Split PowerLevelsMirror into PowerLevelsEventMirror (#1098)
Docker Hub - Develop / docker-latest (push) Failing after 33s
GHCR - Development Branches / ghcr-publish (push) Failing after 38s
Tests / Build & Lint (push) Failing after 6m54s
Tests / Integration tests (push) Failing after 23s
Tests / Application Service Integration tests (push) Failing after 15s
Tests / Unit tests (push) Successful in 7m44s
Docker Hub - Develop / docker-latest (push) Failing after 33s
GHCR - Development Branches / ghcr-publish (push) Failing after 38s
Tests / Build & Lint (push) Failing after 6m54s
Tests / Integration tests (push) Failing after 23s
Tests / Application Service Integration tests (push) Failing after 15s
Tests / Unit tests (push) Successful in 7m44s
This is to accept the createEvent in the PowerLevelsMirror and makes it harder to forget privileged creators. Closes https://github.com/the-draupnir-project/planning/issues/122.
This commit is contained in:
@@ -0,0 +1,7 @@
|
||||
---
|
||||
"@the-draupnir-project/matrix-protection-suite": minor
|
||||
---
|
||||
|
||||
The PowerLevelsMirror has split in two into a PowerLevelsEventMirror and accept
|
||||
the createEvent in the PowerLevelsMirror. This makes it harder to forget
|
||||
privileged creators.
|
||||
@@ -16,7 +16,6 @@ import {
|
||||
RoomCreateEvent,
|
||||
RoomMembershipRevisionIssuer,
|
||||
RoomStateRevisionIssuer,
|
||||
RoomVersionMirror,
|
||||
} from "matrix-protection-suite";
|
||||
|
||||
export interface ManagementRoomDetail {
|
||||
@@ -78,9 +77,9 @@ export class StandardManagementRoomDetail implements ManagementRoomDetail {
|
||||
PowerLevelsMirror.isUserAbleToUse(
|
||||
draupnirUserID,
|
||||
PowerLevelPermission.StateDefault,
|
||||
createEvent,
|
||||
powerLevelEvent.content
|
||||
) ||
|
||||
RoomVersionMirror.isUserAPrivilegedCreator(draupnirUserID, createEvent)
|
||||
)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
PolicyRoomManager,
|
||||
PolicyRuleType,
|
||||
PowerLevelsEvent,
|
||||
PowerLevelsMirror,
|
||||
PowerLevelsEventMirror,
|
||||
RoomCreateEvent,
|
||||
RoomEvent,
|
||||
RoomJoiner,
|
||||
@@ -74,7 +74,7 @@ function renderPrivilegedUsers(revision: RoomStateRevision): DocumentNode {
|
||||
const poweredUsers = powerLevels.content.users
|
||||
? Object.entries(powerLevels.content.users)
|
||||
.filter(([userID]) =>
|
||||
PowerLevelsMirror.isUserAbleToSendEvent(
|
||||
PowerLevelsEventMirror.isUserAbleToSendEvent(
|
||||
userID as StringUserID,
|
||||
PolicyRuleType.User,
|
||||
powerLevels.content
|
||||
|
||||
+11
-1
@@ -119,9 +119,19 @@ export class RoomStateManagerFactory {
|
||||
if (isError(roomStateIssuer)) {
|
||||
return roomStateIssuer;
|
||||
}
|
||||
const createEvent =
|
||||
roomStateIssuer.ok.currentRevision.getStateEvent<RoomCreateEvent>(
|
||||
"m.room.create",
|
||||
""
|
||||
);
|
||||
if (createEvent === undefined) {
|
||||
return ActionError.Result(
|
||||
`Unable to find create event for ${room.toRoomIDOrAlias()} while creating policy room revision issuer`
|
||||
);
|
||||
}
|
||||
const issuer = new RoomStatePolicyRoomRevisionIssuer(
|
||||
room,
|
||||
StandardPolicyRoomRevision.blankRevision(room),
|
||||
StandardPolicyRoomRevision.blankRevision(room, createEvent),
|
||||
roomStateIssuer.ok
|
||||
);
|
||||
this.sha256Reverser?.addPolicyRoomRevisionIssuer(issuer);
|
||||
|
||||
@@ -15,15 +15,31 @@ export enum PowerLevelPermission {
|
||||
StateDefault = "state_default",
|
||||
}
|
||||
|
||||
export type MissingPermissionsChange = {
|
||||
missingStatePermissions: string[];
|
||||
missingPermissions: PowerLevelPermission[];
|
||||
missingEventPermissions: string[];
|
||||
isPrivilidgedInNextPowerLevels: boolean;
|
||||
isPrivilidgedInPriorPowerLevels: boolean;
|
||||
};
|
||||
export function isPowerLevelPermission(
|
||||
permission: string
|
||||
): permission is PowerLevelPermission {
|
||||
switch (permission) {
|
||||
case PowerLevelPermission.Ban:
|
||||
case PowerLevelPermission.Invite:
|
||||
case PowerLevelPermission.Kick:
|
||||
case PowerLevelPermission.Redact:
|
||||
case PowerLevelPermission.EventsDefault:
|
||||
case PowerLevelPermission.StateDefault:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
export const PowerLevelsMirror = Object.freeze({
|
||||
/**
|
||||
* Used for directly introspecting on the power levels event.
|
||||
* Do not use to introspect on the room power levels because you need
|
||||
* to also consider the room create event and room version.
|
||||
*
|
||||
* FIXME: Guh technically the default behaviours are specific to the room version
|
||||
* too and the entire mirror.
|
||||
*/
|
||||
export const PowerLevelsEventMirror = Object.freeze({
|
||||
getUserPowerLevel(
|
||||
who: StringUserID,
|
||||
content?: PowerLevelsEventContent
|
||||
@@ -42,6 +58,14 @@ export const PowerLevelsMirror = Object.freeze({
|
||||
): number {
|
||||
return content?.events?.[eventType] ?? content?.events_default ?? 0;
|
||||
},
|
||||
getPermissionPowerLevel(
|
||||
permission: PowerLevelPermission,
|
||||
content?: PowerLevelsEventContent
|
||||
): number {
|
||||
const defaultPermissionLevel =
|
||||
permission === PowerLevelPermission.Invite ? 0 : 50;
|
||||
return content?.[permission] ?? defaultPermissionLevel;
|
||||
},
|
||||
isUserAbleToSendState(
|
||||
who: StringUserID,
|
||||
eventType: string,
|
||||
@@ -58,9 +82,7 @@ export const PowerLevelsMirror = Object.freeze({
|
||||
content?: PowerLevelsEventContent
|
||||
): boolean {
|
||||
const userLevel = this.getUserPowerLevel(who, content);
|
||||
const defaultPermissionLevel =
|
||||
permission === PowerLevelPermission.Invite ? 0 : 50;
|
||||
const permissionLevel = content?.[permission] ?? defaultPermissionLevel;
|
||||
const permissionLevel = this.getPermissionPowerLevel(permission, content);
|
||||
return userLevel >= permissionLevel;
|
||||
},
|
||||
isUserAbleToSendEvent(
|
||||
@@ -73,6 +95,59 @@ export const PowerLevelsMirror = Object.freeze({
|
||||
this.getEventPowerLevel(eventType, content)
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
export type MissingPermissionsChange = {
|
||||
missingStatePermissions: string[];
|
||||
missingPermissions: PowerLevelPermission[];
|
||||
missingEventPermissions: string[];
|
||||
isPrivilidgedInNextPowerLevels: boolean;
|
||||
isPrivilidgedInPriorPowerLevels: boolean;
|
||||
};
|
||||
|
||||
export const PowerLevelsMirror = Object.freeze({
|
||||
isUserAbleToSendState(
|
||||
who: StringUserID,
|
||||
eventType: string,
|
||||
createEvent: RoomCreateEvent,
|
||||
powerLevelsContent?: PowerLevelsEventContent
|
||||
): boolean {
|
||||
return (
|
||||
PowerLevelsEventMirror.isUserAbleToSendState(
|
||||
who,
|
||||
eventType,
|
||||
powerLevelsContent
|
||||
) || RoomVersionMirror.isUserAPrivilegedCreator(who, createEvent)
|
||||
);
|
||||
},
|
||||
isUserAbleToUse(
|
||||
who: StringUserID,
|
||||
permission: PowerLevelPermission,
|
||||
createEvent: RoomCreateEvent,
|
||||
powerLevelsContent?: PowerLevelsEventContent
|
||||
): boolean {
|
||||
return (
|
||||
PowerLevelsEventMirror.isUserAbleToUse(
|
||||
who,
|
||||
permission,
|
||||
powerLevelsContent
|
||||
) || RoomVersionMirror.isUserAPrivilegedCreator(who, createEvent)
|
||||
);
|
||||
},
|
||||
isUserAbleToSendEvent(
|
||||
who: StringUserID,
|
||||
eventType: string,
|
||||
createEvent: RoomCreateEvent,
|
||||
powerLevelsContent?: PowerLevelsEventContent
|
||||
): boolean {
|
||||
return (
|
||||
PowerLevelsEventMirror.isUserAbleToSendEvent(
|
||||
who,
|
||||
eventType,
|
||||
powerLevelsContent
|
||||
) || RoomVersionMirror.isUserAPrivilegedCreator(who, createEvent)
|
||||
);
|
||||
},
|
||||
missingPermissions(
|
||||
clientUserID: StringUserID,
|
||||
requiredPermissions: PowerLevelPermission[],
|
||||
@@ -81,7 +156,7 @@ export const PowerLevelsMirror = Object.freeze({
|
||||
const missingPermissions: PowerLevelPermission[] = [];
|
||||
for (const permission of requiredPermissions) {
|
||||
if (
|
||||
!PowerLevelsMirror.isUserAbleToUse(
|
||||
!PowerLevelsEventMirror.isUserAbleToUse(
|
||||
clientUserID,
|
||||
permission,
|
||||
powerLevelsContent
|
||||
@@ -100,7 +175,7 @@ export const PowerLevelsMirror = Object.freeze({
|
||||
const missingPermissions: string[] = [];
|
||||
for (const permission of requiredStatePermissions) {
|
||||
if (
|
||||
!PowerLevelsMirror.isUserAbleToSendState(
|
||||
!PowerLevelsEventMirror.isUserAbleToSendState(
|
||||
clientUserID,
|
||||
permission,
|
||||
powerLevelsContent
|
||||
@@ -119,7 +194,7 @@ export const PowerLevelsMirror = Object.freeze({
|
||||
const missingPermissions: string[] = [];
|
||||
for (const permission of requiredEventPermissions) {
|
||||
if (
|
||||
!PowerLevelsMirror.isUserAbleToSendEvent(
|
||||
!PowerLevelsEventMirror.isUserAbleToSendEvent(
|
||||
clientUserID,
|
||||
permission,
|
||||
powerLevelsContent
|
||||
|
||||
@@ -46,6 +46,7 @@ import {
|
||||
import { isError } from "@gnuxie/typescript-result";
|
||||
import { SHA256 } from "crypto-js";
|
||||
import Base64 from "crypto-js/enc-base64";
|
||||
import { RoomCreateEvent } from "../MatrixTypes/CreateRoom";
|
||||
|
||||
const log = new Logger("StandardPolicyRoomRevision");
|
||||
|
||||
@@ -91,13 +92,17 @@ export class StandardPolicyRoomRevision implements PolicyRoomRevision {
|
||||
*/
|
||||
private readonly policyRuleByEventId: PolicyRuleByEventIDMap,
|
||||
private readonly policyRuleBySHA256: PolicyRuleByHashMap,
|
||||
private readonly createEvent: RoomCreateEvent,
|
||||
private readonly powerLevelsEvent: PowerLevelsEvent | undefined
|
||||
) {}
|
||||
|
||||
/**
|
||||
* @returns An empty revision.
|
||||
*/
|
||||
public static blankRevision(room: MatrixRoomID): StandardPolicyRoomRevision {
|
||||
public static blankRevision(
|
||||
room: MatrixRoomID,
|
||||
createEvent: RoomCreateEvent
|
||||
): StandardPolicyRoomRevision {
|
||||
return new StandardPolicyRoomRevision(
|
||||
room,
|
||||
new Revision(),
|
||||
@@ -105,6 +110,7 @@ export class StandardPolicyRoomRevision implements PolicyRoomRevision {
|
||||
PersistentMap(),
|
||||
PersistentMap(),
|
||||
PersistentMap(),
|
||||
createEvent,
|
||||
undefined
|
||||
);
|
||||
}
|
||||
@@ -338,6 +344,7 @@ export class StandardPolicyRoomRevision implements PolicyRoomRevision {
|
||||
nextPolicyRules,
|
||||
nextPolicyRulesByEventID,
|
||||
nextPolicyRulesBySHA256,
|
||||
this.createEvent,
|
||||
this.powerLevelsEvent
|
||||
);
|
||||
}
|
||||
@@ -506,6 +513,7 @@ export class StandardPolicyRoomRevision implements PolicyRoomRevision {
|
||||
return PowerLevelsMirror.isUserAbleToSendState(
|
||||
who,
|
||||
policy,
|
||||
this.createEvent,
|
||||
powerLevelsContent
|
||||
);
|
||||
}
|
||||
@@ -520,6 +528,7 @@ export class StandardPolicyRoomRevision implements PolicyRoomRevision {
|
||||
this.policyRules,
|
||||
this.policyRuleByEventId,
|
||||
this.policyRuleBySHA256,
|
||||
this.createEvent,
|
||||
powerLevels
|
||||
);
|
||||
}
|
||||
@@ -531,6 +540,7 @@ export class StandardPolicyRoomRevision implements PolicyRoomRevision {
|
||||
this.policyRules,
|
||||
this.policyRuleByEventId,
|
||||
this.policyRuleBySHA256,
|
||||
this.createEvent,
|
||||
this.powerLevelsEvent
|
||||
);
|
||||
}
|
||||
|
||||
@@ -42,6 +42,7 @@ import { MjolnirPolicyRoomsConfig } from "../Protection/PolicyListConfig/Mjolnir
|
||||
import { StandardWatchedPolicyRooms } from "../Protection/WatchedPolicyRooms/StandardWatchedPolicyRooms";
|
||||
import { DefaultEventDecoder } from "../MatrixTypes/DefaultEventDecoder";
|
||||
import { DefaultMixinExtractor } from "../SafeMatrixEvents/MatrixEventMixinDescriptions/DefaultMixinExtractor";
|
||||
import { RoomCreateEvent } from "../MatrixTypes/CreateRoom";
|
||||
|
||||
const log = new Logger("DeclareRoomState");
|
||||
|
||||
@@ -219,16 +220,29 @@ export function describeRoom({
|
||||
membershipDescriptions,
|
||||
policyDescriptions,
|
||||
});
|
||||
// if a create event isn't provided, make one.
|
||||
const providedCreateEvent = stateEvents.find(
|
||||
(event) => event.type === "m.room.create"
|
||||
);
|
||||
const createEvent =
|
||||
(providedCreateEvent as RoomCreateEvent | undefined) ??
|
||||
(describeStateEvent({
|
||||
sender: randomUserID(),
|
||||
room_id: room.toRoomIDOrAlias(),
|
||||
type: "m.room.create",
|
||||
state_key: "",
|
||||
content: {},
|
||||
}) as RoomCreateEvent);
|
||||
const stateRevision =
|
||||
StandardRoomStateRevision.blankRevision(room).reviseFromState(stateEvents);
|
||||
const membershipRevision =
|
||||
StandardRoomMembershipRevision.blankRevision(room).reviseFromMembership(
|
||||
membershipEvents
|
||||
);
|
||||
const policyRevision =
|
||||
StandardPolicyRoomRevision.blankRevision(room).reviseFromState(
|
||||
policyEvents
|
||||
);
|
||||
const policyRevision = StandardPolicyRoomRevision.blankRevision(
|
||||
room,
|
||||
createEvent
|
||||
).reviseFromState(policyEvents);
|
||||
const stateRevisionIssuer = new FakeRoomStateRevisionIssuer(
|
||||
stateRevision,
|
||||
room
|
||||
|
||||
Reference in New Issue
Block a user