This commit is contained in:
Valere 2020-04-08 17:55:47 +02:00
parent 3968bb3488
commit 34dec64d9c
4 changed files with 92 additions and 36 deletions

View File

@ -14,6 +14,7 @@ Improvements 🙌:
- Cross-Signing | Setup key backup as part of SSSS bootstrapping (#1201) - Cross-Signing | Setup key backup as part of SSSS bootstrapping (#1201)
- Cross-Signing | Gossip key backup recovery key (#1200) - Cross-Signing | Gossip key backup recovery key (#1200)
- Show room encryption status as a bubble tile (#1078) - Show room encryption status as a bubble tile (#1078)
- Cross-Signing | Restore history after recover from passphrase (#1214)
Bugfix 🐛: Bugfix 🐛:
- Missing avatar/displayname after verification request message (#841) - Missing avatar/displayname after verification request message (#841)

View File

@ -37,6 +37,7 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.GlobalScope import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import timber.log.Timber
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
data class SharedSecureStorageViewState( data class SharedSecureStorageViewState(
@ -117,11 +118,15 @@ class SharedSecureStorageViewModel @AssistedInject constructor(
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
args.requestedSecrets.forEach { args.requestedSecrets.forEach {
val res = awaitCallback<String> { callback -> val res = awaitCallback<String> { callback ->
session.sharedSecretStorageService.getSecret( if (session.getAccountDataEvent(it) != null) {
name = it, session.sharedSecretStorageService.getSecret(
keyId = keyInfo.id, name = it,
secretKey = keySpec, keyId = keyInfo.id,
callback = callback) secretKey = keySpec,
callback = callback)
} else {
Timber.w("## Cannot find secret $it in SSSS, skip")
}
} }
decryptedSecretMap[it] = res decryptedSecretMap[it] = res
} }

View File

@ -32,6 +32,7 @@ import com.airbnb.mvrx.MvRx
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
import com.airbnb.mvrx.withState import com.airbnb.mvrx.withState
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
@ -108,7 +109,7 @@ class VerificationBottomSheet : VectorBaseBottomSheetDialogFragment() {
startActivityForResult(SharedSecureStorageActivity.newIntent( startActivityForResult(SharedSecureStorageActivity.newIntent(
requireContext(), requireContext(),
null, // use default key null, // use default key
listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME), listOf(MASTER_KEY_SSSS_NAME, USER_SIGNING_KEY_SSSS_NAME, SELF_SIGNING_KEY_SSSS_NAME, KEYBACKUP_SECRET_SSSS_NAME),
SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS SharedSecureStorageActivity.DEFAULT_RESULT_KEYSTORE_ALIAS
), SECRET_REQUEST_CODE) ), SECRET_REQUEST_CODE)
} }

View File

@ -15,6 +15,7 @@
*/ */
package im.vector.riotx.features.crypto.verification package im.vector.riotx.features.crypto.verification
import androidx.lifecycle.viewModelScope
import com.airbnb.mvrx.Async import com.airbnb.mvrx.Async
import com.airbnb.mvrx.Fail import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.FragmentViewModelContext import com.airbnb.mvrx.FragmentViewModelContext
@ -28,6 +29,7 @@ import com.squareup.inject.assisted.Assisted
import com.squareup.inject.assisted.AssistedInject import com.squareup.inject.assisted.AssistedInject
import im.vector.matrix.android.api.MatrixCallback import im.vector.matrix.android.api.MatrixCallback
import im.vector.matrix.android.api.session.Session import im.vector.matrix.android.api.session.Session
import im.vector.matrix.android.api.session.crypto.crosssigning.KEYBACKUP_SECRET_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.MASTER_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.SELF_SIGNING_KEY_SSSS_NAME
import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME import im.vector.matrix.android.api.session.crypto.crosssigning.USER_SIGNING_KEY_SSSS_NAME
@ -46,8 +48,13 @@ import im.vector.matrix.android.api.util.MatrixItem
import im.vector.matrix.android.api.util.toMatrixItem import im.vector.matrix.android.api.util.toMatrixItem
import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64 import im.vector.matrix.android.internal.crypto.crosssigning.fromBase64
import im.vector.matrix.android.internal.crypto.crosssigning.isVerified import im.vector.matrix.android.internal.crypto.crosssigning.isVerified
import im.vector.matrix.android.internal.crypto.keysbackup.model.rest.KeysVersionResult
import im.vector.matrix.android.internal.crypto.keysbackup.util.computeRecoveryKey
import im.vector.matrix.android.internal.crypto.model.ImportRoomKeysResult
import im.vector.matrix.android.internal.util.awaitCallback
import im.vector.riotx.core.extensions.exhaustive import im.vector.riotx.core.extensions.exhaustive
import im.vector.riotx.core.platform.VectorViewModel import im.vector.riotx.core.platform.VectorViewModel
import kotlinx.coroutines.launch
import timber.log.Timber import timber.log.Timber
data class VerificationBottomSheetViewState( data class VerificationBottomSheetViewState(
@ -334,40 +341,82 @@ class VerificationBottomSheetViewModel @AssistedInject constructor(
_viewEvents.post(VerificationBottomSheetViewEvents.AccessSecretStore) _viewEvents.post(VerificationBottomSheetViewEvents.AccessSecretStore)
} }
is VerificationAction.GotResultFromSsss -> { is VerificationAction.GotResultFromSsss -> {
try { handleSecretBackFromSSSS(action)
action.cypherData.fromBase64().inputStream().use { ins ->
val res = session.loadSecureSecret<Map<String, String>>(ins, action.alias)
val trustResult = session.cryptoService().crossSigningService().checkTrustFromPrivateKeys(
res?.get(MASTER_KEY_SSSS_NAME),
res?.get(USER_SIGNING_KEY_SSSS_NAME),
res?.get(SELF_SIGNING_KEY_SSSS_NAME)
)
if (trustResult.isVerified()) {
// Sign this device and upload the signature
session.sessionParams.credentials.deviceId?.let { deviceId ->
session.cryptoService()
.crossSigningService().trustDevice(deviceId, object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
Timber.w(failure, "Failed to sign my device after recovery")
}
})
}
setState {
copy(verifiedFromPrivateKeys = true)
}
} else {
// POP UP something
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError("Failed to import keys"))
}
}
} catch (failure: Throwable) {
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError(failure.localizedMessage))
}
} }
}.exhaustive }.exhaustive
} }
private fun handleSecretBackFromSSSS(action: VerificationAction.GotResultFromSsss) {
try {
action.cypherData.fromBase64().inputStream().use { ins ->
val res = session.loadSecureSecret<Map<String, String>>(ins, action.alias)
val trustResult = session.cryptoService().crossSigningService().checkTrustFromPrivateKeys(
res?.get(MASTER_KEY_SSSS_NAME),
res?.get(USER_SIGNING_KEY_SSSS_NAME),
res?.get(SELF_SIGNING_KEY_SSSS_NAME)
)
if (trustResult.isVerified()) {
// Sign this device and upload the signature
session.sessionParams.credentials.deviceId?.let { deviceId ->
session.cryptoService()
.crossSigningService().trustDevice(deviceId, object : MatrixCallback<Unit> {
override fun onFailure(failure: Throwable) {
Timber.w(failure, "Failed to sign my device after recovery")
}
})
}
setState {
copy(verifiedFromPrivateKeys = true)
}
// try to get keybackup key
} else {
// POP UP something
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError("Failed to import keys"))
}
// try the keybackup
tentativeRestoreBackup(res)
Unit
}
} catch (failure: Throwable) {
_viewEvents.post(VerificationBottomSheetViewEvents.ModalError(failure.localizedMessage))
}
}
private fun tentativeRestoreBackup(res: Map<String, String>?) {
viewModelScope.launch {
try {
val secret = res?.get(KEYBACKUP_SECRET_SSSS_NAME) ?: return@launch Unit.also {
Timber.v("## Keybackup secret not restored from SSSS")
}
val version = awaitCallback<KeysVersionResult?> {
session.cryptoService().keysBackupService().getCurrentVersion(it)
} ?: return@launch
awaitCallback<ImportRoomKeysResult> {
session.cryptoService().keysBackupService().restoreKeysWithRecoveryKey(
version,
computeRecoveryKey(secret.fromBase64()),
null,
null,
null,
it
)
}
awaitCallback<Unit> {
session.cryptoService().keysBackupService().trustKeysBackupVersion(version, true, it)
}
} catch (failure: Throwable) {
// Just ignore for now
Timber.v("## Failed to restore backup after SSSS recovery")
}
}
}
override fun transactionCreated(tx: VerificationTransaction) { override fun transactionCreated(tx: VerificationTransaction) {
transactionUpdated(tx) transactionUpdated(tx)
} }