Add access control rework

This commit is contained in:
2026-04-02 03:18:37 +02:00
parent 314a26325f
commit 37cac95b38
111 changed files with 5355 additions and 1892 deletions

View File

@@ -5,6 +5,9 @@ import {
RoomEntity,
RoomChannelEntity,
RoomMemberEntity,
RoomRoleEntity,
RoomUserRoleEntity,
RoomChannelPermissionEntity,
ReactionEntity,
BanEntity,
AttachmentEntity,
@@ -17,6 +20,9 @@ export async function handleClearAllData(dataSource: DataSource): Promise<void>
await dataSource.getRepository(RoomEntity).clear();
await dataSource.getRepository(RoomChannelEntity).clear();
await dataSource.getRepository(RoomMemberEntity).clear();
await dataSource.getRepository(RoomRoleEntity).clear();
await dataSource.getRepository(RoomUserRoleEntity).clear();
await dataSource.getRepository(RoomChannelPermissionEntity).clear();
await dataSource.getRepository(ReactionEntity).clear();
await dataSource.getRepository(BanEntity).clear();
await dataSource.getRepository(AttachmentEntity).clear();

View File

@@ -1,8 +1,11 @@
import { DataSource } from 'typeorm';
import {
RoomChannelPermissionEntity,
RoomChannelEntity,
RoomEntity,
RoomMemberEntity,
RoomRoleEntity,
RoomUserRoleEntity,
MessageEntity
} from '../../../entities';
import { DeleteRoomCommand } from '../../types';
@@ -11,8 +14,11 @@ export async function handleDeleteRoom(command: DeleteRoomCommand, dataSource: D
const { roomId } = command.payload;
await dataSource.transaction(async (manager) => {
await manager.getRepository(RoomChannelPermissionEntity).delete({ roomId });
await manager.getRepository(RoomChannelEntity).delete({ roomId });
await manager.getRepository(RoomMemberEntity).delete({ roomId });
await manager.getRepository(RoomRoleEntity).delete({ roomId });
await manager.getRepository(RoomUserRoleEntity).delete({ roomId });
await manager.getRepository(RoomEntity).delete({ id: roomId });
await manager.getRepository(MessageEntity).delete({ roomId });
});

View File

@@ -5,6 +5,7 @@ import { SaveMessageCommand } from '../../types';
export async function handleSaveMessage(command: SaveMessageCommand, dataSource: DataSource): Promise<void> {
const { message } = command.payload;
await dataSource.transaction(async (manager) => {
const repo = manager.getRepository(MessageEntity);
const entity = repo.create({

View File

@@ -3,8 +3,23 @@ import { RoomEntity } from '../../../entities';
import { replaceRoomRelations } from '../../relations';
import { SaveRoomCommand } from '../../types';
function extractSlowModeInterval(room: SaveRoomCommand['payload']['room']): number {
if (typeof room.slowModeInterval === 'number' && Number.isFinite(room.slowModeInterval)) {
return room.slowModeInterval;
}
const permissions = room.permissions && typeof room.permissions === 'object'
? room.permissions as { slowModeInterval?: unknown }
: null;
return typeof permissions?.slowModeInterval === 'number' && Number.isFinite(permissions.slowModeInterval)
? permissions.slowModeInterval
: 0;
}
export async function handleSaveRoom(command: SaveRoomCommand, dataSource: DataSource): Promise<void> {
const { room } = command.payload;
await dataSource.transaction(async (manager) => {
const repo = manager.getRepository(RoomEntity);
const entity = repo.create({
@@ -21,7 +36,7 @@ export async function handleSaveRoom(command: SaveRoomCommand, dataSource: DataS
maxUsers: room.maxUsers ?? null,
icon: room.icon ?? null,
iconUpdatedAt: room.iconUpdatedAt ?? null,
permissions: room.permissions != null ? JSON.stringify(room.permissions) : null,
slowModeInterval: extractSlowModeInterval(room),
sourceId: room.sourceId ?? null,
sourceName: room.sourceName ?? null,
sourceUrl: room.sourceUrl ?? null
@@ -30,7 +45,11 @@ export async function handleSaveRoom(command: SaveRoomCommand, dataSource: DataS
await repo.save(entity);
await replaceRoomRelations(manager, room.id, {
channels: room.channels ?? [],
members: room.members ?? []
members: room.members ?? [],
roles: room.roles ?? [],
roleAssignments: room.roleAssignments ?? [],
channelPermissions: room.channelPermissions ?? [],
permissions: room.permissions
});
});
}

View File

@@ -5,6 +5,7 @@ import { UpdateMessageCommand } from '../../types';
export async function handleUpdateMessage(command: UpdateMessageCommand, dataSource: DataSource): Promise<void> {
const { messageId, updates } = command.payload;
await dataSource.transaction(async (manager) => {
const repo = manager.getRepository(MessageEntity);
const existing = await repo.findOne({ where: { id: messageId } });

View File

@@ -5,19 +5,32 @@ import { UpdateRoomCommand } from '../../types';
import {
applyUpdates,
boolToInt,
jsonOrNull,
TransformMap
} from './utils/applyUpdates';
const ROOM_TRANSFORMS: TransformMap = {
hasPassword: boolToInt,
isPrivate: boolToInt,
userCount: (val) => (val ?? 0),
permissions: jsonOrNull
userCount: (val) => (val ?? 0)
};
function extractSlowModeInterval(updates: UpdateRoomCommand['payload']['updates']): number | undefined {
if (typeof updates.slowModeInterval === 'number' && Number.isFinite(updates.slowModeInterval)) {
return updates.slowModeInterval;
}
const permissions = updates.permissions && typeof updates.permissions === 'object'
? updates.permissions as { slowModeInterval?: unknown }
: null;
return typeof permissions?.slowModeInterval === 'number' && Number.isFinite(permissions.slowModeInterval)
? permissions.slowModeInterval
: undefined;
}
export async function handleUpdateRoom(command: UpdateRoomCommand, dataSource: DataSource): Promise<void> {
const { roomId, updates } = command.payload;
await dataSource.transaction(async (manager) => {
const repo = manager.getRepository(RoomEntity);
const existing = await repo.findOne({ where: { id: roomId } });
@@ -25,13 +38,30 @@ export async function handleUpdateRoom(command: UpdateRoomCommand, dataSource: D
if (!existing)
return;
const { channels, members, ...entityUpdates } = updates;
const {
channels,
members,
roles,
roleAssignments,
channelPermissions,
permissions: rawPermissions,
...entityUpdates
} = updates;
const slowModeInterval = extractSlowModeInterval(updates);
if (slowModeInterval !== undefined) {
entityUpdates.slowModeInterval = slowModeInterval;
}
applyUpdates(existing, entityUpdates, ROOM_TRANSFORMS);
await repo.save(existing);
await replaceRoomRelations(manager, roomId, {
channels,
members
members,
roles,
roleAssignments,
channelPermissions,
permissions: rawPermissions
});
});
}