Add key exporting to account settings
This commit is contained in:
parent
11486ab51d
commit
a87f98fae0
1
TODO.md
1
TODO.md
|
@ -121,7 +121,6 @@
|
||||||
- Edit/delete own devices
|
- Edit/delete own devices
|
||||||
- Request room keys from own other devices
|
- Request room keys from own other devices
|
||||||
- Auto-trust accounts within the same client
|
- Auto-trust accounts within the same client
|
||||||
- Export keys
|
|
||||||
- Uploads & proper http thumbnails
|
- Uploads & proper http thumbnails
|
||||||
- Reduce messages ListView cacheBuffer height once http thumbnails
|
- Reduce messages ListView cacheBuffer height once http thumbnails
|
||||||
downloading is implemented
|
downloading is implemented
|
||||||
|
|
|
@ -338,6 +338,17 @@ class MatrixClient(nio.AsyncClient):
|
||||||
await self.retry_decrypting_events()
|
await self.retry_decrypting_events()
|
||||||
|
|
||||||
|
|
||||||
|
async def export_keys(self, outfile: str, passphrase: str) -> None:
|
||||||
|
path = Path(outfile)
|
||||||
|
path.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
|
||||||
|
# Remove any existing file
|
||||||
|
# (the QML dialog asks the user if he wants to overwrite before this)
|
||||||
|
path.unlink()
|
||||||
|
|
||||||
|
await super().export_keys(outfile, passphrase)
|
||||||
|
|
||||||
|
|
||||||
async def clear_import_error(self) -> None:
|
async def clear_import_error(self) -> None:
|
||||||
self.models[Account][self.user_id].import_error = ("", "", "")
|
self.models[Account][self.user_id].import_error = ("", "", "")
|
||||||
|
|
||||||
|
|
|
@ -28,10 +28,10 @@ Popup {
|
||||||
|
|
||||||
|
|
||||||
function verifyPassword(pass, callback) {
|
function verifyPassword(pass, callback) {
|
||||||
// Implement this function when using this component.
|
// Can be reimplemented when using this component.
|
||||||
// Return true on success, false on invalid password, or
|
// Pass to the callback true on success, false on invalid password, or
|
||||||
// a [error message, translated] array for any other error.
|
// a [error message, translated] array for any other error.
|
||||||
return ["Verification not implemented", false]
|
callback(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,19 @@ HLoader {
|
||||||
property bool importing: false
|
property bool importing: false
|
||||||
|
|
||||||
|
|
||||||
|
function exportKeys(file, passphrase, button=null) {
|
||||||
|
if (button) button.loading = true
|
||||||
|
|
||||||
|
let path = file.toString().replace(/^file:\/\//, "")
|
||||||
|
|
||||||
|
py.callClientCoro(
|
||||||
|
editAccount.userId, "export_keys", [path, passphrase], () => {
|
||||||
|
// null: user is on another page
|
||||||
|
if (encryptionUI !== null && button) button.loading = false
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
function importKeys(file, passphrase, button=null) {
|
function importKeys(file, passphrase, button=null) {
|
||||||
if (button) button.loading = true
|
if (button) button.loading = true
|
||||||
encryptionUI.importing = true
|
encryptionUI.importing = true
|
||||||
|
@ -22,7 +35,7 @@ HLoader {
|
||||||
|
|
||||||
py.callClientCoro(
|
py.callClientCoro(
|
||||||
editAccount.userId, "import_keys", [path, passphrase], () => {
|
editAccount.userId, "import_keys", [path, passphrase], () => {
|
||||||
if (encryptionUI !== null) { // null: user is on another page
|
if (encryptionUI !== null) {
|
||||||
encryptionUI.importing = false
|
encryptionUI.importing = false
|
||||||
if (button) button.loading = false
|
if (button) button.loading = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,27 @@
|
||||||
import QtQuick 2.12
|
import QtQuick 2.12
|
||||||
import QtQuick.Controls 2.12
|
import QtQuick.Controls 2.12
|
||||||
import QtQuick.Layouts 1.12
|
import QtQuick.Layouts 1.12
|
||||||
|
import Qt.labs.platform 1.1
|
||||||
import "../../Base"
|
import "../../Base"
|
||||||
import "../../utils.js" as Utils
|
import "../../utils.js" as Utils
|
||||||
|
|
||||||
HBox {
|
HBox {
|
||||||
|
property var exportButton: null
|
||||||
|
|
||||||
horizontalSpacing: currentSpacing
|
horizontalSpacing: currentSpacing
|
||||||
verticalSpacing: currentSpacing
|
verticalSpacing: currentSpacing
|
||||||
|
|
||||||
buttonModel: [
|
buttonModel: [
|
||||||
{ name: "export", text: qsTr("Export"), iconName: "export-keys",
|
{ name: "export", text: qsTr("Export"), iconName: "export-keys"},
|
||||||
enabled: false },
|
|
||||||
{ name: "import", text: qsTr("Import"), iconName: "import-keys"},
|
{ name: "import", text: qsTr("Import"), iconName: "import-keys"},
|
||||||
]
|
]
|
||||||
|
|
||||||
buttonCallbacks: ({
|
buttonCallbacks: ({
|
||||||
export: button => {},
|
export: button => {
|
||||||
import: button => { fileDialog.dialog.open() },
|
exportButton = button
|
||||||
|
exportFileDialog.dialog.open()
|
||||||
|
},
|
||||||
|
import: button => { importFileDialog.dialog.open() },
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
|
@ -24,29 +29,49 @@ HBox {
|
||||||
wrapMode: Text.Wrap
|
wrapMode: Text.Wrap
|
||||||
text: qsTr(
|
text: qsTr(
|
||||||
"The decryption keys for messages you received in encrypted " +
|
"The decryption keys for messages you received in encrypted " +
|
||||||
"rooms can be exported to a passphrase-protected file.%1" +
|
"rooms can be exported to a passphrase-protected file.\n" +
|
||||||
"You will then be able to import this file in another " +
|
"You can then import this file on another Matrix account or " +
|
||||||
"Matrix client."
|
"client, to be able to decrypt these messages again."
|
||||||
).arg(pageLoader.isWide ? "\n" :"\n\n")
|
)
|
||||||
|
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
}
|
}
|
||||||
|
|
||||||
HFileDialogOpener {
|
HFileDialogOpener {
|
||||||
id: fileDialog
|
id: exportFileDialog
|
||||||
fill: false
|
fill: false
|
||||||
dialog.title: qsTr("Select a decryption key file to import")
|
dialog.title: qsTr("Save decryption keys file as...")
|
||||||
|
dialog.fileMode: FileDialog.SaveFile
|
||||||
|
onFileChanged: {
|
||||||
|
exportPasswordPopup.file = file
|
||||||
|
exportPasswordPopup.open()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HFileDialogOpener {
|
||||||
|
id: importFileDialog
|
||||||
|
fill: false
|
||||||
|
dialog.title: qsTr("Select a decryption keys file to import")
|
||||||
onFileChanged: {
|
onFileChanged: {
|
||||||
importPasswordPopup.file = file
|
importPasswordPopup.file = file
|
||||||
importPasswordPopup.open()
|
importPasswordPopup.open()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
HPasswordPopup {
|
||||||
|
property url file: ""
|
||||||
|
|
||||||
|
id: exportPasswordPopup
|
||||||
|
label.text: qsTr("Please enter a passphrase to protect this file:")
|
||||||
|
onAcceptedPasswordChanged:
|
||||||
|
encryptionUI.exportKeys(file, acceptedPassword, exportButton)
|
||||||
|
}
|
||||||
|
|
||||||
HPasswordPopup {
|
HPasswordPopup {
|
||||||
property url file: ""
|
property url file: ""
|
||||||
|
|
||||||
function verifyPassword(pass, callback) {
|
function verifyPassword(pass, callback) {
|
||||||
return py.callCoro(
|
py.callCoro(
|
||||||
"check_exported_keys_passphrase",
|
"check_exported_keys_passphrase",
|
||||||
[file.toString().replace(/^file:\/\//, ""), pass],
|
[file.toString().replace(/^file:\/\//, ""), pass],
|
||||||
callback
|
callback
|
||||||
|
|
Loading…
Reference in New Issue
Block a user