Skip to main content

tuwunel_api/client/push/
mod.rs

1mod notifications;
2mod pushers;
3mod pushers_set;
4mod pushrules;
5mod pushrules_global;
6mod pushrules_rule;
7mod pushrules_rule_actions;
8mod pushrules_rule_enabled;
9#[cfg(test)]
10mod tests;
11
12use ruma::{
13	UserId,
14	events::{GlobalAccountDataEventType, push_rules::PushRulesEvent},
15	push::{
16		AnyPushRuleRef, NewPushRule, PredefinedContentRuleId, PredefinedOverrideRuleId, RuleKind,
17		Ruleset, SimplePushRule,
18	},
19};
20use tuwunel_core::{Err, Result, err, utils::json::serialized_len};
21use tuwunel_service::{
22	Services,
23	account_data::{MAX_RULE_BYTES, MAX_RULE_ID_BYTES, admits_rule},
24};
25
26pub(crate) use self::{
27	notifications::get_notifications_route,
28	pushers::get_pushers_route,
29	pushers_set::set_pushers_route,
30	pushrules::get_pushrules_all_route,
31	pushrules_global::get_pushrules_global_route,
32	pushrules_rule::{delete_pushrule_route, get_pushrule_route, set_pushrule_route},
33	pushrules_rule_actions::{get_pushrule_actions_route, set_pushrule_actions_route},
34	pushrules_rule_enabled::{get_pushrule_enabled_route, set_pushrule_enabled_route},
35};
36
37async fn load_push_rules(services: &Services, sender_user: &UserId) -> Result<PushRulesEvent> {
38	services
39		.account_data
40		.get_global(sender_user, GlobalAccountDataEventType::PushRules)
41		.await
42		.map_err(|_| err!(Request(NotFound("PushRules event not found."))))
43}
44
45async fn save_push_rules(
46	services: &Services,
47	sender_user: &UserId,
48	event: &PushRulesEvent,
49) -> Result {
50	let ty = GlobalAccountDataEventType::PushRules;
51
52	services
53		.account_data
54		.update(None, sender_user, ty.to_string().into(), &serde_json::to_value(event)?)
55		.await
56}
57
58fn check_rule_admission(ruleset: &Ruleset, rule: &NewPushRule) -> Result {
59	let rule_id = rule.rule_id();
60
61	if rule_id.len() > MAX_RULE_ID_BYTES {
62		return Err!(Request(TooLarge("Push rule ID is too long.")));
63	}
64
65	if !admits_rule(ruleset, rule.kind(), rule_id) {
66		return Err!(Request(InvalidParam("Account has too many push rules.")));
67	}
68
69	Ok(())
70}
71
72fn check_rule_size(ruleset: &Ruleset, kind: RuleKind, rule_id: &str) -> Result {
73	let rule = ruleset
74		.get(kind, rule_id)
75		.ok_or_else(|| err!(Request(NotFound("Push rule not found."))))?;
76
77	let size = match rule {
78		| AnyPushRuleRef::Override(rule) | AnyPushRuleRef::Underride(rule) =>
79			serialized_len(&(&rule.conditions, &rule.actions))?,
80
81		| AnyPushRuleRef::Content(rule) => serialized_len(&(&rule.pattern, &rule.actions))?,
82
83		| AnyPushRuleRef::Room(SimplePushRule { actions, .. })
84		| AnyPushRuleRef::Sender(SimplePushRule { actions, .. }) => serialized_len(actions)?,
85	};
86
87	if size > MAX_RULE_BYTES {
88		return Err!(Request(TooLarge("Push rule is too large.")));
89	}
90
91	Ok(())
92}
93
94// The deprecated mention push rules are hidden from clients as per MSC4210.
95#[expect(deprecated)]
96fn is_deprecated_mention_rule(rule_id: &str) -> bool {
97	rule_id == PredefinedContentRuleId::ContainsUserName.as_str()
98		|| rule_id == PredefinedOverrideRuleId::ContainsDisplayName.as_str()
99		|| rule_id == PredefinedOverrideRuleId::RoomNotif.as_str()
100}