Page MenuHomePhorge

D67.1732357758.diff
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

D67.1732357758.diff

diff --git a/src/client/room/room-model.hpp b/src/client/room/room-model.hpp
--- a/src/client/room/room-model.hpp
+++ b/src/client/room/room-model.hpp
@@ -230,6 +230,12 @@
std::string /* eventId */,
immer::flex_vector<std::string /* userId */>> eventReadUsers;
+ /// A map from the session id to a list of event ids of events
+ /// that cannot (yet) be decrypted.
+ immer::map<
+ std::string /* sessionId */,
+ immer::flex_vector<std::string /* eventId */>> undecryptedEvents;
+
immer::flex_vector<std::string> joinedMemberIds() const;
immer::flex_vector<std::string> invitedMemberIds() const;
immer::flex_vector<std::string> knockedMemberIds() const;
@@ -266,6 +272,16 @@
void regenerateRelationships();
+ /**
+ * Fill in undecryptedEvents by gathering
+ * the session ids specified in `newEvents`.
+ *
+ * @param newEvents New incoming events.
+ */
+ void addToUndecryptedEvents(EventList newEvents);
+
+ void recalculateUndecryptedEvents();
+
using Action = std::variant<
AddStateEventsAction,
AddToTimelineAction,
@@ -317,6 +333,7 @@
&& a.localNotificationCount == b.localNotificationCount
&& a.readReceipts == b.readReceipts
&& a.eventReadUsers == b.eventReadUsers
+ && a.undecryptedEvents == b.undecryptedEvents
;
}
@@ -402,6 +419,13 @@
& r.readReceipts
& r.eventReadUsers;
}
+ if (version >= 7) {
+ ar & r.undecryptedEvents;
+ } else {
+ if constexpr (typename Archive::is_loading()) {
+ r.recalculateUndecryptedEvents();
+ }
+ }
}
template<class Archive>
@@ -413,5 +437,5 @@
BOOST_CLASS_VERSION(Kazv::PendingRoomKeyEvent, 1)
BOOST_CLASS_VERSION(Kazv::ReadReceipt, 0)
-BOOST_CLASS_VERSION(Kazv::RoomModel, 6)
+BOOST_CLASS_VERSION(Kazv::RoomModel, 7)
BOOST_CLASS_VERSION(Kazv::RoomListModel, 0)
diff --git a/src/client/room/room-model.cpp b/src/client/room/room-model.cpp
--- a/src/client/room/room-model.cpp
+++ b/src/client/room/room-model.cpp
@@ -160,6 +160,8 @@
// calculate event relationships
r.generateRelationships(a.events);
+ r.addToUndecryptedEvents(a.events);
+
return r;
},
[&](AddAccountDataAction a) {
@@ -556,4 +558,39 @@
return kv.second;
}), messages));
}
+
+ void RoomModel::addToUndecryptedEvents(EventList newEvents)
+ {
+ if (!encrypted) {
+ return;
+ }
+
+ for (auto event : newEvents) {
+ if (event.encrypted() && !event.decrypted()) {
+ auto original = event.originalJson();
+ const auto &o = original.get();
+ if (o.contains("content")
+ && o["content"].contains("session_id")
+ && o["content"]["session_id"].is_string()
+ ) {
+ auto sessionId = o["content"]["session_id"].template get<std::string>();
+ undecryptedEvents = std::move(undecryptedEvents)
+ .update(sessionId, [id=event.id()](const auto &v) {
+ return v.push_back(id);
+ });
+ }
+ }
+ }
+ }
+
+ void RoomModel::recalculateUndecryptedEvents()
+ {
+ if (!encrypted) {
+ return;
+ }
+
+ addToUndecryptedEvents(intoImmer(EventList{}, zug::map([](const auto &kv) {
+ return kv.second;
+ }), messages));
+ }
}
diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt
--- a/src/tests/CMakeLists.txt
+++ b/src/tests/CMakeLists.txt
@@ -81,6 +81,7 @@
client/create-room-test.cpp
client/device-list-tracker-benchmark-test.cpp
client/room/read-receipt-test.cpp
+ client/room/undecrypted-events-test.cpp
EXTRA_LINK_LIBRARIES kazvclient kazveventemitter kazvjob client-test-lib kazvtestfixtures
EXTRA_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/client
)
diff --git a/src/tests/client/room/undecrypted-events-test.cpp b/src/tests/client/room/undecrypted-events-test.cpp
new file mode 100644
--- /dev/null
+++ b/src/tests/client/room/undecrypted-events-test.cpp
@@ -0,0 +1,141 @@
+/*
+ * This file is part of libkazv.
+ * SPDX-FileCopyrightText: 2024 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+#include <libkazv-config.hpp>
+#include <catch2/catch_test_macros.hpp>
+#include <sstream>
+#include <boost/archive/text_iarchive.hpp>
+#include <boost/archive/text_oarchive.hpp>
+#include <asio-promise-handler.hpp>
+#include "factory.hpp"
+#include "client-test-util.hpp"
+
+using namespace Kazv;
+using namespace Kazv::Factory;
+
+TEST_CASE("RoomModel::undecryptedEvents", "[client][room][encryption]")
+{
+ auto events = EventList{
+ // not encrypted events, not taken into account
+ makeEvent(),
+ makeEvent(withEventKV("/content/session_id"_json_pointer, "some-session-id")),
+ // encrypted event, not decrypted, valid session id
+ makeEvent(withEventId("$some-event-0") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, "some-session-id")),
+ makeEvent(withEventId("$some-event-1") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, "some-other-session-id")),
+ makeEvent(withEventId("$some-event-2") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, "some-session-id")),
+ // session id is not a string, not taken into account
+ makeEvent(withEventId("$some-event-3") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, json())),
+ // decrypted events are not taken into account
+ makeEvent(withEventId("$some-event-4") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, "some-other-session-id"))
+ .setDecryptedJson(json::object({}), Event::Decrypted),
+ };
+
+ SECTION("it calculates for an encrypted room")
+ {
+ auto room = makeRoom(withRoomEncrypted(true) | withRoomTimeline(events));
+
+ auto expected = immer::map<std::string, immer::flex_vector<std::string>>{
+ {"some-session-id", {"$some-event-0", "$some-event-2"}},
+ {"some-other-session-id", {"$some-event-1"}},
+ };
+
+ REQUIRE(room.undecryptedEvents == expected);
+ }
+
+ SECTION("it does not calculate for an unencrypted room")
+ {
+ auto room = makeRoom(withRoomEncrypted(false) | withRoomTimeline(events));
+ REQUIRE(room.undecryptedEvents == immer::map<std::string, immer::flex_vector<std::string>>{});
+ }
+}
+
+TEST_CASE("Serialize RoomModel with undecryptedEvents", "[client][serialization][room]")
+{
+ using IAr = boost::archive::text_iarchive;
+ using OAr = boost::archive::text_oarchive;
+
+ auto events = EventList{
+ makeEvent(withEventId("$some-event-0") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, "some-session-id")),
+ };
+
+ auto expected = immer::map<std::string, immer::flex_vector<std::string>>{
+ {"some-session-id", {
+ "$some-event-0",
+ }},
+ };
+
+ RoomModel m1 = makeRoom(withRoomEncrypted(true) | withRoomTimeline(events));
+ m1.undecryptedEvents = {}; // force clear the undecrypted map
+ RoomModel m2;
+
+ WHEN("reading from an archive older than v7") {
+ std::stringstream stream;
+
+ {
+ auto ar = OAr(stream);
+ serialize(ar, m1, 6); // HACK to save as v6, thus bypassing event relationships
+ }
+
+ {
+ auto ar = IAr(stream);
+ serialize(ar, m2, 6);
+ }
+
+ THEN("it should regenerate undecryptedEvents") {
+ REQUIRE(m2.undecryptedEvents == expected);
+ }
+ }
+
+ WHEN("reading from an archive later or equal to v7") {
+ std::stringstream stream;
+
+ {
+ auto ar = OAr(stream);
+ ar << m1;
+ }
+
+ {
+ auto ar = IAr(stream);
+ ar >> m2;
+ }
+
+ THEN("it should not regenerate undecryptedEvents") {
+ REQUIRE(m2.undecryptedEvents == immer::map<std::string, immer::flex_vector<std::string>>{});
+ }
+ }
+}
+
+TEST_CASE("Serialize unencrypted RoomModel with undecryptedEvents", "[client][serialization][room]")
+{
+ using IAr = boost::archive::text_iarchive;
+ using OAr = boost::archive::text_oarchive;
+
+ auto events = EventList{
+ makeEvent(withEventId("$some-event-0") | withEventType("m.room.encrypted") | withEventKV("/content/session_id"_json_pointer, "some-session-id")),
+ };
+
+ RoomModel m1 = makeRoom(withRoomEncrypted(false) | withRoomTimeline(events));
+ m1.undecryptedEvents = {}; // force clear the undecrypted map
+ RoomModel m2;
+
+ WHEN("reading from an archive older than v7") {
+ std::stringstream stream;
+
+ {
+ auto ar = OAr(stream);
+ serialize(ar, m1, 6); // HACK to save as v6, thus bypassing event relationships
+ }
+
+ {
+ auto ar = IAr(stream);
+ serialize(ar, m2, 6);
+ }
+
+ THEN("it not should regenerate undecryptedEvents") {
+ REQUIRE(m2.undecryptedEvents == immer::map<std::string, immer::flex_vector<std::string>>{});
+ }
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Sat, Nov 23, 2:29 AM (17 h, 10 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
39114
Default Alt Text
D67.1732357758.diff (9 KB)

Event Timeline