1212// See the License for the specific language governing permissions and
1313// limitations under the License.
1414
15+ use std:: borrow:: Cow ;
1516use std:: collections:: BTreeMap ;
1617
18+ use crate :: push:: { PushRule , PushRules } ;
1719use anyhow:: { Context , Error } ;
1820use lazy_static:: lazy_static;
1921use log:: warn;
@@ -32,7 +34,30 @@ lazy_static! {
3234
3335 /// Used to determine which MSC3931 room version feature flags are actually known to
3436 /// the push evaluator.
35- static ref KNOWN_RVER_FLAGS : Vec <String > = vec![ ] ;
37+ static ref KNOWN_RVER_FLAGS : Vec <String > = vec![
38+ RoomVersionFeatures :: ExtensibleEvents . as_str( ) . to_string( ) ,
39+ ] ;
40+
41+ /// The "safe" rule IDs which are not affected by MSC3932's behaviour (room versions which
42+ /// declare Extensible Events support ultimately *disable* push rules which do not declare
43+ /// *any* MSC3931 room_version_supports condition).
44+ static ref SAFE_EXTENSIBLE_EVENTS_RULE_IDS : Vec <String > = vec![
45+ "global/override/.m.rule.master" . to_string( ) ,
46+ "global/override/.m.rule.roomnotif" . to_string( ) ,
47+ "global/content/.m.rule.contains_user_name" . to_string( ) ,
48+ ] ;
49+ }
50+
51+ enum RoomVersionFeatures {
52+ ExtensibleEvents ,
53+ }
54+
55+ impl RoomVersionFeatures {
56+ fn as_str ( & self ) -> & ' static str {
57+ match self {
58+ RoomVersionFeatures :: ExtensibleEvents => "org.matrix.msc3932.extensible_events" ,
59+ }
60+ }
3661}
3762
3863/// Allows running a set of push rules against a particular event.
@@ -121,7 +146,22 @@ impl PushRuleEvaluator {
121146 continue ;
122147 }
123148
149+ let rule_id = & push_rule. rule_id ( ) . to_string ( ) ;
150+ let extev_flag = & RoomVersionFeatures :: ExtensibleEvents . as_str ( ) . to_string ( ) ;
151+ let supports_extensible_events = self . room_version_feature_flags . contains ( extev_flag) ;
152+ let safe_from_rver_condition = SAFE_EXTENSIBLE_EVENTS_RULE_IDS . contains ( rule_id) ;
153+ let mut has_rver_condition = false ;
154+
124155 for condition in push_rule. conditions . iter ( ) {
156+ has_rver_condition = has_rver_condition
157+ || match condition {
158+ Condition :: Known ( known) => match known {
159+ // per MSC3932, we just need *any* room version condition to match
160+ KnownCondition :: RoomVersionSupports { feature : _ } => true ,
161+ _ => false ,
162+ } ,
163+ _ => false ,
164+ } ;
125165 match self . match_condition ( condition, user_id, display_name) {
126166 Ok ( true ) => { }
127167 Ok ( false ) => continue ' outer,
@@ -132,6 +172,13 @@ impl PushRuleEvaluator {
132172 }
133173 }
134174
175+ // MSC3932: Disable push rules in extensible event-supporting room versions if they
176+ // don't describe *any* MSC3931 room version condition, unless the rule is on the
177+ // safe list.
178+ if !has_rver_condition && !safe_from_rver_condition && supports_extensible_events {
179+ continue ;
180+ }
181+
135182 let actions = push_rule
136183 . actions
137184 . iter ( )
@@ -394,3 +441,50 @@ fn push_rule_evaluator() {
394441 let result = evaluator. run ( & FilteredPushRules :: default ( ) , None , Some ( "bob" ) ) ;
395442 assert_eq ! ( result. len( ) , 3 ) ;
396443}
444+
445+ #[ test]
446+ fn test_requires_room_version_supports_condition ( ) {
447+ let mut flattened_keys = BTreeMap :: new ( ) ;
448+ flattened_keys. insert ( "content.body" . to_string ( ) , "foo bar bob hello" . to_string ( ) ) ;
449+ let flags = vec ! [ RoomVersionFeatures :: ExtensibleEvents . as_str( ) . to_string( ) ] ;
450+ let evaluator = PushRuleEvaluator :: py_new (
451+ flattened_keys,
452+ 10 ,
453+ Some ( 0 ) ,
454+ BTreeMap :: new ( ) ,
455+ BTreeMap :: new ( ) ,
456+ false ,
457+ flags,
458+ )
459+ . unwrap ( ) ;
460+
461+ // first test: are the master and contains_user_name rules excluded from the "requires room
462+ // version condition" check?
463+ let mut result = evaluator. run (
464+ & FilteredPushRules :: default ( ) ,
465+ Some ( "@bob:example.org" ) ,
466+ None ,
467+ ) ;
468+ assert_eq ! ( result. len( ) , 3 ) ;
469+
470+ // second test: if an appropriate push rule is in play, does it get handled?
471+ let custom_rule = PushRule {
472+ rule_id : Cow :: from ( "global/underride/.org.example.extensible" ) ,
473+ priority_class : 1 , // underride
474+ conditions : Cow :: from ( vec ! [ Condition :: Known (
475+ KnownCondition :: RoomVersionSupports {
476+ feature: Cow :: from( RoomVersionFeatures :: ExtensibleEvents . as_str( ) . to_string( ) ) ,
477+ } ,
478+ ) ] ) ,
479+ actions : Cow :: from ( vec ! [ Action :: Notify ] ) ,
480+ default : false ,
481+ default_enabled : true ,
482+ } ;
483+ let rules = PushRules :: new ( vec ! [ custom_rule] ) ;
484+ result = evaluator. run (
485+ & FilteredPushRules :: py_new ( rules, BTreeMap :: new ( ) , true ) ,
486+ None ,
487+ None ,
488+ ) ;
489+ assert_eq ! ( result. len( ) , 1 ) ;
490+ }
0 commit comments