Page MenuHomePhorge

D280.1771237483.diff
No OneTemporary

Size
7 KB
Referenced Files
None
Subscribers
None

D280.1771237483.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
@@ -1,6 +1,6 @@
/*
* This file is part of libkazv.
- * SPDX-FileCopyrightText: 2021 Tusooa Zhu <tusooa@kazv.moe>
+ * SPDX-FileCopyrightText: 2021-2026 tusooa <tusooa@kazv.moe>
* SPDX-License-Identifier: AGPL-3.0-or-later
*/
@@ -33,4 +33,6 @@
ClientResult updateClient(ClientModel m, SetTrustLevelNeededToSendKeysAction a);
ClientResult updateClient(ClientModel m, PrepareForSharingRoomKeyAction a);
+
+ ClientResult updateClient(ClientModel m, ImportFromKeyBackupFileAction 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
@@ -15,6 +15,7 @@
#include <debug.hpp>
#include "cursorutil.hpp"
#include "status-utils.hpp"
+#include "key-export.hpp"
namespace Kazv
{
@@ -688,4 +689,30 @@
return EffectStatus(/* succ = */ true, json::object({{"txnId", txnId}}));
} };
}
+
+ ClientResult updateClient(ClientModel m, ImportFromKeyBackupFileAction a)
+ {
+ auto maybeExportFile = decryptKeyExport(std::move(a.fileContent), std::move(a.password));
+ if (!maybeExportFile) {
+ return {std::move(m), Kazv::detail::ReturnEffectStatusT{{
+ /* succ = */ false,
+ json{
+ {"errorCode", maybeExportFile.reason()},
+ {"error", maybeExportFile.reason()},
+ },
+ }}};
+ }
+
+ std::size_t imported = 0;
+ m.withCrypto([&maybeExportFile, &imported](Crypto &c) {
+ imported = c.importInboundGroupSessions(std::move(maybeExportFile).value());
+ });
+
+ return {std::move(m), Kazv::detail::ReturnEffectStatusT{{
+ /* succ = */ true,
+ json{
+ {"imported", imported},
+ },
+ }}};
+ };
}
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
@@ -567,6 +567,21 @@
RandomData random;
};
+ /**
+ * Import keys from key backup file.
+ *
+ * On success, the reducer returns data with `imported` property
+ * being the number of keys imported. On failure, it returns data with
+ * `errorCode` and `error` properties set to the error in the process.
+ */
+ struct ImportFromKeyBackupFileAction
+ {
+ /// The content of the key backup file.
+ std::string fileContent;
+ /// The password.
+ std::string password;
+ };
+
struct GetUserProfileAction
{
std::string userId;
diff --git a/src/client/client.hpp b/src/client/client.hpp
--- a/src/client/client.hpp
+++ b/src/client/client.hpp
@@ -627,6 +627,15 @@
*/
PromiseT loadEventsFromStorage(immer::map<std::string, EventList> timelineEvents, immer::map<std::string, EventList> relatedEvents) const;
+ /**
+ * Import keys from a key backup file.
+ *
+ * @param fileContent The raw content of the file.
+ * @param password The password to decrypt the file.
+ * @return A Promise that resolves when the keys are imported or when there is an error. Assume the Promise resolves to `r`, if it is successful, `r.dataJson("imported")` contains the number of keys imported. Otherwise, `r` contains the standard error structure.
+ */
+ PromiseT importFromKeyBackupFile(std::string fileContent, std::string password) 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
@@ -513,4 +513,12 @@
std::move(relatedEvents),
});
}
+
+ auto Client::importFromKeyBackupFile(std::string fileContent, std::string password) const -> PromiseT
+ {
+ return m_ctx.dispatch(ImportFromKeyBackupFileAction{
+ std::move(fileContent),
+ std::move(password),
+ });
+ }
}
diff --git a/src/client/clientfwd.hpp b/src/client/clientfwd.hpp
--- a/src/client/clientfwd.hpp
+++ b/src/client/clientfwd.hpp
@@ -71,6 +71,7 @@
struct SetDeviceTrustLevelAction;
struct SetTrustLevelNeededToSendKeysAction;
struct PrepareForSharingRoomKeyAction;
+ struct ImportFromKeyBackupFileAction;
struct GetUserProfileAction;
struct SetAvatarUrlAction;
@@ -139,6 +140,7 @@
SetDeviceTrustLevelAction,
SetTrustLevelNeededToSendKeysAction,
PrepareForSharingRoomKeyAction,
+ ImportFromKeyBackupFileAction,
GetUserProfileAction,
SetAvatarUrlAction,
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
@@ -9,8 +9,9 @@
#include <catch2/catch_all.hpp>
#include <client/actions/encryption.hpp>
#include <client-model.hpp>
-
+#include "key-export.hpp"
#include "client-test-util.hpp"
+#include "action-mock-utils.hpp"
#include "factory.hpp"
using namespace Kazv::Factory;
@@ -391,3 +392,50 @@
{encrypted3.originalJson().get()["content"]["session_id"], {encrypted3.id()}},
});
}
+
+static const std::string password = "test";
+static const std::string backupFile = R"(-----BEGIN MEGOLM SESSION DATA-----
+AV6R43XMe68Ekf7jB4lYHLgAAAAAAAAAAAAAAAAAAAAAAA9CQG628kByLP7LApTtbvhnpgFnUUJ
++tRMkpw4zcGoTOJya9/lawfRWKjd8LZeuHKdNLkEhfIAE16Xmqv+uU8oEASPxjLDOMjsgBKLMRx
+/iwUR7Aoe4wjuwEcdEEOW+T6ffjUz5LmEJcI14qZ1wXUPk1pnNmz+4nX8+a9UxgEpAN7vsmilwz
+P4PXNubhvGsqtZpy44pP6Td0alYgwVfTXqWB1KokMjuQE+2q6/Jb6U/z5D5nv8ArcJL04cD0U6r
+ySsRWI9Jra2OcKFQxgLeVpRAiP6/sRyl9k1n6eiSOfmGkZ+qnvOfZsQh7Wupgh6zRe8LNEtrYZh
+FpSaCE+0U8I5hZJrWNBDFfHg+rtzB4BEk0YwpD3rVcWEsk8kKqHmEulEqIXckd1SbSG7y7H1ADB
+7mjAY7qWetMizPXD+I8MDUnU1TF3Jv3CIZfZY7BHh2WukmiORlpN4H5s/Wwq2oCIk7qXhCHFvaF
+uj+XytIz6TmkEVZfXK9zqUCwCU+VYSGl9GVAezO8CZ6aEJes95yYqRxfADdJG2Vtd0oXwrpR0xV
+1GO+0JJ3xKicVX6U77iMtJbL1Lge32QvbAcv8o6mcaW28xeeYPrccMIRa3vLtuSDDqKC79S9bIP
+2U5F+MHn+5dqMeXcG9K2hS91gsBQMAvX6
+-----END MEGOLM SESSION DATA-----)";
+
+TEST_CASE("import keys", "[client][encryption]")
+{
+ auto u = makeMockSdkUtil(makeClient(
+ withCrypto(makeCrypto())
+ ));
+
+ auto c = u.sdk.client();
+ SECTION("success")
+ {
+ c.importFromKeyBackupFile(backupFile, password)
+ .then([&u](auto stat) {
+ REQUIRE(stat);
+ // the example json in the spec is not a valid key
+ REQUIRE(stat.dataJson("imported") == 0);
+ u.io.stop();
+ });
+
+ u.io.run();
+ }
+
+ SECTION("failure")
+ {
+ c.importFromKeyBackupFile(backupFile, "wrongpass")
+ .then([&u](auto stat) {
+ REQUIRE(!stat);
+ REQUIRE(stat.dataStr("error") == DecryptKeyExportErrorCodes::HMAC_FAILED);
+ u.io.stop();
+ });
+
+ u.io.run();
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Mon, Feb 16, 2:24 AM (12 h, 50 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1108563
Default Alt Text
D280.1771237483.diff (7 KB)

Event Timeline