Merge pull request #1172 from vector-im/feature/ensure_olm_account_unicity

Feature/ensure olm account unicity
This commit is contained in:
Valere 2020-03-26 12:11:09 +01:00 committed by GitHub
commit 1d46b523b9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 67 additions and 62 deletions

View File

@ -10,6 +10,7 @@ Improvements 🙌:
Bugfix 🐛:
- Missing avatar/displayname after verification request message (#841)
- Crypto | RiotX sometimes rotate the current device keys (#1170)
- RiotX can't restore cross signing keys saved by web in SSSS (#1174)
Translations 🗣:

View File

@ -59,9 +59,6 @@ internal class MXOlmDevice @Inject constructor(
var deviceEd25519Key: String? = null
private set
// The OLM lib account instance.
private var olmAccount: OlmAccount? = null
// The OLM lib utility instance.
private var olmUtility: OlmUtility? = null
@ -86,19 +83,10 @@ internal class MXOlmDevice @Inject constructor(
init {
// Retrieve the account from the store
olmAccount = store.getAccount()
if (null == olmAccount) {
Timber.v("MXOlmDevice : create a new olm account")
// Else, create it
try {
olmAccount = OlmAccount()
store.storeAccount(olmAccount!!)
} catch (e: Exception) {
Timber.e(e, "MXOlmDevice : cannot initialize olmAccount")
}
} else {
Timber.v("MXOlmDevice : use an existing account")
try {
store.getOrCreateOlmAccount()
} catch (e: Exception) {
Timber.e(e, "MXOlmDevice : cannot initialize olmAccount")
}
try {
@ -109,13 +97,13 @@ internal class MXOlmDevice @Inject constructor(
}
try {
deviceCurve25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
deviceCurve25519Key = store.getOlmAccount().identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
} catch (e: Exception) {
Timber.e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_IDENTITY_KEY} with error")
}
try {
deviceEd25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
deviceEd25519Key = store.getOlmAccount().identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
} catch (e: Exception) {
Timber.e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_FINGER_PRINT_KEY} with error")
}
@ -126,7 +114,7 @@ internal class MXOlmDevice @Inject constructor(
*/
fun getOneTimeKeys(): Map<String, Map<String, String>>? {
try {
return olmAccount!!.oneTimeKeys()
return store.getOlmAccount().oneTimeKeys()
} catch (e: Exception) {
Timber.e(e, "## getOneTimeKeys() : failed")
}
@ -138,14 +126,13 @@ internal class MXOlmDevice @Inject constructor(
* @return The maximum number of one-time keys the olm account can store.
*/
fun getMaxNumberOfOneTimeKeys(): Long {
return olmAccount?.maxOneTimeKeys() ?: -1
return store.getOlmAccount().maxOneTimeKeys()
}
/**
* Release the instance
*/
fun release() {
olmAccount?.releaseAccount()
olmUtility?.releaseUtility()
}
@ -157,7 +144,7 @@ internal class MXOlmDevice @Inject constructor(
*/
fun signMessage(message: String): String? {
try {
return olmAccount!!.signMessage(message)
return store.getOlmAccount().signMessage(message)
} catch (e: Exception) {
Timber.e(e, "## signMessage() : failed")
}
@ -170,8 +157,8 @@ internal class MXOlmDevice @Inject constructor(
*/
fun markKeysAsPublished() {
try {
olmAccount!!.markOneTimeKeysAsPublished()
store.storeAccount(olmAccount!!)
store.getOlmAccount().markOneTimeKeysAsPublished()
store.saveOlmAccount()
} catch (e: Exception) {
Timber.e(e, "## markKeysAsPublished() : failed")
}
@ -184,8 +171,8 @@ internal class MXOlmDevice @Inject constructor(
*/
fun generateOneTimeKeys(numKeys: Int) {
try {
olmAccount!!.generateOneTimeKeys(numKeys)
store.storeAccount(olmAccount!!)
store.getOlmAccount().generateOneTimeKeys(numKeys)
store.saveOlmAccount()
} catch (e: Exception) {
Timber.e(e, "## generateOneTimeKeys() : failed")
}
@ -205,7 +192,7 @@ internal class MXOlmDevice @Inject constructor(
try {
olmSession = OlmSession()
olmSession.initOutboundSession(olmAccount!!, theirIdentityKey, theirOneTimeKey)
olmSession.initOutboundSession(store.getOlmAccount(), theirIdentityKey, theirOneTimeKey)
val olmSessionWrapper = OlmSessionWrapper(olmSession, 0)
@ -245,7 +232,7 @@ internal class MXOlmDevice @Inject constructor(
try {
try {
olmSession = OlmSession()
olmSession.initInboundSessionFrom(olmAccount!!, theirDeviceIdentityKey, ciphertext)
olmSession.initInboundSessionFrom(store.getOlmAccount(), theirDeviceIdentityKey, ciphertext)
} catch (e: Exception) {
Timber.e(e, "## createInboundSession() : the session creation failed")
return null
@ -254,8 +241,8 @@ internal class MXOlmDevice @Inject constructor(
Timber.v("## createInboundSession() : sessionId: ${olmSession.sessionIdentifier()}")
try {
olmAccount!!.removeOneTimeKeys(olmSession)
store.storeAccount(olmAccount!!)
store.getOlmAccount().removeOneTimeKeys(olmSession)
store.saveOlmAccount()
} catch (e: Exception) {
Timber.e(e, "## createInboundSession() : removeOneTimeKeys failed")
}

View File

@ -49,7 +49,9 @@ internal interface IMXCryptoStore {
/**
* @return the olm account
*/
fun getAccount(): OlmAccount?
fun getOlmAccount(): OlmAccount
fun getOrCreateOlmAccount(): OlmAccount
/**
* Retrieve the known inbound group sessions.
@ -159,7 +161,7 @@ internal interface IMXCryptoStore {
*
* @param account the account to save
*/
fun storeAccount(account: OlmAccount)
fun saveOlmAccount()
/**
* Store a device for a user.

View File

@ -122,27 +122,7 @@ internal class RealmCryptoStore @Inject constructor(
.setRealmConfiguration(realmConfiguration)
.build()
/* ==========================================================================================
* Other data
* ========================================================================================== */
override fun hasData(): Boolean {
return doWithRealm(realmConfiguration) {
!it.isEmpty
// Check if there is a MetaData object
&& it.where<CryptoMetadataEntity>().count() > 0
}
}
override fun deleteStore() {
doRealmTransaction(realmConfiguration) {
it.deleteAll()
}
}
override fun open() {
realmLocker = Realm.getInstance(realmConfiguration)
init {
// Ensure CryptoMetadataEntity is inserted in DB
doRealmTransaction(realmConfiguration) { realm ->
var currentMetadata = realm.where<CryptoMetadataEntity>().findFirst()
@ -173,6 +153,27 @@ internal class RealmCryptoStore @Inject constructor(
}
}
}
/* ==========================================================================================
* Other data
* ========================================================================================== */
override fun hasData(): Boolean {
return doWithRealm(realmConfiguration) {
!it.isEmpty
// Check if there is a MetaData object
&& it.where<CryptoMetadataEntity>().count() > 0
}
}
override fun deleteStore() {
doRealmTransaction(realmConfiguration) {
it.deleteAll()
}
}
override fun open() {
realmLocker = Realm.getInstance(realmConfiguration)
}
override fun close() {
olmSessionsToRelease.forEach {
@ -203,20 +204,31 @@ internal class RealmCryptoStore @Inject constructor(
}?.deviceId ?: ""
}
override fun storeAccount(account: OlmAccount) {
olmAccount = account
override fun saveOlmAccount() {
doRealmTransaction(realmConfiguration) {
it.where<CryptoMetadataEntity>().findFirst()?.putOlmAccount(account)
it.where<CryptoMetadataEntity>().findFirst()?.putOlmAccount(olmAccount)
}
}
override fun getAccount(): OlmAccount? {
if (olmAccount == null) {
olmAccount = doRealmQueryAndCopy(realmConfiguration) { it.where<CryptoMetadataEntity>().findFirst() }?.getOlmAccount()
}
override fun getOlmAccount(): OlmAccount {
return olmAccount!!
}
return olmAccount
override fun getOrCreateOlmAccount(): OlmAccount {
doRealmTransaction(realmConfiguration) {
val metaData = it.where<CryptoMetadataEntity>().findFirst()
val existing = metaData!!.getOlmAccount()
if (existing == null) {
Timber.d("## Crypto Creating olm account")
val created = OlmAccount()
metaData.putOlmAccount(created)
olmAccount = created
} else {
Timber.d("## Crypto Access existing account")
olmAccount = existing
}
}
return olmAccount!!
}
override fun storeUserDevice(userId: String?, deviceInfo: CryptoDeviceInfo?) {

View File

@ -25,6 +25,7 @@ import im.vector.matrix.android.internal.network.executeRequest
import im.vector.matrix.android.internal.task.Task
import im.vector.matrix.android.internal.util.convertToUTF8
import org.greenrobot.eventbus.EventBus
import timber.log.Timber
import javax.inject.Inject
internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadResponse> {
@ -50,6 +51,8 @@ internal class DefaultUploadKeysTask @Inject constructor(
oneTimeKeys = params.oneTimeKeys
)
Timber.i("## Uploading device keys -> $body")
return executeRequest(eventBus) {
apiCall = if (encodedDeviceId.isBlank()) {
cryptoApi.uploadKeys(body)