Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F112882
D67.1732357758.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
9 KB
Referenced Files
None
Subscribers
None
D67.1732357758.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D67: Calculate a map from session id to undecrypted event ids in Room
Attached
Detach File
Event Timeline
Log In to Comment