Skip to main content

ruma_state_res/
event_auth.rs

1use std::{
2    borrow::Borrow,
3    collections::{BTreeMap, BTreeSet, HashSet},
4};
5
6use js_int::Int;
7use ruma_common::{
8    EventId, OwnedUserId, UserId, room::JoinRuleKind, room_version_rules::AuthorizationRules,
9};
10use ruma_events::{
11    StateEventType, TimelineEventType,
12    room::{member::MembershipState, power_levels::UserPowerLevel},
13};
14use serde_json::value::RawValue as RawJsonValue;
15use tracing::{debug, info, instrument, warn};
16
17mod room_member;
18#[cfg(test)]
19mod tests;
20
21use self::room_member::check_room_member;
22use crate::{
23    Event,
24    events::{
25        RoomCreateEvent, RoomJoinRulesEvent, RoomMemberEvent, RoomPowerLevelsEvent,
26        RoomThirdPartyInviteEvent,
27        member::{RoomMemberEventContent, RoomMemberEventOptionExt},
28        power_levels::{RoomPowerLevelsEventOptionExt, RoomPowerLevelsIntField},
29    },
30    utils::RoomIdExt,
31};
32
33/// Get the list of [relevant auth events] required to authorize the event of the given type.
34///
35/// Returns a list of `(event_type, state_key)` tuples.
36///
37/// # Errors
38///
39/// Returns an `Err(_)` if a field could not be deserialized because `content` does not respect the
40/// expected format for the `event_type`.
41///
42/// [relevant auth events]: https://spec.matrix.org/v1.18/server-server-api/#auth-events-selection
43pub fn auth_types_for_event(
44    event_type: &TimelineEventType,
45    sender: &UserId,
46    state_key: Option<&str>,
47    content: &RawJsonValue,
48    rules: &AuthorizationRules,
49) -> Result<Vec<(StateEventType, String)>, String> {
50    // The `auth_events` for the `m.room.create` event in a room is empty.
51    if event_type == &TimelineEventType::RoomCreate {
52        return Ok(vec![]);
53    }
54
55    // For other events, it should be the following subset of the room state:
56    //
57    // - The current `m.room.power_levels` event, if any.
58    // - The sender’s current `m.room.member` event, if any.
59    let mut auth_types = vec![
60        (StateEventType::RoomPowerLevels, "".to_owned()),
61        (StateEventType::RoomMember, sender.to_string()),
62    ];
63
64    // v1-v11, the `m.room.create` event.
65    if !rules.room_create_event_id_as_room_id {
66        auth_types.push((StateEventType::RoomCreate, "".to_owned()));
67    }
68
69    // If type is `m.room.member`:
70    if event_type == &TimelineEventType::RoomMember {
71        // The target’s current `m.room.member` event, if any.
72        let Some(state_key) = state_key else {
73            return Err("missing `state_key` field for `m.room.member` event".to_owned());
74        };
75        let key = (StateEventType::RoomMember, state_key.to_owned());
76        if !auth_types.contains(&key) {
77            auth_types.push(key);
78        }
79
80        let content = RoomMemberEventContent::new(content);
81        let membership = content.membership()?;
82
83        // If `membership` is `join`, `invite` or `knock`, the current `m.room.join_rules` event, if
84        // any.
85        if matches!(
86            membership,
87            MembershipState::Join | MembershipState::Invite | MembershipState::Knock
88        ) {
89            let key = (StateEventType::RoomJoinRules, "".to_owned());
90            if !auth_types.contains(&key) {
91                auth_types.push(key);
92            }
93        }
94
95        // If `membership` is `invite` and `content` contains a `third_party_invite` property, the
96        // current `m.room.third_party_invite` event with `state_key` matching
97        // `content.third_party_invite.signed.token`, if any.
98        if membership == MembershipState::Invite {
99            let third_party_invite = content.third_party_invite()?;
100
101            if let Some(third_party_invite) = third_party_invite {
102                let token = third_party_invite.token()?.to_owned();
103                let key = (StateEventType::RoomThirdPartyInvite, token);
104                if !auth_types.contains(&key) {
105                    auth_types.push(key);
106                }
107            }
108        }
109
110        // If `content.join_authorised_via_users_server` is present, and the room version supports
111        // restricted rooms, then the `m.room.member` event with `state_key` matching
112        // `content.join_authorised_via_users_server`.
113        //
114        // Note: And the membership is join (https://github.com/matrix-org/matrix-spec/pull/2100)
115        if membership == MembershipState::Join && rules.restricted_join_rule {
116            let join_authorised_via_users_server = content.join_authorised_via_users_server()?;
117            if let Some(user_id) = join_authorised_via_users_server {
118                let key = (StateEventType::RoomMember, user_id.to_string());
119                if !auth_types.contains(&key) {
120                    auth_types.push(key);
121                }
122            }
123        }
124    }
125
126    Ok(auth_types)
127}
128
129/// Check whether the incoming event passes the state-independent [authorization rules] for the
130/// given room version rules.
131///
132/// The state-independent rules are the first few authorization rules that check an incoming
133/// `m.room.create` event (which cannot have `auth_events`), and the list of `auth_events` of other
134/// events.
135///
136/// This method only needs to be called once, when the event is received.
137///
138/// # Errors
139///
140/// If the check fails, this returns an `Err(_)` with a description of the check that failed.
141///
142/// [authorization rules]: https://spec.matrix.org/v1.18/server-server-api/#authorization-rules
143#[instrument(skip_all, fields(event_id = incoming_event.event_id().borrow().as_str()))]
144pub fn check_state_independent_auth_rules<E: Event>(
145    rules: &AuthorizationRules,
146    incoming_event: impl Event,
147    fetch_event: impl Fn(&EventId) -> Option<E>,
148) -> Result<(), String> {
149    debug!("starting state-independent auth check");
150
151    // Since v1, if type is m.room.create:
152    if *incoming_event.event_type() == TimelineEventType::RoomCreate {
153        let room_create_event = RoomCreateEvent::new(incoming_event);
154
155        return check_room_create(room_create_event, rules);
156    }
157
158    let expected_auth_types = auth_types_for_event(
159        incoming_event.event_type(),
160        incoming_event.sender(),
161        incoming_event.state_key(),
162        incoming_event.content(),
163        rules,
164    )?
165    .into_iter()
166    .map(|(event_type, state_key)| (TimelineEventType::from(event_type), state_key))
167    .collect::<HashSet<_>>();
168
169    let Some(room_id) = incoming_event.room_id() else {
170        return Err("missing `room_id` field for event".to_owned());
171    };
172
173    let mut seen_auth_types: HashSet<(TimelineEventType, String)> =
174        HashSet::with_capacity(expected_auth_types.len());
175
176    // Since v1, considering auth_events:
177    for auth_event_id in incoming_event.auth_events() {
178        let event_id = auth_event_id.borrow();
179
180        let Some(auth_event) = fetch_event(event_id) else {
181            return Err(format!("failed to find auth event {event_id}"));
182        };
183
184        // The auth event must be in the same room as the incoming event.
185        if auth_event.room_id().is_none_or(|auth_room_id| auth_room_id != room_id) {
186            return Err(format!("auth event {event_id} not in the same room"));
187        }
188
189        let event_type = auth_event.event_type();
190        let state_key = auth_event
191            .state_key()
192            .ok_or_else(|| format!("auth event {event_id} has no `state_key`"))?;
193        let key = (event_type.clone(), state_key.to_owned());
194
195        // Since v1, if there are duplicate entries for a given type and state_key pair, reject.
196        if seen_auth_types.contains(&key) {
197            return Err(format!(
198                "duplicate auth event {event_id} for ({event_type}, {state_key}) pair"
199            ));
200        }
201
202        // Since v1, if there are entries whose type and state_key don’t match those specified by
203        // the auth events selection algorithm described in the server specification, reject.
204        if !expected_auth_types.contains(&key) {
205            return Err(format!(
206                "unexpected auth event {event_id} with ({event_type}, {state_key}) pair"
207            ));
208        }
209
210        // Since v1, if there are entries which were themselves rejected under the checks performed
211        // on receipt of a PDU, reject.
212        if auth_event.rejected() {
213            return Err(format!("rejected auth event {event_id}"));
214        }
215
216        seen_auth_types.insert(key);
217    }
218
219    // v1-v11, if there is no m.room.create event among the entries, reject.
220    if !rules.room_create_event_id_as_room_id
221        && !seen_auth_types
222            .iter()
223            .any(|(event_type, _)| *event_type == TimelineEventType::RoomCreate)
224    {
225        return Err("no `m.room.create` event in auth events".to_owned());
226    }
227
228    // Since v12, the room_id must be the reference hash of an accepted m.room.create event.
229    if rules.room_create_event_id_as_room_id {
230        let room_create_event_id = room_id.room_create_event_id().map_err(|error| {
231            format!("could not construct `m.room.create` event ID from room ID: {error}")
232        })?;
233
234        let room_create_event = fetch_event(&room_create_event_id).ok_or_else(|| {
235            format!("failed to find `m.room.create` event {room_create_event_id}")
236        })?;
237
238        if room_create_event.rejected() {
239            return Err(format!("rejected `m.room.create` event {room_create_event_id}"));
240        }
241    }
242
243    Ok(())
244}
245
246/// Check whether the incoming event passes the state-dependent [authorization rules] for the given
247/// room version rules.
248///
249/// The state-dependent rules are all the remaining rules not checked by
250/// [`check_state_independent_auth_rules()`].
251///
252/// This method should be called several times for an event, to perform the [checks on receipt of a
253/// PDU].
254///
255/// The `fetch_state` closure should gather state from a state snapshot. We need to know if the
256/// event passes auth against some state not a recursive collection of auth_events fields.
257///
258/// This assumes that `ruma_signatures::verify_event()` was called previously, as some authorization
259/// rules depend on the signatures being valid on the event.
260///
261/// # Errors
262///
263/// If the check fails, this returns an `Err(_)` with a description of the check that failed.
264///
265/// [authorization rules]: https://spec.matrix.org/v1.18/server-server-api/#authorization-rules
266/// [checks on receipt of a PDU]: https://spec.matrix.org/v1.18/server-server-api/#checks-performed-on-receipt-of-a-pdu
267#[instrument(skip_all, fields(event_id = incoming_event.event_id().borrow().as_str()))]
268pub fn check_state_dependent_auth_rules<E: Event>(
269    rules: &AuthorizationRules,
270    incoming_event: impl Event,
271    fetch_state: impl Fn(&StateEventType, &str) -> Option<E>,
272) -> Result<(), String> {
273    debug!("starting state-dependent auth check");
274
275    // There are no state-dependent auth rules for create events.
276    if *incoming_event.event_type() == TimelineEventType::RoomCreate {
277        debug!("allowing `m.room.create` event");
278        return Ok(());
279    }
280
281    let room_create_event = fetch_state.room_create_event()?;
282
283    // Since v1, if the create event content has the field m.federate set to false and the sender
284    // domain of the event does not match the sender domain of the create event, reject.
285    let federate = room_create_event.federate()?;
286    if !federate
287        && room_create_event.sender().server_name() != incoming_event.sender().server_name()
288    {
289        return Err("\
290            room is not federated and event's sender domain \
291            does not match `m.room.create` event's sender domain"
292            .to_owned());
293    }
294
295    let sender = incoming_event.sender();
296
297    // v1-v5, if type is m.room.aliases:
298    if rules.special_case_room_aliases && *incoming_event.event_type() == "m.room.aliases".into() {
299        debug!("starting m.room.aliases check");
300        // v1-v5, if event has no state_key, reject.
301        //
302        // v1-v5, if sender's domain doesn't match state_key, reject.
303        if incoming_event.state_key() != Some(sender.server_name().as_str()) {
304            return Err("\
305                server name of the `state_key` of `m.room.aliases` event \
306                does not match the server name of the sender"
307                .to_owned());
308        }
309
310        // Otherwise, allow.
311        info!("`m.room.aliases` event was allowed");
312        return Ok(());
313    }
314
315    // Since v1, if type is m.room.member:
316    if *incoming_event.event_type() == TimelineEventType::RoomMember {
317        let room_member_event = RoomMemberEvent::new(incoming_event);
318        return check_room_member(room_member_event, rules, room_create_event, fetch_state);
319    }
320
321    // Since v1, if the sender's current membership state is not join, reject.
322    let sender_membership = fetch_state.user_membership(sender)?;
323    tracing::info!(?sender_membership);
324
325    if sender_membership != MembershipState::Join {
326        return Err("sender's membership is not `join`".to_owned());
327    }
328
329    let creators = room_create_event.creators(rules)?;
330    let current_room_power_levels_event = fetch_state.room_power_levels_event();
331
332    let sender_power_level =
333        current_room_power_levels_event.user_power_level(sender, &creators, rules)?;
334
335    // Since v1, if type is m.room.third_party_invite:
336    if *incoming_event.event_type() == TimelineEventType::RoomThirdPartyInvite {
337        // Since v1, allow if and only if sender's current power level is greater than
338        // or equal to the invite level.
339        let invite_power_level = current_room_power_levels_event
340            .get_as_int_or_default(RoomPowerLevelsIntField::Invite, rules)?;
341
342        if sender_power_level < invite_power_level {
343            return Err("sender does not have enough power to send invites in this room".to_owned());
344        }
345
346        info!("`m.room.third_party_invite` event was allowed");
347        return Ok(());
348    }
349
350    // Since v1, if the event type's required power level is greater than the sender's power level,
351    // reject.
352    let event_type_power_level = current_room_power_levels_event.event_power_level(
353        incoming_event.event_type(),
354        incoming_event.state_key(),
355        rules,
356    )?;
357    if sender_power_level < event_type_power_level {
358        return Err(format!(
359            "sender does not have enough power to send event of type `{}`",
360            incoming_event.event_type()
361        ));
362    }
363
364    // Since v1, if the event has a state_key that starts with an @ and does not match the sender,
365    // reject.
366    if incoming_event.state_key().is_some_and(|k| k.starts_with('@'))
367        && incoming_event.state_key() != Some(incoming_event.sender().as_str())
368    {
369        return Err(
370            "sender cannot send event with `state_key` matching another user's ID".to_owned()
371        );
372    }
373
374    // If type is m.room.power_levels
375    if *incoming_event.event_type() == TimelineEventType::RoomPowerLevels {
376        let room_power_levels_event = RoomPowerLevelsEvent::new(incoming_event);
377        return check_room_power_levels(
378            room_power_levels_event,
379            current_room_power_levels_event,
380            rules,
381            sender_power_level,
382            &creators,
383        );
384    }
385
386    // v1-v2, if type is m.room.redaction:
387    if rules.special_case_room_redaction
388        && *incoming_event.event_type() == TimelineEventType::RoomRedaction
389    {
390        return check_room_redaction(
391            incoming_event,
392            current_room_power_levels_event,
393            rules,
394            sender_power_level,
395        );
396    }
397
398    // Otherwise, allow.
399    info!("allowing event passed all checks");
400    Ok(())
401}
402
403/// Check whether the given event passes the `m.room.create` authorization rules.
404fn check_room_create(
405    room_create_event: RoomCreateEvent<impl Event>,
406    rules: &AuthorizationRules,
407) -> Result<(), String> {
408    debug!("start `m.room.create` check");
409
410    // Since v1, if it has any previous events, reject.
411    if room_create_event.prev_events().next().is_some() {
412        return Err("`m.room.create` event cannot have previous events".into());
413    }
414
415    if rules.room_create_event_id_as_room_id {
416        // Since v12, if the create event has a room_id, reject.
417        if room_create_event.room_id().is_some() {
418            return Err("`m.room.create` event cannot have a `room_id` field".into());
419        }
420    } else {
421        // v1-v11, if the domain of the room_id does not match the domain of the sender, reject.
422        let Some(room_id) = room_create_event.room_id() else {
423            return Err("missing `room_id` field in `m.room.create` event".into());
424        };
425        let Some(room_id_server_name) = room_id.server_name() else {
426            return Err(
427                "invalid `room_id` field in `m.room.create` event: could not parse server name"
428                    .into(),
429            );
430        };
431
432        if room_id_server_name != room_create_event.sender().server_name() {
433            return Err("invalid `room_id` field in `m.room.create` event: server name does not match sender's server name".into());
434        }
435    }
436
437    // Since v1, if `content.room_version` is present and is not a recognized version, reject.
438    //
439    // This check is assumed to be done before calling auth_check because we have an
440    // AuthorizationRules, which means that we recognized the version.
441
442    // v1-v10, if content has no creator field, reject.
443    if !rules.use_room_create_sender && !room_create_event.has_creator()? {
444        return Err("missing `creator` field in `m.room.create` event".into());
445    }
446
447    // Since v12, if the `additional_creators` field is present and is not an array of strings
448    // where each string passes the same user ID validation that is applied to the sender, reject.
449    room_create_event.additional_creators(rules)?;
450
451    // Otherwise, allow.
452    info!("`m.room.create` event was allowed");
453    Ok(())
454}
455
456/// Check whether the given event passes the `m.room.power_levels` authorization rules.
457fn check_room_power_levels(
458    room_power_levels_event: RoomPowerLevelsEvent<impl Event>,
459    current_room_power_levels_event: Option<RoomPowerLevelsEvent<impl Event>>,
460    rules: &AuthorizationRules,
461    sender_power_level: UserPowerLevel,
462    room_creators: &HashSet<OwnedUserId>,
463) -> Result<(), String> {
464    debug!("starting m.room.power_levels check");
465
466    // Since v10, if any of the properties users_default, events_default, state_default, ban,
467    // redact, kick, or invite in content are present and not an integer, reject.
468    let new_int_fields = room_power_levels_event.int_fields_map(rules)?;
469
470    // Since v10, if either of the properties events or notifications in content are present and not
471    // a dictionary with values that are integers, reject.
472    let new_events = room_power_levels_event.events(rules)?;
473    let new_notifications = room_power_levels_event.notifications(rules)?;
474
475    // v1-v9, If the users property in content is not an object with keys that are valid user IDs
476    // with values that are integers (or a string that is an integer), reject.
477    // Since v10, if the users property in content is not an object with keys that are valid user
478    // IDs with values that are integers, reject.
479    let new_users = room_power_levels_event.users(rules)?;
480
481    // Since v12, if the `users` property in `content` contains the `sender` of the `m.room.create`
482    // event or any of the user IDs in the create event's `content.additional_creators`, reject.
483    if rules.explicitly_privilege_room_creators
484        && new_users.is_some_and(|new_users| {
485            room_creators.iter().any(|creator| new_users.contains_key(creator))
486        })
487    {
488        return Err("creator user IDs are not allowed in the `users` field".to_owned());
489    }
490
491    debug!("validation of power event finished");
492
493    // Since v1, if there is no previous m.room.power_levels event in the room, allow.
494    let Some(current_room_power_levels_event) = current_room_power_levels_event else {
495        info!("initial m.room.power_levels event allowed");
496        return Ok(());
497    };
498
499    // Since v1, for the properties users_default, events_default, state_default, ban, redact, kick,
500    // invite check if they were added, changed or removed. For each found alteration:
501    for field in RoomPowerLevelsIntField::ALL {
502        let current_power_level = current_room_power_levels_event.get_as_int(*field, rules)?;
503        let new_power_level = new_int_fields.get(field).copied();
504
505        if current_power_level == new_power_level {
506            continue;
507        }
508
509        // Since v1, if the current value is higher than the sender’s current power level,
510        // reject.
511        let current_power_level_too_big =
512            current_power_level.unwrap_or_else(|| field.default_value()) > sender_power_level;
513        // Since v1, if the new value is higher than the sender’s current power level, reject.
514        let new_power_level_too_big =
515            new_power_level.unwrap_or_else(|| field.default_value()) > sender_power_level;
516
517        if current_power_level_too_big || new_power_level_too_big {
518            return Err(format!(
519                "sender does not have enough power to change the power level of `{field}`"
520            ));
521        }
522    }
523
524    // Since v1, for each entry being added to, or changed in, the events property:
525    // - Since v1, if the new value is higher than the sender's current power level, reject.
526    let current_events = current_room_power_levels_event.events(rules)?;
527    check_power_level_maps(
528        current_events.as_ref(),
529        new_events.as_ref(),
530        &sender_power_level,
531        |_, current_power_level| {
532            // Since v1, for each entry being changed in, or removed from, the events property:
533            // - Since v1, if the current value is higher than the sender's current power level,
534            //   reject.
535            current_power_level > sender_power_level
536        },
537        |ev_type| {
538            format!(
539                "sender does not have enough power to change the `{ev_type}` event type power level"
540            )
541        },
542    )?;
543
544    // Since v6, for each entry being added to, or changed in, the notifications property:
545    // - Since v6, if the new value is higher than the sender's current power level, reject.
546    if rules.limit_notifications_power_levels {
547        let current_notifications = current_room_power_levels_event.notifications(rules)?;
548        check_power_level_maps(
549            current_notifications.as_ref(),
550            new_notifications.as_ref(),
551            &sender_power_level,
552            |_, current_power_level| {
553                // Since v6, for each entry being changed in, or removed from, the notifications
554                // property:
555                // - Since v6, if the current value is higher than the sender's current power level,
556                //   reject.
557                current_power_level > sender_power_level
558            },
559            |key| {
560                format!(
561                    "sender does not have enough power to change the `{key}` notification power level"
562                )
563            },
564        )?;
565    }
566
567    // Since v1, for each entry being added to, or changed in, the users property:
568    // - Since v1, if the new value is greater than the sender’s current power level, reject.
569    let current_users = current_room_power_levels_event.users(rules)?;
570    check_power_level_maps(
571        current_users,
572        new_users,
573        &sender_power_level,
574        |user_id, current_power_level| {
575            // Since v1, for each entry being changed in, or removed from, the users property, other
576            // than the sender’s own entry:
577            // - Since v1, if the current value is greater than or equal to the sender’s current
578            //   power level, reject.
579            user_id != room_power_levels_event.sender() && current_power_level >= sender_power_level
580        },
581        |user_id| format!("sender does not have enough power to change `{user_id}`'s  power level"),
582    )?;
583
584    // Otherwise, allow.
585    info!("m.room.power_levels event allowed");
586    Ok(())
587}
588
589/// Check the power levels changes between the current and the new maps.
590///
591/// # Arguments
592///
593/// * `current`: the map with the current power levels.
594/// * `new`: the map with the new power levels.
595/// * `sender_power_level`: the power level of the sender of the new map.
596/// * `reject_current_power_level_change_fn`: the function to check if a power level change or
597///   removal must be rejected given its current value.
598///
599///   The arguments to the method are the key of the power level and the current value of the power
600///   level. It must return `true` if the change or removal is rejected.
601///
602///   Note that another check is done after this one to check if the change is allowed given the new
603///   value of the power level.
604/// * `error_fn`: the function to generate an error when the change for the given key is not
605///   allowed.
606fn check_power_level_maps<K: Ord>(
607    current: Option<&BTreeMap<K, Int>>,
608    new: Option<&BTreeMap<K, Int>>,
609    sender_power_level: &UserPowerLevel,
610    reject_current_power_level_change_fn: impl FnOnce(&K, Int) -> bool + Copy,
611    error_fn: impl FnOnce(&K) -> String,
612) -> Result<(), String> {
613    let keys_to_check = current
614        .iter()
615        .flat_map(|m| m.keys())
616        .chain(new.iter().flat_map(|m| m.keys()))
617        .collect::<BTreeSet<_>>();
618
619    for key in keys_to_check {
620        let current_power_level = current.as_ref().and_then(|m| m.get(key));
621        let new_power_level = new.as_ref().and_then(|m| m.get(key));
622
623        if current_power_level == new_power_level {
624            continue;
625        }
626
627        // For each entry being changed in, or removed from, the property.
628        let current_power_level_change_rejected = current_power_level
629            .is_some_and(|power_level| reject_current_power_level_change_fn(key, *power_level));
630
631        // For each entry being added to, or changed in, the property:
632        // - If the new value is higher than the sender's current power level, reject.
633        let new_power_level_too_big = new_power_level.is_some_and(|pl| pl > sender_power_level);
634
635        if current_power_level_change_rejected || new_power_level_too_big {
636            return Err(error_fn(key));
637        }
638    }
639
640    Ok(())
641}
642
643/// Check whether the given event passes the `m.room.redaction` authorization rules.
644fn check_room_redaction(
645    room_redaction_event: impl Event,
646    current_room_power_levels_event: Option<RoomPowerLevelsEvent<impl Event>>,
647    rules: &AuthorizationRules,
648    sender_level: UserPowerLevel,
649) -> Result<(), String> {
650    let redact_level = current_room_power_levels_event
651        .get_as_int_or_default(RoomPowerLevelsIntField::Redact, rules)?;
652
653    // v1-v2, if the sender’s power level is greater than or equal to the redact level, allow.
654    if sender_level >= redact_level {
655        info!("`m.room.redaction` event allowed via power levels");
656        return Ok(());
657    }
658
659    // v1-v2, if the domain of the event_id of the event being redacted is the same as the
660    // domain of the event_id of the m.room.redaction, allow.
661    if room_redaction_event.event_id().borrow().server_name()
662        == room_redaction_event.redacts().as_ref().and_then(|&id| id.borrow().server_name())
663    {
664        info!("`m.room.redaction` event allowed via room version 1 rules");
665        return Ok(());
666    }
667
668    // Otherwise, reject.
669    Err("`m.room.redaction` event did not pass any of the allow rules".to_owned())
670}
671
672trait FetchStateExt<E: Event> {
673    fn room_create_event(&self) -> Result<RoomCreateEvent<E>, String>;
674
675    fn user_membership(&self, user_id: &UserId) -> Result<MembershipState, String>;
676
677    fn room_power_levels_event(&self) -> Option<RoomPowerLevelsEvent<E>>;
678
679    fn join_rule(&self) -> Result<JoinRuleKind, String>;
680
681    fn room_third_party_invite_event(&self, token: &str) -> Option<RoomThirdPartyInviteEvent<E>>;
682}
683
684impl<E, F> FetchStateExt<E> for F
685where
686    F: Fn(&StateEventType, &str) -> Option<E>,
687    E: Event,
688{
689    fn room_create_event(&self) -> Result<RoomCreateEvent<E>, String> {
690        self(&StateEventType::RoomCreate, "")
691            .map(RoomCreateEvent::new)
692            .ok_or_else(|| "no `m.room.create` event in current state".to_owned())
693    }
694
695    fn user_membership(&self, user_id: &UserId) -> Result<MembershipState, String> {
696        self(&StateEventType::RoomMember, user_id.as_str()).map(RoomMemberEvent::new).membership()
697    }
698
699    fn room_power_levels_event(&self) -> Option<RoomPowerLevelsEvent<E>> {
700        self(&StateEventType::RoomPowerLevels, "").map(RoomPowerLevelsEvent::new)
701    }
702
703    fn join_rule(&self) -> Result<JoinRuleKind, String> {
704        self(&StateEventType::RoomJoinRules, "")
705            .map(RoomJoinRulesEvent::new)
706            .ok_or_else(|| "no `m.room.join_rules` event in current state".to_owned())?
707            .join_rule()
708    }
709
710    fn room_third_party_invite_event(&self, token: &str) -> Option<RoomThirdPartyInviteEvent<E>> {
711        self(&StateEventType::RoomThirdPartyInvite, token).map(RoomThirdPartyInviteEvent::new)
712    }
713}