KeysBackup: some API parameters are mandatory, so stop considering them as optional and avoid using !!
Also fix an issue with Json name: `hash` -> `etag` Add some `internal` modifier (not as much as I would like to) var -> val Remove unused code
This commit is contained in:
parent
14e7e5e9fd
commit
0bcf42dbb8
@ -245,7 +245,8 @@ class CryptoTestHelper(private val mTestHelper: CommonTestHelper) {
|
|||||||
fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo {
|
fun createFakeMegolmBackupCreationInfo(): MegolmBackupCreationInfo {
|
||||||
return MegolmBackupCreationInfo(
|
return MegolmBackupCreationInfo(
|
||||||
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
|
algorithm = MXCRYPTO_ALGORITHM_MEGOLM_BACKUP,
|
||||||
authData = createFakeMegolmBackupAuthData()
|
authData = createFakeMegolmBackupAuthData(),
|
||||||
|
recoveryKey = "fake"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,9 +115,8 @@ class KeysBackupTest : InstrumentedTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, megolmBackupCreationInfo.algorithm)
|
assertEquals(MXCRYPTO_ALGORITHM_MEGOLM_BACKUP, megolmBackupCreationInfo.algorithm)
|
||||||
assertNotNull(megolmBackupCreationInfo.authData)
|
assertNotNull(megolmBackupCreationInfo.authData.publicKey)
|
||||||
assertNotNull(megolmBackupCreationInfo.authData!!.publicKey)
|
assertNotNull(megolmBackupCreationInfo.authData.signatures)
|
||||||
assertNotNull(megolmBackupCreationInfo.authData!!.signatures)
|
|
||||||
assertNotNull(megolmBackupCreationInfo.recoveryKey)
|
assertNotNull(megolmBackupCreationInfo.recoveryKey)
|
||||||
|
|
||||||
stateObserver.stopAndCheckStates(null)
|
stateObserver.stopAndCheckStates(null)
|
||||||
|
@ -30,7 +30,6 @@ import org.matrix.android.sdk.api.listeners.StepProgressListener
|
|||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupService
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupState
|
||||||
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
|
import org.matrix.android.sdk.api.session.crypto.keysbackup.KeysBackupStateListener
|
||||||
import org.matrix.android.sdk.api.util.JsonDict
|
|
||||||
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|
||||||
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
|
import org.matrix.android.sdk.internal.crypto.MXOlmDevice
|
||||||
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
import org.matrix.android.sdk.internal.crypto.MegolmSessionData
|
||||||
@ -85,6 +84,7 @@ import kotlinx.coroutines.CoroutineScope
|
|||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.SignalableMegolmBackupAuthData
|
||||||
import org.matrix.olm.OlmException
|
import org.matrix.olm.OlmException
|
||||||
import org.matrix.olm.OlmPkDecryption
|
import org.matrix.olm.OlmPkDecryption
|
||||||
import org.matrix.olm.OlmPkEncryption
|
import org.matrix.olm.OlmPkEncryption
|
||||||
@ -170,7 +170,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
runCatching {
|
runCatching {
|
||||||
withContext(coroutineDispatchers.crypto) {
|
withContext(coroutineDispatchers.crypto) {
|
||||||
val olmPkDecryption = OlmPkDecryption()
|
val olmPkDecryption = OlmPkDecryption()
|
||||||
val megolmBackupAuthData = if (password != null) {
|
val signalableMegolmBackupAuthData = if (password != null) {
|
||||||
// Generate a private key from the password
|
// Generate a private key from the password
|
||||||
val backgroundProgressListener = if (progressListener == null) {
|
val backgroundProgressListener = if (progressListener == null) {
|
||||||
null
|
null
|
||||||
@ -189,7 +189,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
|
val generatePrivateKeyResult = generatePrivateKeyWithPassword(password, backgroundProgressListener)
|
||||||
MegolmBackupAuthData(
|
SignalableMegolmBackupAuthData(
|
||||||
publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
|
publicKey = olmPkDecryption.setPrivateKey(generatePrivateKeyResult.privateKey),
|
||||||
privateKeySalt = generatePrivateKeyResult.salt,
|
privateKeySalt = generatePrivateKeyResult.salt,
|
||||||
privateKeyIterations = generatePrivateKeyResult.iterations
|
privateKeyIterations = generatePrivateKeyResult.iterations
|
||||||
@ -197,14 +197,17 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
} else {
|
} else {
|
||||||
val publicKey = olmPkDecryption.generateKey()
|
val publicKey = olmPkDecryption.generateKey()
|
||||||
|
|
||||||
MegolmBackupAuthData(
|
SignalableMegolmBackupAuthData(
|
||||||
publicKey = publicKey
|
publicKey = publicKey
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, megolmBackupAuthData.signalableJSONDictionary())
|
val canonicalJson = JsonCanonicalizer.getCanonicalJson(Map::class.java, signalableMegolmBackupAuthData.signalableJSONDictionary())
|
||||||
|
|
||||||
val signedMegolmBackupAuthData = megolmBackupAuthData.copy(
|
val signedMegolmBackupAuthData = MegolmBackupAuthData(
|
||||||
|
publicKey = signalableMegolmBackupAuthData.publicKey,
|
||||||
|
privateKeySalt = signalableMegolmBackupAuthData.privateKeySalt,
|
||||||
|
privateKeyIterations = signalableMegolmBackupAuthData.privateKeyIterations,
|
||||||
signatures = objectSigner.signObject(canonicalJson)
|
signatures = objectSigner.signObject(canonicalJson)
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -223,8 +226,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
|
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
|
||||||
algorithm = keysBackupCreationInfo.algorithm,
|
algorithm = keysBackupCreationInfo.algorithm,
|
||||||
authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
|
authData = keysBackupCreationInfo.authData.toJsonDict()
|
||||||
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
keysBackupStateManager.state = KeysBackupState.Enabling
|
keysBackupStateManager.state = KeysBackupState.Enabling
|
||||||
@ -245,7 +247,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
version = data.version,
|
version = data.version,
|
||||||
// We can consider that the server does not have keys yet
|
// We can consider that the server does not have keys yet
|
||||||
count = 0,
|
count = 0,
|
||||||
hash = null
|
hash = ""
|
||||||
)
|
)
|
||||||
|
|
||||||
enableKeysBackup(keyBackupVersion)
|
enableKeysBackup(keyBackupVersion)
|
||||||
@ -267,7 +269,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
withContext(coroutineDispatchers.crypto) {
|
withContext(coroutineDispatchers.crypto) {
|
||||||
// If we're currently backing up to this backup... stop.
|
// If we're currently backing up to this backup... stop.
|
||||||
// (We start using it automatically in createKeysBackupVersion so this is symmetrical).
|
// (We start using it automatically in createKeysBackupVersion so this is symmetrical).
|
||||||
if (keysBackupVersion != null && version == keysBackupVersion!!.version) {
|
if (keysBackupVersion != null && version == keysBackupVersion?.version) {
|
||||||
resetKeysBackupData()
|
resetKeysBackupData()
|
||||||
keysBackupVersion = null
|
keysBackupVersion = null
|
||||||
keysBackupStateManager.state = KeysBackupState.Unknown
|
keysBackupStateManager.state = KeysBackupState.Unknown
|
||||||
@ -408,10 +410,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
val keysBackupVersionTrust = KeysBackupVersionTrust()
|
val keysBackupVersionTrust = KeysBackupVersionTrust()
|
||||||
val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData()
|
val authData = keysBackupVersion.getAuthDataAsMegolmBackupAuthData()
|
||||||
|
|
||||||
if (keysBackupVersion.algorithm == null
|
if (authData == null || authData.publicKey.isEmpty() || authData.signatures.isEmpty()) {
|
||||||
|| authData == null
|
|
||||||
|| authData.publicKey.isEmpty()
|
|
||||||
|| authData.signatures.isNullOrEmpty()) {
|
|
||||||
Timber.v("getKeysBackupTrust: Key backup is absent or missing required data")
|
Timber.v("getKeysBackupTrust: Key backup is absent or missing required data")
|
||||||
return keysBackupVersionTrust
|
return keysBackupVersionTrust
|
||||||
}
|
}
|
||||||
@ -479,7 +478,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.main) {
|
||||||
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
|
val updateKeysBackupVersionBody = withContext(coroutineDispatchers.crypto) {
|
||||||
// Get current signatures, or create an empty set
|
// Get current signatures, or create an empty set
|
||||||
val myUserSignatures = authData.signatures?.get(userId)?.toMutableMap() ?: HashMap()
|
val myUserSignatures = authData.signatures[userId].orEmpty().toMutableMap()
|
||||||
|
|
||||||
if (trust) {
|
if (trust) {
|
||||||
// Add current device signature
|
// Add current device signature
|
||||||
@ -498,26 +497,23 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
// Create an updated version of KeysVersionResult
|
// Create an updated version of KeysVersionResult
|
||||||
val newMegolmBackupAuthData = authData.copy()
|
val newMegolmBackupAuthData = authData.copy()
|
||||||
|
|
||||||
val newSignatures = newMegolmBackupAuthData.signatures!!.toMutableMap()
|
val newSignatures = newMegolmBackupAuthData.signatures.toMutableMap()
|
||||||
newSignatures[userId] = myUserSignatures
|
newSignatures[userId] = myUserSignatures
|
||||||
|
|
||||||
val newMegolmBackupAuthDataWithNewSignature = newMegolmBackupAuthData.copy(
|
val newMegolmBackupAuthDataWithNewSignature = newMegolmBackupAuthData.copy(
|
||||||
signatures = newSignatures
|
signatures = newSignatures
|
||||||
)
|
)
|
||||||
|
|
||||||
val moshi = MoshiProvider.providesMoshi()
|
|
||||||
val adapter = moshi.adapter(Map::class.java)
|
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
UpdateKeysBackupVersionBody(
|
UpdateKeysBackupVersionBody(
|
||||||
algorithm = keysBackupVersion.algorithm,
|
algorithm = keysBackupVersion.algorithm,
|
||||||
authData = adapter.fromJson(newMegolmBackupAuthDataWithNewSignature.toJsonString()) as Map<String, Any>?,
|
authData = newMegolmBackupAuthDataWithNewSignature.toJsonDict(),
|
||||||
version = keysBackupVersion.version!!)
|
version = keysBackupVersion.version)
|
||||||
}
|
}
|
||||||
|
|
||||||
// And send it to the homeserver
|
// And send it to the homeserver
|
||||||
updateKeysBackupVersionTask
|
updateKeysBackupVersionTask
|
||||||
.configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version!!, updateKeysBackupVersionBody)) {
|
.configureWith(UpdateKeysBackupVersionTask.Params(keysBackupVersion.version, updateKeysBackupVersionBody)) {
|
||||||
this.callback = object : MatrixCallback<Unit> {
|
this.callback = object : MatrixCallback<Unit> {
|
||||||
override fun onSuccess(data: Unit) {
|
override fun onSuccess(data: Unit) {
|
||||||
// Relaunch the state machine on this updated backup version
|
// Relaunch the state machine on this updated backup version
|
||||||
@ -688,7 +684,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey)
|
stepProgressListener?.onStepProgress(StepProgressListener.Step.DownloadingKey)
|
||||||
|
|
||||||
// Get backed up keys from the homeserver
|
// Get backed up keys from the homeserver
|
||||||
val data = getKeys(sessionId, roomId, keysVersionResult.version!!)
|
val data = getKeys(sessionId, roomId, keysVersionResult.version)
|
||||||
|
|
||||||
withContext(coroutineDispatchers.computation) {
|
withContext(coroutineDispatchers.computation) {
|
||||||
val sessionsData = ArrayList<MegolmSessionData>()
|
val sessionsData = ArrayList<MegolmSessionData>()
|
||||||
@ -1023,19 +1019,10 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
* @return the authentication if found and valid, null in other case
|
* @return the authentication if found and valid, null in other case
|
||||||
*/
|
*/
|
||||||
private fun getMegolmBackupAuthData(keysBackupData: KeysVersionResult): MegolmBackupAuthData? {
|
private fun getMegolmBackupAuthData(keysBackupData: KeysVersionResult): MegolmBackupAuthData? {
|
||||||
if (keysBackupData.version.isNullOrBlank()
|
return keysBackupData
|
||||||
|| keysBackupData.algorithm != MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|
.takeIf { it.version.isNotEmpty() && it.algorithm == MXCRYPTO_ALGORITHM_MEGOLM_BACKUP }
|
||||||
|| keysBackupData.authData == null) {
|
?.getAuthDataAsMegolmBackupAuthData()
|
||||||
return null
|
?.takeIf { it.publicKey.isNotEmpty() }
|
||||||
}
|
|
||||||
|
|
||||||
val authData = keysBackupData.getAuthDataAsMegolmBackupAuthData()
|
|
||||||
|
|
||||||
if (authData?.signatures == null || authData.publicKey.isBlank()) {
|
|
||||||
return null
|
|
||||||
}
|
|
||||||
|
|
||||||
return authData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -1123,34 +1110,29 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
* @param keysVersionResult backup information object as returned by [getCurrentVersion].
|
* @param keysVersionResult backup information object as returned by [getCurrentVersion].
|
||||||
*/
|
*/
|
||||||
private fun enableKeysBackup(keysVersionResult: KeysVersionResult) {
|
private fun enableKeysBackup(keysVersionResult: KeysVersionResult) {
|
||||||
if (keysVersionResult.authData != null) {
|
val retrievedMegolmBackupAuthData = keysVersionResult.getAuthDataAsMegolmBackupAuthData()
|
||||||
val retrievedMegolmBackupAuthData = keysVersionResult.getAuthDataAsMegolmBackupAuthData()
|
|
||||||
|
|
||||||
if (retrievedMegolmBackupAuthData != null) {
|
if (retrievedMegolmBackupAuthData != null) {
|
||||||
keysBackupVersion = keysVersionResult
|
keysBackupVersion = keysVersionResult
|
||||||
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
cryptoCoroutineScope.launch(coroutineDispatchers.crypto) {
|
||||||
cryptoStore.setKeyBackupVersion(keysVersionResult.version)
|
cryptoStore.setKeyBackupVersion(keysVersionResult.version)
|
||||||
}
|
|
||||||
|
|
||||||
onServerDataRetrieved(keysVersionResult.count, keysVersionResult.hash)
|
|
||||||
|
|
||||||
try {
|
|
||||||
backupOlmPkEncryption = OlmPkEncryption().apply {
|
|
||||||
setRecipientKey(retrievedMegolmBackupAuthData.publicKey)
|
|
||||||
}
|
|
||||||
} catch (e: OlmException) {
|
|
||||||
Timber.e(e, "OlmException")
|
|
||||||
keysBackupStateManager.state = KeysBackupState.Disabled
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
|
|
||||||
|
|
||||||
maybeBackupKeys()
|
|
||||||
} else {
|
|
||||||
Timber.e("Invalid authentication data")
|
|
||||||
keysBackupStateManager.state = KeysBackupState.Disabled
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
onServerDataRetrieved(keysVersionResult.count, keysVersionResult.hash)
|
||||||
|
|
||||||
|
try {
|
||||||
|
backupOlmPkEncryption = OlmPkEncryption().apply {
|
||||||
|
setRecipientKey(retrievedMegolmBackupAuthData.publicKey)
|
||||||
|
}
|
||||||
|
} catch (e: OlmException) {
|
||||||
|
Timber.e(e, "OlmException")
|
||||||
|
keysBackupStateManager.state = KeysBackupState.Disabled
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
keysBackupStateManager.state = KeysBackupState.ReadyToBackUp
|
||||||
|
|
||||||
|
maybeBackupKeys()
|
||||||
} else {
|
} else {
|
||||||
Timber.e("Invalid authentication data")
|
Timber.e("Invalid authentication data")
|
||||||
keysBackupStateManager.state = KeysBackupState.Disabled
|
keysBackupStateManager.state = KeysBackupState.Disabled
|
||||||
@ -1160,11 +1142,11 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
/**
|
/**
|
||||||
* Update the DB with data fetch from the server
|
* Update the DB with data fetch from the server
|
||||||
*/
|
*/
|
||||||
private fun onServerDataRetrieved(count: Int?, hash: String?) {
|
private fun onServerDataRetrieved(count: Int?, etag: String?) {
|
||||||
cryptoStore.setKeysBackupData(KeysBackupDataEntity()
|
cryptoStore.setKeysBackupData(KeysBackupDataEntity()
|
||||||
.apply {
|
.apply {
|
||||||
backupLastServerNumberOfKeys = count
|
backupLastServerNumberOfKeys = count
|
||||||
backupLastServerHash = hash
|
backupLastServerHash = etag
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -1316,7 +1298,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
|
|
||||||
// Make the request
|
// Make the request
|
||||||
storeSessionDataTask
|
storeSessionDataTask
|
||||||
.configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version!!, keysBackupData)) {
|
.configureWith(StoreSessionsDataTask.Params(keysBackupVersion!!.version, keysBackupData)) {
|
||||||
this.callback = sendingRequestCallback
|
this.callback = sendingRequestCallback
|
||||||
}
|
}
|
||||||
.executeBy(taskExecutor)
|
.executeBy(taskExecutor)
|
||||||
@ -1337,8 +1319,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
"algorithm" to sessionData!!.algorithm,
|
"algorithm" to sessionData!!.algorithm,
|
||||||
"sender_key" to sessionData.senderKey,
|
"sender_key" to sessionData.senderKey,
|
||||||
"sender_claimed_keys" to sessionData.senderClaimedKeys,
|
"sender_claimed_keys" to sessionData.senderClaimedKeys,
|
||||||
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain
|
"forwarding_curve25519_key_chain" to (sessionData.forwardingCurve25519KeyChain.orEmpty()),
|
||||||
?: ArrayList<Any>()),
|
|
||||||
"session_key" to sessionData.sessionKey)
|
"session_key" to sessionData.sessionKey)
|
||||||
|
|
||||||
var encryptedSessionBackupData: OlmPkMessage? = null
|
var encryptedSessionBackupData: OlmPkMessage? = null
|
||||||
@ -1379,9 +1360,9 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
|
|
||||||
val jsonObject = keyBackupData.sessionData
|
val jsonObject = keyBackupData.sessionData
|
||||||
|
|
||||||
val ciphertext = jsonObject?.get("ciphertext")?.toString()
|
val ciphertext = jsonObject["ciphertext"]?.toString()
|
||||||
val mac = jsonObject?.get("mac")?.toString()
|
val mac = jsonObject["mac"]?.toString()
|
||||||
val ephemeralKey = jsonObject?.get("ephemeral")?.toString()
|
val ephemeralKey = jsonObject["ephemeral"]?.toString()
|
||||||
|
|
||||||
if (ciphertext != null && mac != null && ephemeralKey != null) {
|
if (ciphertext != null && mac != null && ephemeralKey != null) {
|
||||||
val encrypted = OlmPkMessage()
|
val encrypted = OlmPkMessage()
|
||||||
@ -1426,8 +1407,7 @@ internal class DefaultKeysBackupService @Inject constructor(
|
|||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
|
val createKeysBackupVersionBody = CreateKeysBackupVersionBody(
|
||||||
algorithm = keysBackupCreationInfo.algorithm,
|
algorithm = keysBackupCreationInfo.algorithm,
|
||||||
authData = MoshiProvider.providesMoshi().adapter(Map::class.java)
|
authData = keysBackupCreationInfo.authData.toJsonDict()
|
||||||
.fromJson(keysBackupCreationInfo.authData?.toJsonString() ?: "") as JsonDict?
|
|
||||||
)
|
)
|
||||||
|
|
||||||
createKeysBackupVersionTask
|
createKeysBackupVersionTask
|
||||||
|
@ -35,7 +35,7 @@ import retrofit2.http.Path
|
|||||||
import retrofit2.http.Query
|
import retrofit2.http.Query
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ref: https://github.com/uhoreg/matrix-doc/blob/e2e_backup/proposals/1219-storing-megolm-keys-serverside.md
|
* Ref: https://matrix.org/docs/spec/client_server/unstable#server-side-key-backups
|
||||||
*/
|
*/
|
||||||
internal interface RoomKeysApi {
|
internal interface RoomKeysApi {
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model
|
|||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,7 +31,7 @@ data class MegolmBackupAuthData(
|
|||||||
* The curve25519 public key used to encrypt the backups.
|
* The curve25519 public key used to encrypt the backups.
|
||||||
*/
|
*/
|
||||||
@Json(name = "public_key")
|
@Json(name = "public_key")
|
||||||
val publicKey: String = "",
|
val publicKey: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* In case of a backup created from a password, the salt associated with the backup
|
* In case of a backup created from a password, the salt associated with the backup
|
||||||
@ -50,20 +51,38 @@ data class MegolmBackupAuthData(
|
|||||||
* userId -> (deviceSignKeyId -> signature)
|
* userId -> (deviceSignKeyId -> signature)
|
||||||
*/
|
*/
|
||||||
@Json(name = "signatures")
|
@Json(name = "signatures")
|
||||||
val signatures: Map<String, Map<String, String>>? = null
|
val signatures: Map<String, Map<String, String>>
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun toJsonString(): String {
|
fun toJsonDict(): JsonDict {
|
||||||
return MoshiProvider.providesMoshi()
|
val moshi = MoshiProvider.providesMoshi()
|
||||||
|
val adapter = moshi.adapter(Map::class.java)
|
||||||
|
|
||||||
|
return moshi
|
||||||
.adapter(MegolmBackupAuthData::class.java)
|
.adapter(MegolmBackupAuthData::class.java)
|
||||||
.toJson(this)
|
.toJson(this)
|
||||||
|
.let {
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
adapter.fromJson(it) as JsonDict
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
fun signalableJSONDictionary(): JsonDict {
|
||||||
* Same as the parent [MXJSONModel JSONDictionary] but return only
|
return SignalableMegolmBackupAuthData(
|
||||||
* data that must be signed.
|
publicKey = publicKey,
|
||||||
*/
|
privateKeySalt = privateKeySalt,
|
||||||
fun signalableJSONDictionary(): Map<String, Any> = HashMap<String, Any>().apply {
|
privateKeyIterations = privateKeyIterations
|
||||||
|
)
|
||||||
|
.signalableJSONDictionary()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal data class SignalableMegolmBackupAuthData(
|
||||||
|
val publicKey: String,
|
||||||
|
val privateKeySalt: String? = null,
|
||||||
|
val privateKeyIterations: Int? = null
|
||||||
|
) {
|
||||||
|
fun signalableJSONDictionary(): JsonDict = HashMap<String, Any>().apply {
|
||||||
put("public_key", publicKey)
|
put("public_key", publicKey)
|
||||||
|
|
||||||
privateKeySalt?.let {
|
privateKeySalt?.let {
|
||||||
|
@ -23,15 +23,15 @@ data class MegolmBackupCreationInfo(
|
|||||||
/**
|
/**
|
||||||
* The algorithm used for storing backups [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP].
|
* The algorithm used for storing backups [org.matrix.androidsdk.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP].
|
||||||
*/
|
*/
|
||||||
val algorithm: String = "",
|
val algorithm: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authentication data.
|
* Authentication data.
|
||||||
*/
|
*/
|
||||||
val authData: MegolmBackupAuthData? = null,
|
val authData: MegolmBackupAuthData,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The Base58 recovery key.
|
* The Base58 recovery key.
|
||||||
*/
|
*/
|
||||||
val recoveryKey: String = ""
|
val recoveryKey: String
|
||||||
)
|
)
|
||||||
|
@ -16,15 +16,16 @@
|
|||||||
|
|
||||||
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
|
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
|
||||||
|
|
||||||
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class BackupKeysResult(
|
internal data class BackupKeysResult(
|
||||||
|
|
||||||
// The hash value which is an opaque string representing stored keys in the backup
|
// The hash value which is an opaque string representing stored keys in the backup
|
||||||
var hash: String? = null,
|
@Json(name = "etag")
|
||||||
|
val hash: String,
|
||||||
|
|
||||||
// The number of keys stored in the backup.
|
// The number of keys stored in the backup.
|
||||||
var count: Int? = null
|
@Json(name = "count")
|
||||||
|
val count: Int
|
||||||
)
|
)
|
||||||
|
@ -21,17 +21,17 @@ import com.squareup.moshi.JsonClass
|
|||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
|
||||||
@JsonClass(generateAdapter = true)
|
@JsonClass(generateAdapter = true)
|
||||||
data class CreateKeysBackupVersionBody(
|
internal data class CreateKeysBackupVersionBody(
|
||||||
/**
|
/**
|
||||||
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
||||||
*/
|
*/
|
||||||
@Json(name = "algorithm")
|
@Json(name = "algorithm")
|
||||||
override val algorithm: String? = null,
|
override val algorithm: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
|
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
|
||||||
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
||||||
*/
|
*/
|
||||||
@Json(name = "auth_data")
|
@Json(name = "auth_data")
|
||||||
override val authData: JsonDict? = null
|
override val authData: JsonDict
|
||||||
) : KeysAlgorithmAndData
|
) : KeysAlgorithmAndData
|
||||||
|
@ -18,7 +18,7 @@ package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
|
|||||||
|
|
||||||
import com.squareup.moshi.Json
|
import com.squareup.moshi.Json
|
||||||
import com.squareup.moshi.JsonClass
|
import com.squareup.moshi.JsonClass
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
import org.matrix.android.sdk.internal.network.parsing.ForceToBoolean
|
import org.matrix.android.sdk.internal.network.parsing.ForceToBoolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -30,13 +30,13 @@ data class KeyBackupData(
|
|||||||
* Required. The index of the first message in the session that the key can decrypt.
|
* Required. The index of the first message in the session that the key can decrypt.
|
||||||
*/
|
*/
|
||||||
@Json(name = "first_message_index")
|
@Json(name = "first_message_index")
|
||||||
val firstMessageIndex: Long = 0,
|
val firstMessageIndex: Long,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Required. The number of times this key has been forwarded.
|
* Required. The number of times this key has been forwarded.
|
||||||
*/
|
*/
|
||||||
@Json(name = "forwarded_count")
|
@Json(name = "forwarded_count")
|
||||||
val forwardedCount: Int = 0,
|
val forwardedCount: Int,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Whether the device backing up the key has verified the device that the key is from.
|
* Whether the device backing up the key has verified the device that the key is from.
|
||||||
@ -44,16 +44,11 @@ data class KeyBackupData(
|
|||||||
*/
|
*/
|
||||||
@ForceToBoolean
|
@ForceToBoolean
|
||||||
@Json(name = "is_verified")
|
@Json(name = "is_verified")
|
||||||
val isVerified: Boolean = false,
|
val isVerified: Boolean,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Algorithm-dependent data.
|
* Algorithm-dependent data.
|
||||||
*/
|
*/
|
||||||
@Json(name = "session_data")
|
@Json(name = "session_data")
|
||||||
val sessionData: Map<String, Any>? = null
|
val sessionData: JsonDict
|
||||||
) {
|
)
|
||||||
|
|
||||||
fun toJsonString(): String {
|
|
||||||
return MoshiProvider.providesMoshi().adapter(KeyBackupData::class.java).toJson(this)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
|
package org.matrix.android.sdk.internal.crypto.keysbackup.model.rest
|
||||||
|
|
||||||
import org.matrix.android.sdk.api.util.JsonDict
|
import org.matrix.android.sdk.api.util.JsonDict
|
||||||
|
import org.matrix.android.sdk.internal.crypto.MXCRYPTO_ALGORITHM_MEGOLM_BACKUP
|
||||||
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
import org.matrix.android.sdk.internal.crypto.keysbackup.model.MegolmBackupAuthData
|
||||||
import org.matrix.android.sdk.internal.di.MoshiProvider
|
import org.matrix.android.sdk.internal.di.MoshiProvider
|
||||||
|
|
||||||
@ -37,24 +38,25 @@ import org.matrix.android.sdk.internal.di.MoshiProvider
|
|||||||
* }
|
* }
|
||||||
* </pre>
|
* </pre>
|
||||||
*/
|
*/
|
||||||
interface KeysAlgorithmAndData {
|
internal interface KeysAlgorithmAndData {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
||||||
*/
|
*/
|
||||||
val algorithm: String?
|
val algorithm: String
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2" see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
||||||
*/
|
*/
|
||||||
val authData: JsonDict?
|
val authData: JsonDict
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Facility method to convert authData to a MegolmBackupAuthData object
|
* Facility method to convert authData to a MegolmBackupAuthData object
|
||||||
*/
|
*/
|
||||||
fun getAuthDataAsMegolmBackupAuthData(): MegolmBackupAuthData? {
|
fun getAuthDataAsMegolmBackupAuthData(): MegolmBackupAuthData? {
|
||||||
return MoshiProvider.providesMoshi()
|
return MoshiProvider.providesMoshi()
|
||||||
.adapter(MegolmBackupAuthData::class.java)
|
.takeIf { algorithm == MXCRYPTO_ALGORITHM_MEGOLM_BACKUP }
|
||||||
.fromJsonValue(authData)
|
?.adapter(MegolmBackupAuthData::class.java)
|
||||||
|
?.fromJsonValue(authData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,5 +23,5 @@ import com.squareup.moshi.JsonClass
|
|||||||
data class KeysVersion(
|
data class KeysVersion(
|
||||||
// the keys backup version
|
// the keys backup version
|
||||||
@Json(name = "version")
|
@Json(name = "version")
|
||||||
val version: String? = null
|
val version: String
|
||||||
)
|
)
|
||||||
|
@ -26,24 +26,24 @@ data class KeysVersionResult(
|
|||||||
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
||||||
*/
|
*/
|
||||||
@Json(name = "algorithm")
|
@Json(name = "algorithm")
|
||||||
override val algorithm: String? = null,
|
override val algorithm: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
|
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
|
||||||
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
||||||
*/
|
*/
|
||||||
@Json(name = "auth_data")
|
@Json(name = "auth_data")
|
||||||
override val authData: JsonDict? = null,
|
override val authData: JsonDict,
|
||||||
|
|
||||||
// the backup version
|
// the backup version
|
||||||
@Json(name = "version")
|
@Json(name = "version")
|
||||||
val version: String? = null,
|
val version: String,
|
||||||
|
|
||||||
// The hash value which is an opaque string representing stored keys in the backup
|
// The hash value which is an opaque string representing stored keys in the backup
|
||||||
@Json(name = "hash")
|
@Json(name = "etag")
|
||||||
val hash: String? = null,
|
val hash: String,
|
||||||
|
|
||||||
// The number of keys stored in the backup.
|
// The number of keys stored in the backup.
|
||||||
@Json(name = "count")
|
@Json(name = "count")
|
||||||
val count: Int? = null
|
val count: Int
|
||||||
) : KeysAlgorithmAndData
|
) : KeysAlgorithmAndData
|
||||||
|
@ -26,16 +26,16 @@ data class UpdateKeysBackupVersionBody(
|
|||||||
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
* The algorithm used for storing backups. Currently, only "m.megolm_backup.v1.curve25519-aes-sha2" is defined
|
||||||
*/
|
*/
|
||||||
@Json(name = "algorithm")
|
@Json(name = "algorithm")
|
||||||
override val algorithm: String? = null,
|
override val algorithm: String,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
|
* algorithm-dependent data, for "m.megolm_backup.v1.curve25519-aes-sha2"
|
||||||
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
* see [org.matrix.android.sdk.internal.crypto.keysbackup.MegolmBackupAuthData]
|
||||||
*/
|
*/
|
||||||
@Json(name = "auth_data")
|
@Json(name = "auth_data")
|
||||||
override val authData: JsonDict? = null,
|
override val authData: JsonDict,
|
||||||
|
|
||||||
// the backup version, mandatory
|
// Optional. The backup version. If present, must be the same as the path parameter.
|
||||||
@Json(name = "version")
|
@Json(name = "version")
|
||||||
val version: String
|
val version: String? = null
|
||||||
) : KeysAlgorithmAndData
|
) : KeysAlgorithmAndData
|
||||||
|
@ -103,7 +103,7 @@ class BootstrapSharedViewModel @AssistedInject constructor(
|
|||||||
} else {
|
} else {
|
||||||
// we need to get existing backup passphrase/key and convert to SSSS
|
// we need to get existing backup passphrase/key and convert to SSSS
|
||||||
val keyVersion = awaitCallback<KeysVersionResult?> {
|
val keyVersion = awaitCallback<KeysVersionResult?> {
|
||||||
session.cryptoService().keysBackupService().getVersion(version.version ?: "", it)
|
session.cryptoService().keysBackupService().getVersion(version.version, it)
|
||||||
}
|
}
|
||||||
if (keyVersion == null) {
|
if (keyVersion == null) {
|
||||||
// strange case... just finish?
|
// strange case... just finish?
|
||||||
|
Loading…
Reference in New Issue
Block a user