12
12
// See the License for the specific language governing permissions and
13
13
// limitations under the License.
14
14
15
+ use std:: borrow:: Cow ;
15
16
use std:: collections:: BTreeMap ;
16
17
18
+ use crate :: push:: { PushRule , PushRules } ;
17
19
use anyhow:: { Context , Error } ;
18
20
use lazy_static:: lazy_static;
19
21
use log:: warn;
@@ -32,7 +34,30 @@ lazy_static! {
32
34
33
35
/// Used to determine which MSC3931 room version feature flags are actually known to
34
36
/// 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
+ }
36
61
}
37
62
38
63
/// Allows running a set of push rules against a particular event.
@@ -121,7 +146,22 @@ impl PushRuleEvaluator {
121
146
continue ;
122
147
}
123
148
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
+
124
155
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
+ } ;
125
165
match self . match_condition ( condition, user_id, display_name) {
126
166
Ok ( true ) => { }
127
167
Ok ( false ) => continue ' outer,
@@ -132,6 +172,13 @@ impl PushRuleEvaluator {
132
172
}
133
173
}
134
174
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
+
135
182
let actions = push_rule
136
183
. actions
137
184
. iter ( )
@@ -394,3 +441,51 @@ fn push_rule_evaluator() {
394
441
let result = evaluator. run ( & FilteredPushRules :: default ( ) , None , Some ( "bob" ) ) ;
395
442
assert_eq ! ( result. len( ) , 3 ) ;
396
443
}
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
+ true ,
459
+ )
460
+ . unwrap ( ) ;
461
+
462
+ // first test: are the master and contains_user_name rules excluded from the "requires room
463
+ // version condition" check?
464
+ let mut result = evaluator. run (
465
+ & FilteredPushRules :: default ( ) ,
466
+ Some ( "@bob:example.org" ) ,
467
+ None ,
468
+ ) ;
469
+ assert_eq ! ( result. len( ) , 3 ) ;
470
+
471
+ // second test: if an appropriate push rule is in play, does it get handled?
472
+ let custom_rule = PushRule {
473
+ rule_id : Cow :: from ( "global/underride/.org.example.extensible" ) ,
474
+ priority_class : 1 , // underride
475
+ conditions : Cow :: from ( vec ! [ Condition :: Known (
476
+ KnownCondition :: RoomVersionSupports {
477
+ feature: Cow :: from( RoomVersionFeatures :: ExtensibleEvents . as_str( ) . to_string( ) ) ,
478
+ } ,
479
+ ) ] ) ,
480
+ actions : Cow :: from ( vec ! [ Action :: Notify ] ) ,
481
+ default : false ,
482
+ default_enabled : true ,
483
+ } ;
484
+ let rules = PushRules :: new ( vec ! [ custom_rule] ) ;
485
+ result = evaluator. run (
486
+ & FilteredPushRules :: py_new ( rules, BTreeMap :: new ( ) , true ) ,
487
+ None ,
488
+ None ,
489
+ ) ;
490
+ assert_eq ! ( result. len( ) , 1 ) ;
491
+ }
0 commit comments