forked from GitHub-Mirror/riotX-android
Crypto: export room keys
This commit is contained in:
parent
8c8a4dcbd1
commit
5f0d1d9536
@ -1,30 +0,0 @@
|
|||||||
/*
|
|
||||||
*
|
|
||||||
* * Copyright 2019 New Vector Ltd
|
|
||||||
* *
|
|
||||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* * you may not use this file except in compliance with the License.
|
|
||||||
* * You may obtain a copy of the License at
|
|
||||||
* *
|
|
||||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* *
|
|
||||||
* * Unless required by applicable law or agreed to in writing, software
|
|
||||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* * See the License for the specific language governing permissions and
|
|
||||||
* * limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package im.vector.matrix.android.api.util
|
|
||||||
|
|
||||||
import arrow.core.*
|
|
||||||
|
|
||||||
inline fun <A> TryOf<A>.onError(f: (Throwable) -> Unit): Try<A> = fix()
|
|
||||||
.fold(
|
|
||||||
{
|
|
||||||
f(it)
|
|
||||||
Failure(it)
|
|
||||||
},
|
|
||||||
{ Success(it) }
|
|
||||||
)
|
|
@ -64,6 +64,7 @@ import im.vector.matrix.android.internal.crypto.verification.DefaultSasVerificat
|
|||||||
import im.vector.matrix.android.internal.database.model.EventEntity
|
import im.vector.matrix.android.internal.database.model.EventEntity
|
||||||
import im.vector.matrix.android.internal.database.query.where
|
import im.vector.matrix.android.internal.database.query.where
|
||||||
import im.vector.matrix.android.internal.di.MoshiProvider
|
import im.vector.matrix.android.internal.di.MoshiProvider
|
||||||
|
import im.vector.matrix.android.internal.extensions.foldToCallback
|
||||||
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
|
import im.vector.matrix.android.internal.session.cache.ClearCacheTask
|
||||||
import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask
|
import im.vector.matrix.android.internal.session.room.membership.LoadRoomMembersTask
|
||||||
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
import im.vector.matrix.android.internal.session.room.membership.RoomMembers
|
||||||
@ -560,10 +561,10 @@ internal class CryptoManager(
|
|||||||
} else {
|
} else {
|
||||||
val algorithm = getEncryptionAlgorithm(roomId)
|
val algorithm = getEncryptionAlgorithm(roomId)
|
||||||
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
|
val reason = String.format(MXCryptoError.UNABLE_TO_ENCRYPT_REASON,
|
||||||
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
algorithm ?: MXCryptoError.NO_MORE_ALGORITHM_REASON)
|
||||||
Timber.e("## encryptEventContent() : $reason")
|
Timber.e("## encryptEventContent() : $reason")
|
||||||
callback.onFailure(Failure.CryptoError(MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE,
|
callback.onFailure(Failure.CryptoError(MXCryptoError(MXCryptoError.UNABLE_TO_ENCRYPT_ERROR_CODE,
|
||||||
MXCryptoError.UNABLE_TO_ENCRYPT, reason)))
|
MXCryptoError.UNABLE_TO_ENCRYPT, reason)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -700,7 +701,7 @@ internal class CryptoManager(
|
|||||||
monarchy.doWithRealm { realm ->
|
monarchy.doWithRealm { realm ->
|
||||||
// Check whether the event content must be encrypted for the invited members.
|
// Check whether the event content must be encrypted for the invited members.
|
||||||
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser()
|
val encryptForInvitedMembers = isEncryptionEnabledForInvitedUser()
|
||||||
&& shouldEncryptForInvitedMembers(roomId)
|
&& shouldEncryptForInvitedMembers(roomId)
|
||||||
|
|
||||||
userIds = if (encryptForInvitedMembers) {
|
userIds = if (encryptForInvitedMembers) {
|
||||||
RoomMembers(realm, roomId).getActiveRoomMemberIds()
|
RoomMembers(realm, roomId).getActiveRoomMemberIds()
|
||||||
@ -787,35 +788,32 @@ internal class CryptoManager(
|
|||||||
* @param anIterationCount the encryption iteration count (0 means no encryption)
|
* @param anIterationCount the encryption iteration count (0 means no encryption)
|
||||||
* @param callback the exported keys
|
* @param callback the exported keys
|
||||||
*/
|
*/
|
||||||
fun exportRoomKeys(password: String, anIterationCount: Int, callback: MatrixCallback<ByteArray>) {
|
private fun exportRoomKeys(password: String, anIterationCount: Int, callback: MatrixCallback<ByteArray>) {
|
||||||
val iterationCount = Math.max(0, anIterationCount)
|
GlobalScope.launch(coroutineDispatchers.main) {
|
||||||
|
withContext(coroutineDispatchers.crypto) {
|
||||||
|
Try {
|
||||||
|
val iterationCount = Math.max(0, anIterationCount)
|
||||||
|
|
||||||
val exportedSessions = ArrayList<MegolmSessionData>()
|
val exportedSessions = ArrayList<MegolmSessionData>()
|
||||||
|
|
||||||
val inboundGroupSessions = cryptoStore.getInboundGroupSessions()
|
val inboundGroupSessions = cryptoStore.getInboundGroupSessions()
|
||||||
|
|
||||||
for (session in inboundGroupSessions) {
|
for (session in inboundGroupSessions) {
|
||||||
val megolmSessionData = session.exportKeys()
|
val megolmSessionData = session.exportKeys()
|
||||||
|
|
||||||
if (null != megolmSessionData) {
|
if (null != megolmSessionData) {
|
||||||
exportedSessions.add(megolmSessionData)
|
exportedSessions.add(megolmSessionData)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val adapter = MoshiProvider.providesMoshi()
|
||||||
|
.adapter(List::class.java)
|
||||||
|
|
||||||
|
MXMegolmExportEncryption
|
||||||
|
.encryptMegolmKeyFile(adapter.toJson(exportedSessions), password, iterationCount)
|
||||||
|
}
|
||||||
|
}.foldToCallback(callback)
|
||||||
}
|
}
|
||||||
|
|
||||||
val encryptedRoomKeys: ByteArray
|
|
||||||
|
|
||||||
try {
|
|
||||||
val adapter = MoshiProvider.providesMoshi()
|
|
||||||
.adapter(List::class.java)
|
|
||||||
|
|
||||||
encryptedRoomKeys = MXMegolmExportEncryption
|
|
||||||
.encryptMegolmKeyFile(adapter.toJson(exportedSessions), password, iterationCount)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
callback.onFailure(e)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
callback.onSuccess(encryptedRoomKeys)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -830,6 +828,7 @@ internal class CryptoManager(
|
|||||||
password: String,
|
password: String,
|
||||||
progressListener: ProgressListener?,
|
progressListener: ProgressListener?,
|
||||||
callback: MatrixCallback<ImportRoomKeysResult>) {
|
callback: MatrixCallback<ImportRoomKeysResult>) {
|
||||||
|
// TODO Use coroutines
|
||||||
Timber.v("## importRoomKeys starts")
|
Timber.v("## importRoomKeys starts")
|
||||||
|
|
||||||
val t0 = System.currentTimeMillis()
|
val t0 = System.currentTimeMillis()
|
||||||
@ -898,7 +897,7 @@ internal class CryptoManager(
|
|||||||
// trigger an an unknown devices exception
|
// trigger an an unknown devices exception
|
||||||
callback.onFailure(
|
callback.onFailure(
|
||||||
Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
|
Failure.CryptoError(MXCryptoError(MXCryptoError.UNKNOWN_DEVICES_CODE,
|
||||||
MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
|
MXCryptoError.UNABLE_TO_ENCRYPT, MXCryptoError.UNKNOWN_DEVICES_REASON, unknownDevices)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -21,7 +21,7 @@ import android.text.TextUtils
|
|||||||
import arrow.core.Try
|
import arrow.core.Try
|
||||||
import im.vector.matrix.android.api.MatrixPatterns
|
import im.vector.matrix.android.api.MatrixPatterns
|
||||||
import im.vector.matrix.android.api.auth.data.Credentials
|
import im.vector.matrix.android.api.auth.data.Credentials
|
||||||
import im.vector.matrix.android.api.util.onError
|
import im.vector.matrix.android.internal.extensions.onError
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
import im.vector.matrix.android.internal.crypto.model.MXDeviceInfo
|
||||||
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
import im.vector.matrix.android.internal.crypto.model.MXUsersDevicesMap
|
||||||
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
import im.vector.matrix.android.internal.crypto.store.IMXCryptoStore
|
||||||
|
@ -0,0 +1,33 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.matrix.android.internal.extensions
|
||||||
|
|
||||||
|
import arrow.core.*
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
|
||||||
|
inline fun <A> TryOf<A>.onError(f: (Throwable) -> Unit): Try<A> = fix()
|
||||||
|
.fold(
|
||||||
|
{
|
||||||
|
f(it)
|
||||||
|
Failure(it)
|
||||||
|
},
|
||||||
|
{ Success(it) }
|
||||||
|
)
|
||||||
|
|
||||||
|
fun <A> Try<A>.foldToCallback(callback: MatrixCallback<A>): Unit = fold(
|
||||||
|
{ callback.onFailure(it) },
|
||||||
|
{ callback.onSuccess(it) })
|
@ -19,34 +19,30 @@ package im.vector.riotredesign.core.dialogs
|
|||||||
import android.app.Activity
|
import android.app.Activity
|
||||||
import android.text.Editable
|
import android.text.Editable
|
||||||
import android.text.TextUtils
|
import android.text.TextUtils
|
||||||
import android.text.TextWatcher
|
|
||||||
import android.widget.Button
|
import android.widget.Button
|
||||||
|
import android.widget.ImageView
|
||||||
import androidx.appcompat.app.AlertDialog
|
import androidx.appcompat.app.AlertDialog
|
||||||
import com.google.android.material.textfield.TextInputEditText
|
import com.google.android.material.textfield.TextInputEditText
|
||||||
import com.google.android.material.textfield.TextInputLayout
|
import com.google.android.material.textfield.TextInputLayout
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
|
import im.vector.riotredesign.core.extensions.showPassword
|
||||||
|
import im.vector.riotredesign.core.platform.SimpleTextWatcher
|
||||||
|
|
||||||
class ExportKeysDialog {
|
class ExportKeysDialog {
|
||||||
|
|
||||||
|
var passwordVisible = false
|
||||||
|
|
||||||
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
fun show(activity: Activity, exportKeyDialogListener: ExportKeyDialogListener) {
|
||||||
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
val dialogLayout = activity.layoutInflater.inflate(R.layout.dialog_export_e2e_keys, null)
|
||||||
val builder = AlertDialog.Builder(activity)
|
val builder = AlertDialog.Builder(activity)
|
||||||
.setTitle(R.string.encryption_export_room_keys)
|
.setTitle(R.string.encryption_export_room_keys)
|
||||||
.setView(dialogLayout)
|
.setView(dialogLayout)
|
||||||
|
|
||||||
val passPhrase1EditText = dialogLayout.findViewById<TextInputEditText>(R.id.dialog_e2e_keys_passphrase_edit_text)
|
val passPhrase1EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEt)
|
||||||
val passPhrase2EditText = dialogLayout.findViewById<TextInputEditText>(R.id.dialog_e2e_keys_confirm_passphrase_edit_text)
|
val passPhrase2EditText = dialogLayout.findViewById<TextInputEditText>(R.id.exportDialogEtConfirm)
|
||||||
val passPhrase2Til = dialogLayout.findViewById<TextInputLayout>(R.id.dialog_e2e_keys_confirm_passphrase_til)
|
val passPhrase2Til = dialogLayout.findViewById<TextInputLayout>(R.id.exportDialogTilConfirm)
|
||||||
val exportButton = dialogLayout.findViewById<Button>(R.id.dialog_e2e_keys_export_button)
|
val exportButton = dialogLayout.findViewById<Button>(R.id.exportDialogSubmit)
|
||||||
val textWatcher = object : TextWatcher {
|
val textWatcher = object : SimpleTextWatcher() {
|
||||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun afterTextChanged(s: Editable) {
|
override fun afterTextChanged(s: Editable) {
|
||||||
when {
|
when {
|
||||||
TextUtils.isEmpty(passPhrase1EditText.text) -> {
|
TextUtils.isEmpty(passPhrase1EditText.text) -> {
|
||||||
@ -68,6 +64,14 @@ class ExportKeysDialog {
|
|||||||
passPhrase1EditText.addTextChangedListener(textWatcher)
|
passPhrase1EditText.addTextChangedListener(textWatcher)
|
||||||
passPhrase2EditText.addTextChangedListener(textWatcher)
|
passPhrase2EditText.addTextChangedListener(textWatcher)
|
||||||
|
|
||||||
|
val showPassword = dialogLayout.findViewById<ImageView>(R.id.exportDialogShowPassword)
|
||||||
|
showPassword.setOnClickListener {
|
||||||
|
passwordVisible = !passwordVisible
|
||||||
|
passPhrase1EditText.showPassword(passwordVisible)
|
||||||
|
passPhrase2EditText.showPassword(passwordVisible)
|
||||||
|
showPassword.setImageResource(if (passwordVisible) R.drawable.ic_eye_closed_black else R.drawable.ic_eye_black)
|
||||||
|
}
|
||||||
|
|
||||||
val exportDialog = builder.show()
|
val exportDialog = builder.show()
|
||||||
|
|
||||||
exportButton.setOnClickListener {
|
exportButton.setOnClickListener {
|
||||||
|
@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2019 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.riotredesign.features.crypto.keys
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.os.Environment
|
||||||
|
import androidx.annotation.WorkerThread
|
||||||
|
import arrow.core.Try
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
|
import im.vector.matrix.android.api.session.Session
|
||||||
|
import im.vector.matrix.android.internal.extensions.foldToCallback
|
||||||
|
import im.vector.riotredesign.core.files.addEntryToDownloadManager
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import okio.Okio
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class KeysExporter(private val session: Session) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export keys and return the file path with the callback
|
||||||
|
*/
|
||||||
|
fun export(context: Context, password: String, callback: MatrixCallback<String>) {
|
||||||
|
session.exportRoomKeys(password, object : MatrixCallback<ByteArray> {
|
||||||
|
|
||||||
|
override fun onSuccess(data: ByteArray) {
|
||||||
|
GlobalScope.launch(Dispatchers.Main) {
|
||||||
|
withContext(Dispatchers.IO) {
|
||||||
|
copyToFile(context, data)
|
||||||
|
}
|
||||||
|
.foldToCallback(callback)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onFailure(failure: Throwable) {
|
||||||
|
callback.onFailure(failure)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
@WorkerThread
|
||||||
|
private fun copyToFile(context: Context, data: ByteArray): Try<String> {
|
||||||
|
return Try {
|
||||||
|
val parentDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS)
|
||||||
|
val file = File(parentDir, "riotx-keys-" + System.currentTimeMillis() + ".txt")
|
||||||
|
|
||||||
|
val sink = Okio.sink(file)
|
||||||
|
|
||||||
|
val bufferedSink = Okio.buffer(sink)
|
||||||
|
|
||||||
|
bufferedSink.write(data)
|
||||||
|
|
||||||
|
bufferedSink.close()
|
||||||
|
sink.close()
|
||||||
|
|
||||||
|
addEntryToDownloadManager(context, file, "text/plain")
|
||||||
|
|
||||||
|
file.absolutePath
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -23,10 +23,13 @@ import androidx.fragment.app.FragmentManager
|
|||||||
import androidx.lifecycle.Observer
|
import androidx.lifecycle.Observer
|
||||||
import androidx.lifecycle.ViewModelProviders
|
import androidx.lifecycle.ViewModelProviders
|
||||||
import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel
|
import im.vector.fragments.keysbackup.setup.KeysBackupSetupSharedViewModel
|
||||||
|
import im.vector.matrix.android.api.MatrixCallback
|
||||||
import im.vector.riotredesign.R
|
import im.vector.riotredesign.R
|
||||||
import im.vector.riotredesign.core.dialogs.ExportKeysDialog
|
import im.vector.riotredesign.core.dialogs.ExportKeysDialog
|
||||||
import im.vector.riotredesign.core.extensions.observeEvent
|
import im.vector.riotredesign.core.extensions.observeEvent
|
||||||
import im.vector.riotredesign.core.platform.SimpleFragmentActivity
|
import im.vector.riotredesign.core.platform.SimpleFragmentActivity
|
||||||
|
import im.vector.riotredesign.core.utils.toast
|
||||||
|
import im.vector.riotredesign.features.crypto.keys.KeysExporter
|
||||||
|
|
||||||
class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
||||||
|
|
||||||
@ -118,49 +121,38 @@ class KeysBackupSetupActivity : SimpleFragmentActivity() {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exportKeysManually() {
|
private fun exportKeysManually() {
|
||||||
ExportKeysDialog().show(this, object : ExportKeysDialog.ExportKeyDialogListener {
|
ExportKeysDialog().show(this, object : ExportKeysDialog.ExportKeyDialogListener {
|
||||||
override fun onPassphrase(passphrase: String) {
|
override fun onPassphrase(passphrase: String) {
|
||||||
notImplemented()
|
|
||||||
/*
|
|
||||||
showWaitingView()
|
showWaitingView()
|
||||||
|
|
||||||
CommonActivityUtils.exportKeys(session, passphrase, object : SimpleApiCallback<String>(this@KeysBackupSetupActivity) {
|
KeysExporter(session)
|
||||||
override fun onSuccess(filename: String) {
|
.export(this@KeysBackupSetupActivity,
|
||||||
hideWaitingView()
|
passphrase,
|
||||||
|
object : MatrixCallback<String> {
|
||||||
|
|
||||||
AlertDialog.Builder(this@KeysBackupSetupActivity)
|
override fun onSuccess(data: String) {
|
||||||
.setMessage(getString(R.string.encryption_export_saved_as, filename))
|
hideWaitingView()
|
||||||
.setCancelable(false)
|
|
||||||
.setPositiveButton(R.string.ok) { dialog, which ->
|
|
||||||
val resultIntent = Intent()
|
|
||||||
resultIntent.putExtra(MANUAL_EXPORT, true)
|
|
||||||
setResult(RESULT_OK, resultIntent)
|
|
||||||
finish()
|
|
||||||
}
|
|
||||||
.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNetworkError(e: Exception) {
|
AlertDialog.Builder(this@KeysBackupSetupActivity)
|
||||||
super.onNetworkError(e)
|
.setMessage(getString(R.string.encryption_export_saved_as, data))
|
||||||
hideWaitingView()
|
.setCancelable(false)
|
||||||
}
|
.setPositiveButton(R.string.ok) { dialog, which ->
|
||||||
|
val resultIntent = Intent()
|
||||||
|
resultIntent.putExtra(MANUAL_EXPORT, true)
|
||||||
|
setResult(RESULT_OK, resultIntent)
|
||||||
|
finish()
|
||||||
|
}
|
||||||
|
.show()
|
||||||
|
}
|
||||||
|
|
||||||
override fun onMatrixError(e: MatrixError) {
|
override fun onFailure(failure: Throwable) {
|
||||||
super.onMatrixError(e)
|
toast(failure.localizedMessage)
|
||||||
hideWaitingView()
|
hideWaitingView()
|
||||||
}
|
}
|
||||||
|
})
|
||||||
override fun onUnexpectedError(e: Exception) {
|
|
||||||
super.onUnexpectedError(e)
|
|
||||||
hideWaitingView()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -56,6 +56,7 @@ import im.vector.riotredesign.core.dialogs.ExportKeysDialog
|
|||||||
import im.vector.riotredesign.core.extensions.showPassword
|
import im.vector.riotredesign.core.extensions.showPassword
|
||||||
import im.vector.riotredesign.core.extensions.withArgs
|
import im.vector.riotredesign.core.extensions.withArgs
|
||||||
import im.vector.riotredesign.core.platform.SimpleTextWatcher
|
import im.vector.riotredesign.core.platform.SimpleTextWatcher
|
||||||
|
import im.vector.riotredesign.core.platform.VectorBaseActivity
|
||||||
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
import im.vector.riotredesign.core.platform.VectorPreferenceFragment
|
||||||
import im.vector.riotredesign.core.preference.BingRule
|
import im.vector.riotredesign.core.preference.BingRule
|
||||||
import im.vector.riotredesign.core.preference.ProgressBarPreference
|
import im.vector.riotredesign.core.preference.ProgressBarPreference
|
||||||
@ -64,6 +65,7 @@ import im.vector.riotredesign.core.preference.VectorPreference
|
|||||||
import im.vector.riotredesign.core.utils.*
|
import im.vector.riotredesign.core.utils.*
|
||||||
import im.vector.riotredesign.features.MainActivity
|
import im.vector.riotredesign.features.MainActivity
|
||||||
import im.vector.riotredesign.features.configuration.VectorConfiguration
|
import im.vector.riotredesign.features.configuration.VectorConfiguration
|
||||||
|
import im.vector.riotredesign.features.crypto.keys.KeysExporter
|
||||||
import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
import im.vector.riotredesign.features.crypto.keysbackup.settings.KeysBackupManageActivity
|
||||||
import im.vector.riotredesign.features.themes.ThemeUtils
|
import im.vector.riotredesign.features.themes.ThemeUtils
|
||||||
import org.koin.android.ext.android.inject
|
import org.koin.android.ext.android.inject
|
||||||
@ -885,9 +887,7 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this)
|
PreferenceManager.getDefaultSharedPreferences(context).unregisterOnSharedPreferenceChangeListener(this)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO Test
|
|
||||||
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
|
||||||
/* TODO
|
|
||||||
if (allGranted(grantResults)) {
|
if (allGranted(grantResults)) {
|
||||||
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
|
if (requestCode == PERMISSION_REQUEST_CODE_LAUNCH_CAMERA) {
|
||||||
changeAvatar()
|
changeAvatar()
|
||||||
@ -895,7 +895,6 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
exportKeys()
|
exportKeys()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//==============================================================================================================
|
//==============================================================================================================
|
||||||
@ -2594,38 +2593,27 @@ class VectorSettingsPreferencesFragment : VectorPreferenceFragment(), SharedPref
|
|||||||
activity?.let { activity ->
|
activity?.let { activity ->
|
||||||
ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener {
|
ExportKeysDialog().show(activity, object : ExportKeysDialog.ExportKeyDialogListener {
|
||||||
override fun onPassphrase(passphrase: String) {
|
override fun onPassphrase(passphrase: String) {
|
||||||
notImplemented()
|
|
||||||
/*
|
|
||||||
|
|
||||||
displayLoadingView()
|
displayLoadingView()
|
||||||
|
|
||||||
CommonActivityUtils.exportKeys(session, passphrase, object : SimpleApiCallback<String>(activity) {
|
KeysExporter(mSession)
|
||||||
override fun onSuccess(filename: String) {
|
.export(requireContext(),
|
||||||
hideLoadingView()
|
passphrase,
|
||||||
|
object : MatrixCallback<String> {
|
||||||
|
override fun onSuccess(data: String) {
|
||||||
|
hideLoadingView()
|
||||||
|
|
||||||
AlertDialog.Builder(activity)
|
AlertDialog.Builder(activity)
|
||||||
.setMessage(getString(R.string.encryption_export_saved_as, filename))
|
.setMessage(getString(R.string.encryption_export_saved_as, data))
|
||||||
.setCancelable(false)
|
.setCancelable(false)
|
||||||
.setPositiveButton(R.string.ok, null)
|
.setPositiveButton(R.string.ok, null)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onNetworkError(e: Exception) {
|
override fun onFailure(failure: Throwable) {
|
||||||
super.onNetworkError(e)
|
onCommonDone(failure.localizedMessage)
|
||||||
hideLoadingView()
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMatrixError(e: MatrixError) {
|
})
|
||||||
super.onMatrixError(e)
|
|
||||||
hideLoadingView()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUnexpectedError(e: Exception) {
|
|
||||||
super.onUnexpectedError(e)
|
|
||||||
hideLoadingView()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
android:id="@+id/layout_root"
|
android:id="@+id/layout_root"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="match_parent"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:orientation="vertical"
|
||||||
android:paddingStart="?dialogPreferredPadding"
|
android:paddingStart="?dialogPreferredPadding"
|
||||||
android:paddingLeft="?dialogPreferredPadding"
|
android:paddingLeft="?dialogPreferredPadding"
|
||||||
@ -13,21 +13,41 @@
|
|||||||
android:paddingBottom="12dp">
|
android:paddingBottom="12dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
|
android:id="@+id/exportDialogText"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:text="@string/encryption_export_notice"
|
android:text="@string/encryption_export_notice"
|
||||||
android:textColor="?riotx_text_primary"
|
android:textColor="?riotx_text_primary"
|
||||||
android:textSize="16sp" />
|
android:textSize="16sp"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/exportDialogShowPassword"
|
||||||
|
android:layout_width="@dimen/layout_touch_size"
|
||||||
|
android:layout_height="@dimen/layout_touch_size"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
android:background="?attr/selectableItemBackground"
|
||||||
|
android:scaleType="center"
|
||||||
|
android:src="@drawable/ic_eye_black"
|
||||||
|
android:tint="?attr/colorAccent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/exportDialogTil"
|
||||||
|
app:layout_constraintTop_toTopOf="@id/exportDialogTil" />
|
||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
|
android:id="@+id/exportDialogTil"
|
||||||
style="@style/VectorTextInputLayout"
|
style="@style/VectorTextInputLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="8dp"
|
android:layout_marginTop="8dp"
|
||||||
android:textColorHint="?attr/vctr_default_text_hint_color">
|
android:textColorHint="?attr/vctr_default_text_hint_color"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/exportDialogShowPassword"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/exportDialogText">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/dialog_e2e_keys_passphrase_edit_text"
|
android:id="@+id/exportDialogEt"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/passphrase_create_passphrase"
|
android:hint="@string/passphrase_create_passphrase"
|
||||||
@ -38,16 +58,19 @@
|
|||||||
|
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputLayout
|
<com.google.android.material.textfield.TextInputLayout
|
||||||
android:id="@+id/dialog_e2e_keys_confirm_passphrase_til"
|
android:id="@+id/exportDialogTilConfirm"
|
||||||
style="@style/VectorTextInputLayout"
|
style="@style/VectorTextInputLayout"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="0dp"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:layout_marginTop="10dp"
|
android:layout_marginTop="10dp"
|
||||||
android:textColorHint="?attr/vctr_default_text_hint_color"
|
android:textColorHint="?attr/vctr_default_text_hint_color"
|
||||||
app:errorEnabled="true">
|
app:errorEnabled="true"
|
||||||
|
app:layout_constraintEnd_toEndOf="@+id/exportDialogTil"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/exportDialogTil">
|
||||||
|
|
||||||
<com.google.android.material.textfield.TextInputEditText
|
<com.google.android.material.textfield.TextInputEditText
|
||||||
android:id="@+id/dialog_e2e_keys_confirm_passphrase_edit_text"
|
android:id="@+id/exportDialogEtConfirm"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:hint="@string/passphrase_confirm_passphrase"
|
android:hint="@string/passphrase_confirm_passphrase"
|
||||||
@ -57,10 +80,14 @@
|
|||||||
</com.google.android.material.textfield.TextInputLayout>
|
</com.google.android.material.textfield.TextInputLayout>
|
||||||
|
|
||||||
<com.google.android.material.button.MaterialButton
|
<com.google.android.material.button.MaterialButton
|
||||||
android:id="@+id/dialog_e2e_keys_export_button"
|
android:id="@+id/exportDialogSubmit"
|
||||||
style="@style/VectorButtonStyle"
|
style="@style/VectorButtonStyle"
|
||||||
android:layout_width="wrap_content"
|
android:layout_width="wrap_content"
|
||||||
android:layout_gravity="end"
|
android:layout_gravity="end"
|
||||||
android:enabled="false"
|
android:enabled="false"
|
||||||
android:text="@string/encryption_export_export" />
|
android:text="@string/encryption_export_export"
|
||||||
</LinearLayout>
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/exportDialogTilConfirm" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
Loading…
Reference in New Issue
Block a user