Page MenuHomePhorge

D345.1786157047.diff
No OneTemporary

Size
10 KB
Referenced Files
None
Subscribers
None

D345.1786157047.diff

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

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)

Event Timeline