Page MenuHomePhorge

D282.1771353698.diff
No OneTemporary

Size
9 KB
Referenced Files
None
Subscribers
None

D282.1771353698.diff

diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -216,6 +216,7 @@
SettingsPage.qml
settings/ProfileSettings.qml
settings/CacheSettings.qml
+ settings/SecuritySettings.qml
room-settings/RoomSettingsPage.qml
room-settings/RoomTagHandler.qml
diff --git a/src/contents/ui/SettingsPage.qml b/src/contents/ui/SettingsPage.qml
--- a/src/contents/ui/SettingsPage.qml
+++ b/src/contents/ui/SettingsPage.qml
@@ -34,6 +34,9 @@
id: cacheSettings
Layout.fillWidth: true
}
+ Settings.SecuritySettings {
+ Layout.fillWidth: true
+ }
}
function saveRecursively() {
diff --git a/src/contents/ui/settings/SecuritySettings.qml b/src/contents/ui/settings/SecuritySettings.qml
new file mode 100644
--- /dev/null
+++ b/src/contents/ui/settings/SecuritySettings.qml
@@ -0,0 +1,61 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtQuick.Dialogs
+import org.kde.kirigami as Kirigami
+import '..' as Kazv
+
+ColumnLayout {
+ id: securitySettings
+ property string fileToImport: ''
+
+ Button {
+ objectName: 'importKeysButton'
+ Layout.fillWidth: true
+ text: l10n.get('settings-security-import-keys-action')
+ onClicked: fileDialog.open()
+ }
+
+ FileDialog {
+ id: fileDialog
+ objectName: 'fileDialog'
+ onAccepted: {
+ securitySettings.fileToImport = selectedFile;
+ passwordInputPopup.open();
+ }
+ }
+
+ property var passwordInputOverlay: Kazv.ConfirmationOverlay {
+ id: passwordInputPopup
+ parent: Overlay.overlay
+ title: l10n.get('settings-security-import-keys-password-input-title')
+ message: l10n.get('settings-security-import-keys-password-input-label')
+ confirmActionText: l10n.get('settings-security-import-keys-confirm-action')
+ cancelActionText: l10n.get('settings-security-import-keys-cancel-action')
+ Kirigami.PasswordField {
+ id: passwordInput
+ objectName: 'passwordInput'
+ Layout.fillWidth: true
+ }
+ onAccepted: {
+ securitySettings.importKeys.call();
+ }
+ }
+
+ property var importKeys: Kazv.AsyncHandler {
+ trigger: () => matrixSdk.importFromKeyBackupFile(securitySettings.fileToImport, passwordInput.text)
+ onResolved: (success, data) => {
+ if (success) {
+ showPassiveNotification(l10n.get('settings-security-import-keys-success-notification', { imported: data.imported }));
+ } else {
+ showPassiveNotification(l10n.get('settings-security-import-keys-failure-notification', { errorMsg: data.error, errorCode: data.errorCode }));
+ }
+ }
+ }
+}
diff --git a/src/l10n/cmn-Hans/100-ui.ftl b/src/l10n/cmn-Hans/100-ui.ftl
--- a/src/l10n/cmn-Hans/100-ui.ftl
+++ b/src/l10n/cmn-Hans/100-ui.ftl
@@ -337,6 +337,13 @@
settings-profile-display-name = 显示名:
settings-profile-save-failed-prompt = 无法保存用户资料。错误码:{ $errorCode }。错误讯息:{ $errorMsg }。
settings-cache-directory = 缓存目录:
+settings-security-import-keys-action = 从备份文件导入密钥...
+settings-security-import-keys-password-input-title = 输入密码
+settings-security-import-keys-password-input-label = 当你创建备份时,提示了你要设置一个用来加密备份文件的密码。输入你当时设置的那个密码:
+settings-security-import-keys-confirm-action = 导入
+settings-security-import-keys-cancel-action = 不导入
+settings-security-import-keys-success-notification = 导入了 { $imported } 个密钥。
+settings-security-import-keys-failure-notification = 无法加载密钥备份文件。错误码:{ $errorCode }。错误讯息:{ $errorMsg }。
typing-indicator = { $typingUser } { $otherNum ->
[0] 正在输入...
@@ -421,4 +428,4 @@
confirm-deletion-popup-confirm-action = 删除
confirm-deletion-popup-cancel-action = 取消
-get-room-id-by-alias-failed-prompt = 无法通过房间别名获取房间 id。错误码:{ $errorCode }。错误讯息:{ $errorMsg }。
\ No newline at end of file
+get-room-id-by-alias-failed-prompt = 无法通过房间别名获取房间 id。错误码:{ $errorCode }。错误讯息:{ $errorMsg }。
diff --git a/src/l10n/en/100-ui.ftl b/src/l10n/en/100-ui.ftl
--- a/src/l10n/en/100-ui.ftl
+++ b/src/l10n/en/100-ui.ftl
@@ -359,6 +359,13 @@
settings-profile-display-name = Display name:
settings-profile-save-failed-prompt = Unable to save profile. Error code: { $errorCode }. Error message: { $errorMsg }.
settings-cache-directory = Cache directory:
+settings-security-import-keys-action = Import keys from a backup file...
+settings-security-import-keys-password-input-title = Enter password
+settings-security-import-keys-password-input-label = When you created the backup, you were prompted to set a password to encrypt the backup file. Enter the password you set at that time:
+settings-security-import-keys-confirm-action = Import
+settings-security-import-keys-cancel-action = Do not import
+settings-security-import-keys-success-notification = Imported { $imported } keys.
+settings-security-import-keys-failure-notification = Unable to load key backup file. Error code: { $errorCode }. Error message: { $errorMsg }.
typing-indicator = { $typingUser } { $otherNum ->
[0] is typing...
@@ -443,4 +450,4 @@
confirm-deletion-popup-confirm-action = Delete
confirm-deletion-popup-cancel-action = Cancel
-get-room-id-by-alias-failed-prompt = Unable to get room id by alias. Error code: { $errorCode }. Error message: { $errorMsg }.
\ No newline at end of file
+get-room-id-by-alias-failed-prompt = Unable to get room id by alias. Error code: { $errorCode }. Error message: { $errorMsg }.
diff --git a/src/matrix-sdk.hpp b/src/matrix-sdk.hpp
--- a/src/matrix-sdk.hpp
+++ b/src/matrix-sdk.hpp
@@ -331,6 +331,18 @@
*/
MatrixPromise *backfillRoomFromEvent(const QString &roomId, const QString &eventId);
+ /**
+ * Import from key backup file.
+ *
+ * @param fileUrl The url of the key backup file. Will be passed to
+ * QUrl::toLocalFile(), and must be a local file.
+ * @param password The password to decrypt the key backup file.
+ * @return A MatrixPromise that resolves when the keys are imported.
+ * If successful, `data["imported"]` contains the number of imported keys.
+ * If unsuccessful, `data` contains a standard error structure.
+ */
+ MatrixPromise *importFromKeyBackupFile(QUrl fileUrl, QString password);
+
private:
MatrixPromise *sendAccountDataImpl(Kazv::Event event);
diff --git a/src/matrix-sdk.cpp b/src/matrix-sdk.cpp
--- a/src/matrix-sdk.cpp
+++ b/src/matrix-sdk.cpp
@@ -1099,6 +1099,30 @@
);
}
+MatrixPromise *MatrixSdk::importFromKeyBackupFile(QUrl fileUrl, QString password)
+{
+ if (!fileUrl.isLocalFile()) {
+ return new MatrixPromise(m_d->sdk.context().createResolvedPromise({
+ /* succ = */ false,
+ json{{"error", "Not a local file"}, {"errorCode", "NOT_LOCAL_FILE"}},
+ }));
+ }
+ auto filename = fileUrl.toLocalFile();
+ auto f = QFile(filename);
+ if (!f.open(QFile::ReadOnly)) {
+ return new MatrixPromise(m_d->sdk.context().createResolvedPromise({
+ /* succ = */ false,
+ json{{"error", "File open failed"}, {"errorCode", "FILE_OPEN_FAILED"}},
+ }));
+ }
+ auto ba = f.readAll();
+ auto content = std::string(ba.begin(), ba.end());
+ auto passwordStd = std::move(password).toStdString();
+ return new MatrixPromise(m_d->clientOnSecondaryRoot.importFromKeyBackupFile(
+ std::move(content), std::move(passwordStd)
+ ));
+}
+
void MatrixSdk::setUserDataDir(const std::string &userDataDir)
{
m_d->userDataDir = userDataDir;
diff --git a/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml b/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
--- a/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
+++ b/src/tests/quick-tests/test-helpers/MatrixSdkMock.qml
@@ -33,6 +33,10 @@
property var getRoomIdByAlias: mockHelper.promise([
'roomAlias'
])
+ property var importFromKeyBackupFile: mockHelper.promise([
+ 'fileUrl',
+ 'password',
+ ])
property var sessions: []
diff --git a/src/tests/quick-tests/tst_SecuritySettings.qml b/src/tests/quick-tests/tst_SecuritySettings.qml
new file mode 100644
--- /dev/null
+++ b/src/tests/quick-tests/tst_SecuritySettings.qml
@@ -0,0 +1,49 @@
+/*
+ * This file is part of kazv.
+ * SPDX-FileCopyrightText: 2026 tusooa <tusooa@kazv.moe>
+ * SPDX-License-Identifier: AGPL-3.0-or-later
+ */
+
+import QtQuick
+import QtQuick.Layouts
+import QtQuick.Controls
+import QtTest
+import '../../contents/ui' as Kazv
+import '../../contents/ui/settings' as KazvSettings
+import moe.kazv.mxc.kazv 0.0 as MK
+import 'test-helpers.js' as JsHelpers
+import 'test-helpers' as QmlHelpers
+
+QmlHelpers.TestItem {
+ id: item
+
+ KazvSettings.SecuritySettings {
+ id: securitySettings
+ anchors.fill: parent
+ }
+
+ TestCase {
+ id: securitySettingsTest
+ name: 'SecuritySettingsTest'
+ when: windowShown
+
+ function init() {
+ item.mockHelper.clearAll();
+ }
+
+ function test_importKeys() {
+ const button = findChild(securitySettings, 'importKeysButton');
+ mouseClick(button);
+ const dialog = findChild(securitySettings, 'fileDialog');
+ dialog.accept();
+ securitySettings.fileToImport = 'file:///tmp/test';
+ const input = findChild(securitySettings.passwordInputOverlay, 'passwordInput');
+ input.text = 'test';
+ securitySettings.passwordInputOverlay.accepted();
+ securitySettings.passwordInputOverlay.close();
+ compare(item.matrixSdk.importFromKeyBackupFile.calledTimes(), 1);
+ compare(item.matrixSdk.importFromKeyBackupFile.lastArgs().fileUrl, 'file:///tmp/test');
+ compare(item.matrixSdk.importFromKeyBackupFile.lastArgs().password, 'test');
+ }
+ }
+}

File Metadata

Mime Type
text/plain
Expires
Tue, Feb 17, 10:41 AM (19 h, 47 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1112765
Default Alt Text
D282.1771353698.diff (9 KB)

Event Timeline