Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F85629361
D345.1786157047.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Award Token
Flag For Later
Size
10 KB
Referenced Files
None
Subscribers
None
D345.1786157047.diff
View Options
diff --git a/src/client/actions/encryption.hpp b/src/client/actions/encryption.hpp
--- a/src/client/actions/encryption.hpp
+++ b/src/client/actions/encryption.hpp
@@ -41,4 +41,6 @@
ClientResult updateClient(ClientModel m, ImportFromKeyBackupFileAction a);
ClientResult updateClient(ClientModel m, NotifyVerificationTrackerModelAction a);
+
+ ClientResult updateClient(ClientModel m, RequestShareRoomSessionKeyAction a);
}
diff --git a/src/client/actions/encryption.cpp b/src/client/actions/encryption.cpp
--- a/src/client/actions/encryption.cpp
+++ b/src/client/actions/encryption.cpp
@@ -10,12 +10,14 @@
#include <zug/transducer/cat.hpp>
#include "encryption.hpp"
+#include "send.hpp"
#include <immer-utils.hpp>
#include <debug.hpp>
#include "cursorutil.hpp"
#include "status-utils.hpp"
#include "key-export.hpp"
+#include "clientutil.hpp"
namespace Kazv
{
@@ -838,4 +840,38 @@
m.addTrigger(VerificationTrackerModelChanged{});
return {std::move(m), lager::noop};
}
+
+ ClientResult updateClient(ClientModel m, RequestShareRoomSessionKeyAction a)
+ {
+ auto devices = a.devices.empty() ? m.devicesToRequestKeys() : a.devices;
+ auto origEventJson = a.event.originalJson().get();
+ if (!(
+ origEventJson.contains("/content/algorithm"_json_pointer)
+ && origEventJson.contains("/content/session_id"_json_pointer)
+ )) {
+ return { std::move(m), failEffect("MOE.KAZV.MXC_BAD_EVENT", "Event is malformed") };
+ }
+ auto requestId = getTxnId(Event(), m);
+ auto requestJson = json{
+ {"type", "m.room_key_request"},
+ {"content", {
+ {"action", "request"},
+ {"body", {
+ {"algorithm", origEventJson.at("/content/algorithm"_json_pointer)},
+ {"room_id", a.roomId},
+ {"session_id", origEventJson.at("/content/session_id"_json_pointer)},
+ }},
+ {"request_id", requestId},
+ {"requesting_device_id", m.deviceId},
+ }},
+ };
+ if (origEventJson.contains("/content/sender_key"_json_pointer)) {
+ requestJson["content"]["body"]["sender_key"] = origEventJson["/content/sender_key"_json_pointer];
+ }
+
+ return updateClient(std::move(m), SendToDeviceMessageAction{
+ Event(std::move(requestJson)),
+ devices,
+ });
+ }
}
diff --git a/src/client/client-model.hpp b/src/client/client-model.hpp
--- a/src/client/client-model.hpp
+++ b/src/client/client-model.hpp
@@ -92,6 +92,10 @@
immer::flex_vector<std::string /* deviceId */> devicesToSendKeys(std::string userId) const;
+ // Get the devices from which we are supposed to request keys.
+ // By the matrix specification, this is all verified devices of this user.
+ immer::map<std::string /* userId */, immer::flex_vector<std::string>> devicesToRequestKeys() const;
+
/// rotate sessions for a room if there is a user in the room with
/// devicesToSendKeys changes
void maybeRotateSessions(ClientModel oldClient);
@@ -663,6 +667,13 @@
*/
struct NotifyVerificationTrackerModelAction {};
+ struct RequestShareRoomSessionKeyAction
+ {
+ std::string roomId;
+ Event event;
+ immer::map<std::string, immer::flex_vector<std::string>> devices;
+ };
+
struct GetUserProfileAction
{
std::string userId;
diff --git a/src/client/client-model.cpp b/src/client/client-model.cpp
--- a/src/client/client-model.cpp
+++ b/src/client/client-model.cpp
@@ -308,6 +308,24 @@
devices);
}
+ immer::map<std::string /* userId */, immer::flex_vector<std::string>> ClientModel::devicesToRequestKeys() const
+ {
+ auto devices = deviceLists.devicesFor(userId);
+
+ return {
+ {userId, intoImmer(
+ immer::flex_vector<std::string>{},
+ zug::filter([=](auto n) {
+ auto [id, dev] = n;
+ return dev.trustLevel >= Verified && !dev.deleted;
+ })
+ | zug::map([](auto n) {
+ return n.first;
+ }),
+ devices)},
+ };
+ }
+
std::size_t ClientModel::numOneTimeKeysNeeded() const
{
const auto &crypto = constCrypto();
diff --git a/src/client/client.hpp b/src/client/client.hpp
--- a/src/client/client.hpp
+++ b/src/client/client.hpp
@@ -832,6 +832,23 @@
*/
PromiseT ensureInitVerificationTracker() const;
+ /**
+ * Request a key sharing from other devices.
+ *
+ * @param roomId The room id of the undecryptable event.
+ * @param event The undecryptable event. Must be a room event.
+ * @param devices The devices to send to. A map from user id to
+ * a list of device ids. If empty,
+ * this function will automatically use verified devices of the same user.
+ *
+ * @return A Promise that resolves when the key request is sent.
+ */
+ PromiseT requestShareRoomSessionKey(
+ std::string roomId,
+ Event event,
+ immer::map<std::string, immer::flex_vector<std::string>> devices = {}
+ ) const;
+
private:
void syncForever(std::optional<int> retryTime = std::nullopt) const;
diff --git a/src/client/client.cpp b/src/client/client.cpp
--- a/src/client/client.cpp
+++ b/src/client/client.cpp
@@ -517,6 +517,19 @@
});
}
+ auto Client::requestShareRoomSessionKey(
+ std::string roomId,
+ Event event,
+ immer::map<std::string, immer::flex_vector<std::string>> devices
+ ) const -> PromiseT
+ {
+ return m_ctx.dispatch(RequestShareRoomSessionKeyAction{
+ std::move(roomId),
+ std::move(event),
+ std::move(devices)
+ });
+ }
+
auto Client::syncForever(std::optional<int> retryTime) const -> void
{
KAZV_VERIFY_THREAD_ID();
diff --git a/src/client/clientfwd.hpp b/src/client/clientfwd.hpp
--- a/src/client/clientfwd.hpp
+++ b/src/client/clientfwd.hpp
@@ -75,6 +75,7 @@
struct PrepareForSharingRoomKeyAction;
struct ImportFromKeyBackupFileAction;
struct NotifyVerificationTrackerModelAction;
+ struct RequestShareRoomSessionKeyAction;
struct GetUserProfileAction;
struct SetAvatarUrlAction;
@@ -148,6 +149,7 @@
PrepareForSharingRoomKeyAction,
ImportFromKeyBackupFileAction,
NotifyVerificationTrackerModelAction,
+ RequestShareRoomSessionKeyAction,
GetUserProfileAction,
SetAvatarUrlAction,
diff --git a/src/tests/client/client-test-util.hpp b/src/tests/client/client-test-util.hpp
--- a/src/tests/client/client-test-util.hpp
+++ b/src/tests/client/client-test-util.hpp
@@ -53,3 +53,5 @@
}
Context<SdkAction> dumbContext();
+
+json getRequestJsonBody(const BaseJob &job);
diff --git a/src/tests/client/client-test-util.cpp b/src/tests/client/client-test-util.cpp
--- a/src/tests/client/client-test-util.cpp
+++ b/src/tests/client/client-test-util.cpp
@@ -52,3 +52,8 @@
lager::make_deps()
);
}
+
+json getRequestJsonBody(const BaseJob &job)
+{
+ return json::parse(std::get<Bytes>(job.requestBody()));
+}
diff --git a/src/tests/client/encryption-test.cpp b/src/tests/client/encryption-test.cpp
--- a/src/tests/client/encryption-test.cpp
+++ b/src/tests/client/encryption-test.cpp
@@ -727,3 +727,76 @@
u.io.run();
}
}
+
+TEST_CASE("Client::devicesToRequestKeys()", "[client][encryption]")
+{
+ auto device1 = makeDeviceKeyInfo(withAttr(&DeviceKeyInfo::trustLevel, Verified));
+ auto device2 = makeDeviceKeyInfo();
+ auto client = makeClient(
+ withAttr(&ClientModel::userId, "@mew:example.org")
+ | withDevice("@foo:example.org", makeDeviceKeyInfo(withAttr(&DeviceKeyInfo::trustLevel, Verified)))
+ | withDevice("@mew:example.org", device1)
+ | withDevice("@mew:example.org", device2)
+ );
+
+ auto expected = immer::map<std::string, immer::flex_vector<std::string>>{
+ {"@mew:example.org", {device1.deviceId}},
+ };
+ REQUIRE(client.devicesToRequestKeys() == expected);
+}
+
+TEST_CASE("RequestShareRoomSessionKeyAction", "[client][encryption]")
+{
+ auto roomId = "!someroom:example.com";
+ auto room = makeRoom(
+ withRoomEncrypted(true)
+ | withRoomId(roomId)
+ );
+ auto sendingClient = makeClient(
+ withCrypto(makeCrypto())
+ | withRoom(room)
+ );
+
+ auto plainText = makeEvent();
+ auto [encrypted, sessionId] = sendingClient.megOlmEncrypt(plainText, roomId, 1719196953000,
+ genRandomData(EncryptMegOlmEventAction::maxRandomSize()));
+
+ auto device1 = makeDeviceKeyInfo(withAttr(&DeviceKeyInfo::trustLevel, Verified));
+ auto client = makeClient(
+ withCrypto(makeCrypto())
+ | withAttr(&ClientModel::userId, "@mew:example.org")
+ | withDevice("@mew:example.org", device1)
+ | withRoom(room)
+ );
+
+ auto [next, _] = updateClient(client, RequestShareRoomSessionKeyAction{
+ roomId,
+ encrypted,
+ {},
+ });
+
+ assert1Job(next);
+ for1stJob(next, [device1, roomId, encrypted](const BaseJob &job) {
+ REQUIRE(job.jobId() == "SendToDevice");
+ auto body = getRequestJsonBody(job);
+ REQUIRE(job.url().find("/m.room_key_request/") != std::string::npos);
+ auto msg = body.at("messages").at("@mew:example.org").at(device1.deviceId);
+ REQUIRE(msg.at("action") == "request");
+ REQUIRE(msg.at("body").at("room_id") == roomId);
+ REQUIRE(msg.at("body").at("session_id") == encrypted.originalJson().get().at("/content/session_id"_json_pointer));
+ });
+}
+
+TEST_CASE("Client::requestShareRoomSessionKey", "[client][encryption]")
+{
+ auto u = makeMockSdkUtil(makeClient());
+ auto md = u.getMockDispatcher(returnResolved<RequestShareRoomSessionKeyAction>({true, {}}));
+ auto client = u.getClient(md);
+ client.requestShareRoomSessionKey("!roomid", makeEvent())
+ .then([&md, &u](auto) {
+ REQUIRE(md.template calledTimes<RequestShareRoomSessionKeyAction>() == 1);
+ u.io.stop();
+ });
+
+ u.io.run();
+}
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Aug 7, 7:44 PM (17 h, 11 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1723903
Default Alt Text
D345.1786157047.diff (10 KB)
Attached To
Mode
D345: Send room key request
Attached
Detach File
Event Timeline
Log In to Comment