refactor: stricter domain: access-control

This commit is contained in:
2026-04-11 13:25:26 +02:00
parent 6800c73292
commit 0b9a9f311e
16 changed files with 46 additions and 44 deletions

View File

@@ -1,6 +0,0 @@
export * from './access-control.models';
export * from './access-control.constants';
export * from './role.rules';
export * from './role-assignment.rules';
export * from './permission.rules';
export * from './room.rules';

View File

@@ -1,4 +1,4 @@
import type { RoomPermissionDefinition } from './access-control.models';
import type { RoomPermissionDefinition } from '../models/access-control.model';
export const SYSTEM_ROLE_IDS = {
everyone: 'system-everyone',

View File

@@ -2,7 +2,7 @@ import type {
RoomMember,
RoomPermissionKey,
User
} from '../../../shared-kernel';
} from '../../../../shared-kernel';
export interface RoomPermissionDefinition {
key: RoomPermissionKey;

View File

@@ -0,0 +1,47 @@
import { BanEntry, User } from '../../../../shared-kernel';
type BanAwareUser = Pick<User, 'id' | 'oderId'> | null | undefined;
/** Build the set of user identifiers that may appear in room ban entries. */
export function getRoomBanCandidateIds(user: BanAwareUser, persistedUserId?: string | null): string[] {
const candidates = [
user?.id,
user?.oderId,
persistedUserId
].filter((value): value is string => typeof value === 'string' && value.trim().length > 0);
return Array.from(new Set(candidates));
}
/** Resolve the user identifier stored by a ban entry, with legacy fallback support. */
export function getRoomBanTargetId(ban: Pick<BanEntry, 'userId' | 'oderId'>): string {
if (typeof ban.userId === 'string' && ban.userId.trim().length > 0) {
return ban.userId;
}
return ban.oderId;
}
/** Return true when the given ban targets the provided user. */
export function isRoomBanMatch(
ban: Pick<BanEntry, 'userId' | 'oderId'>,
user: BanAwareUser,
persistedUserId?: string | null
): boolean {
const candidateIds = getRoomBanCandidateIds(user, persistedUserId);
if (candidateIds.length === 0) {
return false;
}
return candidateIds.includes(getRoomBanTargetId(ban));
}
/** Return true when any active ban entry targets the provided user. */
export function hasRoomBanForUser(
bans: Pick<BanEntry, 'userId' | 'oderId'>[],
user: BanAwareUser,
persistedUserId?: string | null
): boolean {
return bans.some((ban) => isRoomBanMatch(ban, user, persistedUserId));
}

View File

@@ -4,9 +4,9 @@ import {
Room,
RoomPermissionKey,
RoomRole
} from '../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from './access-control.constants';
import type { MemberIdentity } from './access-control.models';
} from '../../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants';
import type { MemberIdentity } from '../models/access-control.model';
import {
buildRoleLookup,
getRolePermissionState,
@@ -14,7 +14,7 @@ import {
normalizePermissionState,
roleSortAscending,
compareText
} from './access-control.internal';
} from '../util/access-control.util';
import { getAssignedRoleIds, getHighestAssignedRole } from './role-assignment.rules';
import { getRoomRoleById, normalizeRoomRoles } from './role.rules';

View File

@@ -3,9 +3,9 @@ import {
RoomMember,
RoomRole,
RoomRoleAssignment
} from '../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from './access-control.constants';
import type { MemberIdentity } from './access-control.models';
} from '../../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants';
import type { MemberIdentity } from '../models/access-control.model';
import {
buildRoleLookup,
compareText,
@@ -13,7 +13,7 @@ import {
matchesIdentity,
roleSortDescending,
uniqueStrings
} from './access-control.internal';
} from '../util/access-control.util';
import { getRoomRoleById, normalizeRoomRoles } from './role.rules';
function sortAssignments(assignments: readonly RoomRoleAssignment[]): RoomRoleAssignment[] {

View File

@@ -2,8 +2,8 @@ import {
RoomPermissionMatrix,
RoomPermissions,
RoomRole
} from '../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from './access-control.constants';
} from '../../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants';
import {
buildRoleLookup,
buildSystemRole,
@@ -12,7 +12,7 @@ import {
normalizePermissionMatrix,
roleSortAscending,
roleSortDescending
} from './access-control.internal';
} from '../util/access-control.util';
const ROLE_COLORS = {
everyone: '#6b7280',

View File

@@ -7,14 +7,14 @@ import {
RoomRole,
RoomRoleAssignment,
UserRole
} from '../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from './access-control.constants';
} from '../../../../shared-kernel';
import { SYSTEM_ROLE_IDS } from '../constants/access-control.constants';
import {
getRolePermissionState,
permissionStateToBoolean,
resolveLegacyAllowState
} from './access-control.internal';
import type { MemberIdentity } from './access-control.models';
} from '../util/access-control.util';
import type { MemberIdentity } from '../models/access-control.model';
import {
getAssignedRoleIds,
normalizeRoomRoleAssignments,

View File

@@ -5,8 +5,8 @@ import {
RoomRole,
RoomRoleAssignment,
ROOM_PERMISSION_KEYS
} from '../../../shared-kernel';
import type { MemberIdentity } from './access-control.models';
} from '../../../../shared-kernel';
import type { MemberIdentity } from '../models/access-control.model';
export function normalizeName(name: string): string {
return name.trim().replace(/\s+/g, ' ');