mirror of
https://github.com/element-hq/element-android
synced 2024-11-24 18:35:40 +03:00
Merge pull request #1172 from vector-im/feature/ensure_olm_account_unicity
Feature/ensure olm account unicity
This commit is contained in:
commit
1d46b523b9
5 changed files with 67 additions and 62 deletions
|
@ -10,6 +10,7 @@ Improvements 🙌:
|
||||||
|
|
||||||
Bugfix 🐛:
|
Bugfix 🐛:
|
||||||
- Missing avatar/displayname after verification request message (#841)
|
- 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)
|
- RiotX can't restore cross signing keys saved by web in SSSS (#1174)
|
||||||
|
|
||||||
Translations 🗣:
|
Translations 🗣:
|
||||||
|
|
|
@ -59,9 +59,6 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
var deviceEd25519Key: String? = null
|
var deviceEd25519Key: String? = null
|
||||||
private set
|
private set
|
||||||
|
|
||||||
// The OLM lib account instance.
|
|
||||||
private var olmAccount: OlmAccount? = null
|
|
||||||
|
|
||||||
// The OLM lib utility instance.
|
// The OLM lib utility instance.
|
||||||
private var olmUtility: OlmUtility? = null
|
private var olmUtility: OlmUtility? = null
|
||||||
|
|
||||||
|
@ -86,20 +83,11 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Retrieve the account from the store
|
// Retrieve the account from the store
|
||||||
olmAccount = store.getAccount()
|
|
||||||
|
|
||||||
if (null == olmAccount) {
|
|
||||||
Timber.v("MXOlmDevice : create a new olm account")
|
|
||||||
// Else, create it
|
|
||||||
try {
|
try {
|
||||||
olmAccount = OlmAccount()
|
store.getOrCreateOlmAccount()
|
||||||
store.storeAccount(olmAccount!!)
|
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "MXOlmDevice : cannot initialize olmAccount")
|
Timber.e(e, "MXOlmDevice : cannot initialize olmAccount")
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Timber.v("MXOlmDevice : use an existing account")
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
olmUtility = OlmUtility()
|
olmUtility = OlmUtility()
|
||||||
|
@ -109,13 +97,13 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deviceCurve25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
|
deviceCurve25519Key = store.getOlmAccount().identityKeys()[OlmAccount.JSON_KEY_IDENTITY_KEY]
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_IDENTITY_KEY} with error")
|
Timber.e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_IDENTITY_KEY} with error")
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
deviceEd25519Key = olmAccount!!.identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
|
deviceEd25519Key = store.getOlmAccount().identityKeys()[OlmAccount.JSON_KEY_FINGER_PRINT_KEY]
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## MXOlmDevice : cannot find ${OlmAccount.JSON_KEY_FINGER_PRINT_KEY} with error")
|
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>>? {
|
fun getOneTimeKeys(): Map<String, Map<String, String>>? {
|
||||||
try {
|
try {
|
||||||
return olmAccount!!.oneTimeKeys()
|
return store.getOlmAccount().oneTimeKeys()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## getOneTimeKeys() : failed")
|
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.
|
* @return The maximum number of one-time keys the olm account can store.
|
||||||
*/
|
*/
|
||||||
fun getMaxNumberOfOneTimeKeys(): Long {
|
fun getMaxNumberOfOneTimeKeys(): Long {
|
||||||
return olmAccount?.maxOneTimeKeys() ?: -1
|
return store.getOlmAccount().maxOneTimeKeys()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Release the instance
|
* Release the instance
|
||||||
*/
|
*/
|
||||||
fun release() {
|
fun release() {
|
||||||
olmAccount?.releaseAccount()
|
|
||||||
olmUtility?.releaseUtility()
|
olmUtility?.releaseUtility()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -157,7 +144,7 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
*/
|
*/
|
||||||
fun signMessage(message: String): String? {
|
fun signMessage(message: String): String? {
|
||||||
try {
|
try {
|
||||||
return olmAccount!!.signMessage(message)
|
return store.getOlmAccount().signMessage(message)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## signMessage() : failed")
|
Timber.e(e, "## signMessage() : failed")
|
||||||
}
|
}
|
||||||
|
@ -170,8 +157,8 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
*/
|
*/
|
||||||
fun markKeysAsPublished() {
|
fun markKeysAsPublished() {
|
||||||
try {
|
try {
|
||||||
olmAccount!!.markOneTimeKeysAsPublished()
|
store.getOlmAccount().markOneTimeKeysAsPublished()
|
||||||
store.storeAccount(olmAccount!!)
|
store.saveOlmAccount()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## markKeysAsPublished() : failed")
|
Timber.e(e, "## markKeysAsPublished() : failed")
|
||||||
}
|
}
|
||||||
|
@ -184,8 +171,8 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
*/
|
*/
|
||||||
fun generateOneTimeKeys(numKeys: Int) {
|
fun generateOneTimeKeys(numKeys: Int) {
|
||||||
try {
|
try {
|
||||||
olmAccount!!.generateOneTimeKeys(numKeys)
|
store.getOlmAccount().generateOneTimeKeys(numKeys)
|
||||||
store.storeAccount(olmAccount!!)
|
store.saveOlmAccount()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## generateOneTimeKeys() : failed")
|
Timber.e(e, "## generateOneTimeKeys() : failed")
|
||||||
}
|
}
|
||||||
|
@ -205,7 +192,7 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
|
|
||||||
try {
|
try {
|
||||||
olmSession = OlmSession()
|
olmSession = OlmSession()
|
||||||
olmSession.initOutboundSession(olmAccount!!, theirIdentityKey, theirOneTimeKey)
|
olmSession.initOutboundSession(store.getOlmAccount(), theirIdentityKey, theirOneTimeKey)
|
||||||
|
|
||||||
val olmSessionWrapper = OlmSessionWrapper(olmSession, 0)
|
val olmSessionWrapper = OlmSessionWrapper(olmSession, 0)
|
||||||
|
|
||||||
|
@ -245,7 +232,7 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
try {
|
try {
|
||||||
try {
|
try {
|
||||||
olmSession = OlmSession()
|
olmSession = OlmSession()
|
||||||
olmSession.initInboundSessionFrom(olmAccount!!, theirDeviceIdentityKey, ciphertext)
|
olmSession.initInboundSessionFrom(store.getOlmAccount(), theirDeviceIdentityKey, ciphertext)
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## createInboundSession() : the session creation failed")
|
Timber.e(e, "## createInboundSession() : the session creation failed")
|
||||||
return null
|
return null
|
||||||
|
@ -254,8 +241,8 @@ internal class MXOlmDevice @Inject constructor(
|
||||||
Timber.v("## createInboundSession() : sessionId: ${olmSession.sessionIdentifier()}")
|
Timber.v("## createInboundSession() : sessionId: ${olmSession.sessionIdentifier()}")
|
||||||
|
|
||||||
try {
|
try {
|
||||||
olmAccount!!.removeOneTimeKeys(olmSession)
|
store.getOlmAccount().removeOneTimeKeys(olmSession)
|
||||||
store.storeAccount(olmAccount!!)
|
store.saveOlmAccount()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.e(e, "## createInboundSession() : removeOneTimeKeys failed")
|
Timber.e(e, "## createInboundSession() : removeOneTimeKeys failed")
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,9 @@ internal interface IMXCryptoStore {
|
||||||
/**
|
/**
|
||||||
* @return the olm account
|
* @return the olm account
|
||||||
*/
|
*/
|
||||||
fun getAccount(): OlmAccount?
|
fun getOlmAccount(): OlmAccount
|
||||||
|
|
||||||
|
fun getOrCreateOlmAccount(): OlmAccount
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieve the known inbound group sessions.
|
* Retrieve the known inbound group sessions.
|
||||||
|
@ -159,7 +161,7 @@ internal interface IMXCryptoStore {
|
||||||
*
|
*
|
||||||
* @param account the account to save
|
* @param account the account to save
|
||||||
*/
|
*/
|
||||||
fun storeAccount(account: OlmAccount)
|
fun saveOlmAccount()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Store a device for a user.
|
* Store a device for a user.
|
||||||
|
|
|
@ -122,27 +122,7 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
.setRealmConfiguration(realmConfiguration)
|
.setRealmConfiguration(realmConfiguration)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
/* ==========================================================================================
|
init {
|
||||||
* 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)
|
|
||||||
|
|
||||||
// Ensure CryptoMetadataEntity is inserted in DB
|
// Ensure CryptoMetadataEntity is inserted in DB
|
||||||
doRealmTransaction(realmConfiguration) { realm ->
|
doRealmTransaction(realmConfiguration) { realm ->
|
||||||
var currentMetadata = realm.where<CryptoMetadataEntity>().findFirst()
|
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() {
|
override fun close() {
|
||||||
olmSessionsToRelease.forEach {
|
olmSessionsToRelease.forEach {
|
||||||
|
@ -203,20 +204,31 @@ internal class RealmCryptoStore @Inject constructor(
|
||||||
}?.deviceId ?: ""
|
}?.deviceId ?: ""
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun storeAccount(account: OlmAccount) {
|
override fun saveOlmAccount() {
|
||||||
olmAccount = account
|
|
||||||
|
|
||||||
doRealmTransaction(realmConfiguration) {
|
doRealmTransaction(realmConfiguration) {
|
||||||
it.where<CryptoMetadataEntity>().findFirst()?.putOlmAccount(account)
|
it.where<CryptoMetadataEntity>().findFirst()?.putOlmAccount(olmAccount)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun getAccount(): OlmAccount? {
|
override fun getOlmAccount(): OlmAccount {
|
||||||
if (olmAccount == null) {
|
return olmAccount!!
|
||||||
olmAccount = doRealmQueryAndCopy(realmConfiguration) { it.where<CryptoMetadataEntity>().findFirst() }?.getOlmAccount()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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?) {
|
override fun storeUserDevice(userId: String?, deviceInfo: CryptoDeviceInfo?) {
|
||||||
|
|
|
@ -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.task.Task
|
||||||
import im.vector.matrix.android.internal.util.convertToUTF8
|
import im.vector.matrix.android.internal.util.convertToUTF8
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadResponse> {
|
internal interface UploadKeysTask : Task<UploadKeysTask.Params, KeysUploadResponse> {
|
||||||
|
@ -50,6 +51,8 @@ internal class DefaultUploadKeysTask @Inject constructor(
|
||||||
oneTimeKeys = params.oneTimeKeys
|
oneTimeKeys = params.oneTimeKeys
|
||||||
)
|
)
|
||||||
|
|
||||||
|
Timber.i("## Uploading device keys -> $body")
|
||||||
|
|
||||||
return executeRequest(eventBus) {
|
return executeRequest(eventBus) {
|
||||||
apiCall = if (encodedDeviceId.isBlank()) {
|
apiCall = if (encodedDeviceId.isBlank()) {
|
||||||
cryptoApi.uploadKeys(body)
|
cryptoApi.uploadKeys(body)
|
||||||
|
|
Loading…
Reference in a new issue