Page MenuHomePhorge

D333.1784755652.diff
No OneTemporary

Size
13 KB
Referenced Files
None
Subscribers
None

D333.1784755652.diff

diff --git a/src/client/notification-handler.cpp b/src/client/notification-handler.cpp
--- a/src/client/notification-handler.cpp
+++ b/src/client/notification-handler.cpp
@@ -42,8 +42,11 @@
PushAction NotificationHandler::handleNotification(const Event &e) const
{
- auto roomId = e.raw().get().contains("room_id")
- ? e.raw().get()["room_id"].template get<std::string>()
+ // https://spec.matrix.org/v1.19/client-server-api/#receiving-notifications
+ // "Clients should process push rules for each incoming event after decrypting them."
+ // room_id is always in the outer cleartext event
+ auto roomId = e.originalJson().get().contains("room_id")
+ ? e.originalJson().get()["room_id"].template get<std::string>()
: std::string();
auto room = m_d->client[&ClientModel::roomList][&RoomListModel::rooms][roomId][lager::lenses::or_default].make().get();
return m_d->pushRulesDesc.get().handle(e, room);
diff --git a/src/client/push-rules-desc.cpp b/src/client/push-rules-desc.cpp
--- a/src/client/push-rules-desc.cpp
+++ b/src/client/push-rules-desc.cpp
@@ -232,21 +232,24 @@
}
if (ruleSetName == "override" || ruleSetName == "underride") {
+ // If the event is not decrypted, use the cleartext event json
+ // (the event can also be unencrypted, which only has cleartext)
+ auto eventJson = e.decrypted() ? e.raw().get() : e.originalJson().get();
return std::all_of(
rule.at("conditions").begin(),
rule.at("conditions").end(),
- [&e, &room](const auto &condition) mutable {
+ [&eventJson, &room](const auto &condition) mutable {
if (condition.is_object()) {
if (condition.at("kind") == "event_property_is") {
auto path = splitPath(condition.at("key"));
- auto valueInEvent = getInJson(e.originalJson().get(), path);
+ auto valueInEvent = getInJson(eventJson, path);
if (!valueInEvent.has_value() || !isNonCompoundCanonicalJsonValue(valueInEvent.value())) {
return false;
}
return valueInEvent.value() == condition.at("value");
} else if (condition.at("kind") == "event_match") {
auto path = splitPath(condition.at("key"));
- auto valueInEvent = getInJson(e.originalJson().get(), path);
+ auto valueInEvent = getInJson(eventJson, path);
if (!valueInEvent.has_value() || !valueInEvent.value().is_string()) {
return false;
}
@@ -255,7 +258,7 @@
return matchGlob(valueStr, patternStr);
} else if (condition.at("kind") == "event_property_contains") {
auto path = splitPath(condition.at("key"));
- auto valueInEvent = getInJson(e.originalJson().get(), path);
+ auto valueInEvent = getInJson(eventJson, path);
if (!valueInEvent.has_value() || !valueInEvent.value().is_array()) {
return false;
}
diff --git a/src/tests/client/notification-handler-test.cpp b/src/tests/client/notification-handler-test.cpp
--- a/src/tests/client/notification-handler-test.cpp
+++ b/src/tests/client/notification-handler-test.cpp
@@ -10,6 +10,7 @@
#include <notification-handler.hpp>
#include <asio-promise-handler.hpp>
#include <factory.hpp>
+#include <room/room-model.hpp>
#include "push-rules-test-util.hpp"
#include "client-test-util.hpp"
@@ -17,6 +18,14 @@
using namespace Kazv;
using namespace Kazv::Factory;
+static Event makePushRulesEvent(const json &pushRulesContent)
+{
+ return makeEvent(
+ withEventContent(pushRulesContent)
+ | withEventType("m.push_rules")
+ );
+}
+
TEST_CASE("NotificationHandler::handleNotification()", "[client][push-rules]")
{
auto pushRulesEvent = makeEvent(
@@ -44,3 +53,143 @@
REQUIRE(res.shouldNotify);
}
+
+TEST_CASE("NotificationHandler resolves room for encrypted and undecryptable events", "[client][push-rules][notification]")
+{
+ auto rulesContent = emptyRulesContent;
+ rulesContent["global"]["override"].push_back(suppressNoticesRule);
+ rulesContent["global"]["override"].push_back(encryptedOneToOneRule);
+ rulesContent["global"]["underride"].push_back(messageRule);
+
+ auto pushRulesEvent = makePushRulesEvent(rulesContent);
+
+ auto room = makeRoom();
+ room.joinedMemberCount = 2;
+
+ auto clientModel = makeClient(
+ withRoom(room)
+ | withAccountData({pushRulesEvent})
+ );
+
+ auto io = boost::asio::io_context();
+ auto ph = AsioPromiseHandler(io.get_executor());
+ auto store = createTestClientStoreFrom(clientModel, ph);
+
+ auto client = Client(
+ store.reader().map([](auto c) { return SdkModel{c}; }),
+ store,
+ std::nullopt
+ );
+
+ auto nh = client.notificationHandler();
+
+ SECTION("unencrypted event finds room and matches .m.rule.message")
+ {
+ auto unencryptedEvt = makeEvent(
+ withEventKV("/room_id"_json_pointer, room.roomId)
+ );
+
+ auto result = nh.handleNotification(unencryptedEvt);
+ REQUIRE(result.shouldNotify);
+ }
+
+ SECTION("encrypted event in one-to-one room matches .m.rule.encrypted_room_one_to_one")
+ {
+ auto encryptedEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/room_id"_json_pointer, room.roomId)
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ );
+
+ auto result = nh.handleNotification(encryptedEvt);
+ REQUIRE(result.shouldNotify);
+ REQUIRE(result.sound.has_value());
+ REQUIRE(result.sound.value() == "default");
+ }
+
+ SECTION("undecryptable event in one-to-one room matches .m.rule.encrypted_room_one_to_one")
+ {
+ auto undecryptableEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/room_id"_json_pointer, room.roomId)
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ );
+ undecryptableEvt = undecryptableEvt.setDecryptedJson(
+ json{
+ {"type", "m.room.message"},
+ {"content", {
+ {"msgtype", "moe.kazv.mxc.cannot.decrypt"},
+ {"body", "**This message cannot be decrypted due to some reason.**"},
+ {"moe.kazv.mxc.error", "some reason"},
+ {"moe.kazv.mxc.errcode", "MOE.KAZV.MXC_DECRYPT_ERROR"},
+ {"moe.kazv.mxc.raw", json(nullptr)},
+ }},
+ },
+ Event::NotDecrypted
+ );
+
+ auto result = nh.handleNotification(undecryptableEvt);
+ REQUIRE(result.shouldNotify);
+ REQUIRE(result.sound.has_value());
+ REQUIRE(result.sound.value() == "default");
+ }
+}
+
+TEST_CASE("AddLocalNotificationsAction adds notifications for encrypted events", "[client][push-rules][room]")
+{
+ auto rulesContent = emptyRulesContent;
+ rulesContent["global"]["underride"].push_back(encryptedRule);
+ auto pushRules = PushRulesDesc(makePushRulesEvent(rulesContent));
+
+ auto encryptedEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ | withEventSenderId("@someone:example.com")
+ );
+
+ auto room = makeRoom(
+ withRoomEncrypted(true)
+ | withRoomTimeline({encryptedEvt})
+ );
+
+ auto updatedRoom = RoomModel::update(
+ room,
+ AddLocalNotificationsAction{
+ immer::flex_vector<Event>{encryptedEvt},
+ pushRules,
+ "@bob:example.com",
+ }
+ );
+
+ REQUIRE(!updatedRoom.unreadNotificationEventIds.empty());
+ REQUIRE(updatedRoom.unreadNotificationEventIds[0] == encryptedEvt.id());
+}
+
+TEST_CASE("AddLocalNotificationsAction does not add notifications for own events", "[client][push-rules][room]")
+{
+ auto rulesContent = emptyRulesContent;
+ rulesContent["global"]["underride"].push_back(encryptedRule);
+ auto pushRules = PushRulesDesc(makePushRulesEvent(rulesContent));
+
+ auto ownEncryptedEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ | withEventSenderId("@bob:example.com")
+ );
+
+ auto room = makeRoom(
+ withRoomEncrypted(true)
+ | withRoomTimeline({ownEncryptedEvt})
+ );
+
+ auto updatedRoom = RoomModel::update(
+ room,
+ AddLocalNotificationsAction{
+ immer::flex_vector<Event>{ownEncryptedEvt},
+ pushRules,
+ "@bob:example.com",
+ }
+ );
+
+ REQUIRE(updatedRoom.unreadNotificationEventIds.empty());
+}
diff --git a/src/tests/client/push-rules-desc-test.cpp b/src/tests/client/push-rules-desc-test.cpp
--- a/src/tests/client/push-rules-desc-test.cpp
+++ b/src/tests/client/push-rules-desc-test.cpp
@@ -551,3 +551,105 @@
REQUIRE(PushRulesDesc(makePushRulesEvent(rulesContent)).handle(makeEvent(), room).shouldHighlight);
}
}
+
+TEST_CASE("PushRulesDesc handles encrypted events", "[client][push-rules]")
+{
+ auto rulesContent = emptyRulesContent;
+ rulesContent["global"]["underride"].push_back(encryptedRule);
+ auto pushRules = PushRulesDesc(makePushRulesEvent(rulesContent));
+ auto room = makeRoom();
+
+ auto encryptedEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ );
+
+ REQUIRE(pushRules.handle(encryptedEvt, room).shouldNotify);
+}
+
+TEST_CASE("PushRulesDesc handles undecryptable events", "[client][push-rules]")
+{
+ auto rulesContent = emptyRulesContent;
+ rulesContent["global"]["underride"].push_back(encryptedRule);
+ auto pushRules = PushRulesDesc(makePushRulesEvent(rulesContent));
+ auto room = makeRoom();
+
+ auto undecryptableEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ );
+ undecryptableEvt = undecryptableEvt.setDecryptedJson(
+ json{
+ {"type", "m.room.message"},
+ {"content", {
+ {"msgtype", "moe.kazv.mxc.cannot.decrypt"},
+ {"body", "**This message cannot be decrypted due to some reason.**"},
+ {"moe.kazv.mxc.error", "some reason"},
+ {"moe.kazv.mxc.errcode", "MOE.KAZV.MXC_DECRYPT_ERROR"},
+ {"moe.kazv.mxc.raw", json(nullptr)},
+ }},
+ },
+ Event::NotDecrypted
+ );
+
+ REQUIRE(pushRules.handle(undecryptableEvt, room).shouldNotify);
+}
+
+TEST_CASE("PushRulesDesc uses correct type for decrypted vs undecryptable events", "[client][push-rules]")
+{
+ auto rulesContent = emptyRulesContent;
+ auto room = makeRoom();
+
+ SECTION("decrypted event should use decrypted type")
+ {
+ rulesContent["global"]["underride"].push_back(messageRule);
+ auto pushRules = PushRulesDesc(makePushRulesEvent(rulesContent));
+
+ auto decryptedEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ );
+ decryptedEvt = decryptedEvt.setDecryptedJson(
+ json{
+ {"type", "m.room.message"},
+ {"content", {
+ {"msgtype", "m.text"},
+ {"body", "hello"},
+ }},
+ },
+ Event::Decrypted
+ );
+
+ REQUIRE(decryptedEvt.decrypted());
+ REQUIRE(decryptedEvt.raw().get()["type"] == "m.room.message");
+ REQUIRE(decryptedEvt.originalJson().get()["type"] == "m.room.encrypted");
+ REQUIRE(pushRules.handle(decryptedEvt, room).shouldNotify);
+ }
+
+ SECTION("undecryptable event should use originalJson() with m.room.encrypted type")
+ {
+ rulesContent["global"]["underride"].push_back(encryptedRule);
+ auto pushRules = PushRulesDesc(makePushRulesEvent(rulesContent));
+
+ auto undecryptableEvt = makeEvent(
+ withEventType("m.room.encrypted")
+ | withEventKV("/content/session_id"_json_pointer, "some-session-id")
+ );
+ undecryptableEvt = undecryptableEvt.setDecryptedJson(
+ json{
+ {"type", "m.room.message"},
+ {"content", {
+ {"msgtype", "moe.kazv.mxc.cannot.decrypt"},
+ {"body", "**Cannot decrypt**"},
+ }},
+ },
+ Event::NotDecrypted
+ );
+
+ REQUIRE(!undecryptableEvt.decrypted());
+ REQUIRE(undecryptableEvt.originalJson().get()["type"] == "m.room.encrypted");
+ // Undecryptable events are not decrypted, so they should use
+ // originalJson() with type m.room.encrypted to match .m.rule.encrypted.
+ REQUIRE(pushRules.handle(undecryptableEvt, room).shouldNotify);
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Wed, Jul 22, 2:27 PM (21 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1701929
Default Alt Text
D333.1784755652.diff (13 KB)

Event Timeline