1- import { createValidator , success , failure } from '../Validator' ;
1+ import { createValidator , success , failure , ValidationResult } from '../Validator' ;
22import { AuthorizedEvent } from './index' ;
33import { Logger } from '../../routes/federation/logger' ;
44
@@ -16,14 +16,6 @@ interface PowerLevels {
1616 invite ?: number ;
1717}
1818
19- /**
20- * Validates room authorization rules
21- *
22- * Matrix rooms have specific authorization rules that determine
23- * who can send what types of events, based on power levels and
24- * room state. This validator enforces these rules according to
25- * the Matrix specification.
26- */
2719export const validateRoomRules = createValidator < AuthorizedEvent > ( async ( event , _ , eventId ) => {
2820 try {
2921 logger . debug ( `Validating room rules for event ${ eventId } ` ) ;
@@ -35,11 +27,9 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
3527 return failure ( 'M_MISSING_AUTH_EVENTS' , 'Event missing auth event objects' ) ;
3628 }
3729
38- // Create a map of auth events for easy access
3930 const authEvents = new Map ( ) ;
4031 authorizedEvent . auth_event_objects . forEach ( authEvent => {
4132 if ( authEvent . event && authEvent . event . type ) {
42- // For state events, use type + state_key as the key
4333 if ( authEvent . event . state_key !== undefined ) {
4434 authEvents . set ( `${ authEvent . event . type } |${ authEvent . event . state_key } ` , authEvent . event ) ;
4535 } else {
@@ -48,7 +38,6 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
4838 }
4939 } ) ;
5040
51- // Get required auth events for the rules check
5241 const createEvent = authEvents . get ( 'm.room.create|' ) ;
5342 if ( ! createEvent ) {
5443 logger . error ( `Missing required create event for rules validation` ) ;
@@ -70,7 +59,6 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
7059 const eventType = event . event . type ;
7160 const stateKey = event . event . state_key ;
7261
73- // Check if the sender's event is allowed based on auth rules
7462 // 1. Check room creator for create events
7563 if ( eventType === 'm.room.create' ) {
7664 // Create events must have the sender match the creator
@@ -82,15 +70,11 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
8270
8371 // 2. For member events, validate based on membership type
8472 else if ( eventType === 'm.room.member' ) {
85- // For self-membership changes
8673 if ( stateKey === sender ) {
87- // For joins, check join rules
8874 if ( event . event . content ?. membership === 'join' ) {
8975 const joinRulesEvent = authEvents . get ( 'm.room.join_rules|' ) ;
9076
91- // Only enforce join rules if they are specified
9277 if ( joinRulesEvent && joinRulesEvent . content ?. join_rule === 'invite' ) {
93- // For invite-only rooms, check if user was invited
9478 const memberEvent = authEvents . get ( `m.room.member|${ sender } ` ) ;
9579 const existingMembership = memberEvent ?. content ?. membership ;
9680
@@ -103,9 +87,7 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
10387 }
10488 }
10589 }
106- // For changing others' membership
10790 else {
108- // For invites, check that the inviter has permission
10991 if ( event . event . content ?. membership === 'invite' ) {
11092 const userPowerLevel = getUserPowerLevel ( sender , powerLevels ) ;
11193 if ( userPowerLevel < ( powerLevels . invite ?? 50 ) ) {
@@ -114,7 +96,6 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
11496 }
11597 }
11698
117- // For kick/ban, check appropriate permissions
11899 else if ( [ 'ban' , 'kick' ] . includes ( event . event . content ?. membership || '' ) ) {
119100 const targetUser = stateKey ;
120101 const action = event . event . content ?. membership ;
@@ -141,13 +122,11 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
141122 else if ( eventType === 'm.room.power_levels' ) {
142123 const userPowerLevel = getUserPowerLevel ( sender , powerLevels ) ;
143124
144- // Check sender has required power level to change power levels
145125 if ( userPowerLevel < ( powerLevels . events ?. [ 'm.room.power_levels' ] ?? powerLevels . state_default ?? 50 ) ) {
146126 logger . error ( `User ${ sender } doesn't have permission to change power levels (power level: ${ userPowerLevel } )` ) ;
147127 return failure ( 'M_FORBIDDEN' , 'User doesn\'t have permission to change power levels' ) ;
148128 }
149129
150- // Prevent privilege escalation
151130 const newPowerLevels = event . event . content as PowerLevels ;
152131 if ( newPowerLevels && newPowerLevels . users ) {
153132 for ( const [ user , level ] of Object . entries ( newPowerLevels . users ) ) {
@@ -173,7 +152,6 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
173152
174153 // 5. For normal message events, check event power levels
175154 else {
176- // First check that the sender is actually in the room
177155 const memberEvent = authEvents . get ( `m.room.member|${ sender } ` ) ;
178156 if ( ! memberEvent || memberEvent . content ?. membership !== 'join' ) {
179157 logger . error ( `User ${ sender } tried to send message without being in the room` ) ;
@@ -198,8 +176,6 @@ export const validateRoomRules = createValidator<AuthorizedEvent>(async (event,
198176 }
199177} ) ;
200178
201- // Helper functions for power level checks
202-
203179function getUserPowerLevel ( userId : string , powerLevels : PowerLevels ) : number {
204180 if ( powerLevels . users && powerLevels . users [ userId ] !== undefined ) {
205181 return powerLevels . users [ userId ] ;
0 commit comments