mirror of
https://github.com/element-hq/element-android
synced 2024-11-28 21:48:50 +03:00
SoftLogout: Store the info that the token is not valid anymore for a faster startup
This commit is contained in:
parent
261b4be287
commit
a5af949c15
10 changed files with 77 additions and 10 deletions
|
@ -22,5 +22,6 @@ package im.vector.matrix.android.api.auth.data
|
||||||
*/
|
*/
|
||||||
data class SessionParams(
|
data class SessionParams(
|
||||||
val credentials: Credentials,
|
val credentials: Credentials,
|
||||||
val homeServerConnectionConfig: HomeServerConnectionConfig
|
val homeServerConnectionConfig: HomeServerConnectionConfig,
|
||||||
|
val isTokenValid: Boolean
|
||||||
)
|
)
|
||||||
|
|
|
@ -62,6 +62,11 @@ interface Session :
|
||||||
*/
|
*/
|
||||||
val sessionParams: SessionParams
|
val sessionParams: SessionParams
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The session is valid, i.e. it has a valid token so far
|
||||||
|
*/
|
||||||
|
val isOpenable: Boolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Useful shortcut to get access to the userId
|
* Useful shortcut to get access to the userId
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -60,7 +60,8 @@ internal class DefaultSessionCreator @Inject constructor(
|
||||||
?.also { Timber.d("Overriding identity server url to $it") }
|
?.also { Timber.d("Overriding identity server url to $it") }
|
||||||
?.let { Uri.parse(it) }
|
?.let { Uri.parse(it) }
|
||||||
?: homeServerConnectionConfig.identityServerUri
|
?: homeServerConnectionConfig.identityServerUri
|
||||||
))
|
),
|
||||||
|
isTokenValid = true)
|
||||||
|
|
||||||
sessionParamsStore.save(sessionParams)
|
sessionParamsStore.save(sessionParams)
|
||||||
return sessionManager.getOrCreateSession(sessionParams)
|
return sessionManager.getOrCreateSession(sessionParams)
|
||||||
|
|
|
@ -29,6 +29,8 @@ internal interface SessionParamsStore {
|
||||||
|
|
||||||
suspend fun save(sessionParams: SessionParams)
|
suspend fun save(sessionParams: SessionParams)
|
||||||
|
|
||||||
|
suspend fun setTokenInvalid(userId: String)
|
||||||
|
|
||||||
suspend fun updateCredentials(newCredentials: Credentials)
|
suspend fun updateCredentials(newCredentials: Credentials)
|
||||||
|
|
||||||
suspend fun delete(userId: String)
|
suspend fun delete(userId: String)
|
||||||
|
|
|
@ -24,7 +24,7 @@ internal class AuthRealmMigration : RealmMigration {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
// Current schema version
|
// Current schema version
|
||||||
const val SCHEMA_VERSION = 1L
|
const val SCHEMA_VERSION = 2L
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
|
||||||
|
@ -46,5 +46,14 @@ internal class AuthRealmMigration : RealmMigration {
|
||||||
.addField(PendingSessionEntityFields.IS_REGISTRATION_STARTED, Boolean::class.java)
|
.addField(PendingSessionEntityFields.IS_REGISTRATION_STARTED, Boolean::class.java)
|
||||||
.addField(PendingSessionEntityFields.CURRENT_THREE_PID_DATA_JSON, String::class.java)
|
.addField(PendingSessionEntityFields.CURRENT_THREE_PID_DATA_JSON, String::class.java)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (oldVersion <= 1) {
|
||||||
|
Timber.d("Step 1 -> 2")
|
||||||
|
Timber.d("Add boolean isTokenValid in SessionParamsEntity, with value true")
|
||||||
|
|
||||||
|
realm.schema.get("SessionParamsEntity")
|
||||||
|
?.addField(SessionParamsEntityFields.IS_TOKEN_VALID, Boolean::class.java)
|
||||||
|
?.transform { it.set(SessionParamsEntityFields.IS_TOKEN_VALID, true) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -76,6 +76,26 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun setTokenInvalid(userId: String) {
|
||||||
|
awaitTransaction(realmConfiguration) { realm ->
|
||||||
|
val currentSessionParams = realm
|
||||||
|
.where(SessionParamsEntity::class.java)
|
||||||
|
.equalTo(SessionParamsEntityFields.USER_ID, userId)
|
||||||
|
.findAll()
|
||||||
|
.firstOrNull()
|
||||||
|
|
||||||
|
if (currentSessionParams == null) {
|
||||||
|
// Should not happen
|
||||||
|
"Session param not found for user $userId"
|
||||||
|
.let { Timber.w(it) }
|
||||||
|
.also { error(it) }
|
||||||
|
} else {
|
||||||
|
currentSessionParams.isTokenValid = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
override suspend fun updateCredentials(newCredentials: Credentials) {
|
override suspend fun updateCredentials(newCredentials: Credentials) {
|
||||||
awaitTransaction(realmConfiguration) { realm ->
|
awaitTransaction(realmConfiguration) { realm ->
|
||||||
val currentSessionParams = realm
|
val currentSessionParams = realm
|
||||||
|
@ -92,7 +112,8 @@ internal class RealmSessionParamsStore @Inject constructor(private val mapper: S
|
||||||
.also { error(it) }
|
.also { error(it) }
|
||||||
} else {
|
} else {
|
||||||
val newSessionParams = currentSessionParams.copy(
|
val newSessionParams = currentSessionParams.copy(
|
||||||
credentials = newCredentials
|
credentials = newCredentials,
|
||||||
|
isTokenValid = true
|
||||||
)
|
)
|
||||||
|
|
||||||
val entity = mapper.map(newSessionParams)
|
val entity = mapper.map(newSessionParams)
|
||||||
|
|
|
@ -22,5 +22,8 @@ import io.realm.annotations.PrimaryKey
|
||||||
internal open class SessionParamsEntity(
|
internal open class SessionParamsEntity(
|
||||||
@PrimaryKey var userId: String = "",
|
@PrimaryKey var userId: String = "",
|
||||||
var credentialsJson: String = "",
|
var credentialsJson: String = "",
|
||||||
var homeServerConnectionConfigJson: String = ""
|
var homeServerConnectionConfigJson: String = "",
|
||||||
|
// Set to false when the token is invalid and the user has been soft logged out
|
||||||
|
// In case of hard logout, this object in deleted from DB
|
||||||
|
var isTokenValid: Boolean = true
|
||||||
) : RealmObject()
|
) : RealmObject()
|
||||||
|
|
|
@ -36,7 +36,7 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
|
||||||
if (credentials == null || homeServerConnectionConfig == null) {
|
if (credentials == null || homeServerConnectionConfig == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return SessionParams(credentials, homeServerConnectionConfig)
|
return SessionParams(credentials, homeServerConnectionConfig, entity.isTokenValid)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun map(sessionParams: SessionParams?): SessionParamsEntity? {
|
fun map(sessionParams: SessionParams?): SessionParamsEntity? {
|
||||||
|
@ -48,6 +48,10 @@ internal class SessionParamsMapper @Inject constructor(moshi: Moshi) {
|
||||||
if (credentialsJson == null || homeServerConnectionConfigJson == null) {
|
if (credentialsJson == null || homeServerConnectionConfigJson == null) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
return SessionParamsEntity(sessionParams.credentials.userId, credentialsJson, homeServerConnectionConfigJson)
|
return SessionParamsEntity(
|
||||||
|
sessionParams.credentials.userId,
|
||||||
|
credentialsJson,
|
||||||
|
homeServerConnectionConfigJson,
|
||||||
|
sessionParams.isTokenValid)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,10 +42,14 @@ import im.vector.matrix.android.api.session.signout.SignOutService
|
||||||
import im.vector.matrix.android.api.session.sync.FilterService
|
import im.vector.matrix.android.api.session.sync.FilterService
|
||||||
import im.vector.matrix.android.api.session.sync.SyncState
|
import im.vector.matrix.android.api.session.sync.SyncState
|
||||||
import im.vector.matrix.android.api.session.user.UserService
|
import im.vector.matrix.android.api.session.user.UserService
|
||||||
|
import im.vector.matrix.android.internal.auth.SessionParamsStore
|
||||||
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
import im.vector.matrix.android.internal.crypto.DefaultCryptoService
|
||||||
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
import im.vector.matrix.android.internal.database.LiveEntityObserver
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
import im.vector.matrix.android.internal.session.sync.job.SyncThread
|
||||||
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
import im.vector.matrix.android.internal.session.sync.job.SyncWorker
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.GlobalScope
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
import org.greenrobot.eventbus.EventBus
|
import org.greenrobot.eventbus.EventBus
|
||||||
import org.greenrobot.eventbus.Subscribe
|
import org.greenrobot.eventbus.Subscribe
|
||||||
import org.greenrobot.eventbus.ThreadMode
|
import org.greenrobot.eventbus.ThreadMode
|
||||||
|
@ -72,6 +76,7 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||||
private val secureStorageService: Lazy<SecureStorageService>,
|
private val secureStorageService: Lazy<SecureStorageService>,
|
||||||
private val syncThreadProvider: Provider<SyncThread>,
|
private val syncThreadProvider: Provider<SyncThread>,
|
||||||
private val contentUrlResolver: ContentUrlResolver,
|
private val contentUrlResolver: ContentUrlResolver,
|
||||||
|
private val sessionParamsStore: SessionParamsStore,
|
||||||
private val contentUploadProgressTracker: ContentUploadStateTracker,
|
private val contentUploadProgressTracker: ContentUploadStateTracker,
|
||||||
private val initialSyncProgressService: Lazy<InitialSyncProgressService>,
|
private val initialSyncProgressService: Lazy<InitialSyncProgressService>,
|
||||||
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>)
|
private val homeServerCapabilitiesService: Lazy<HomeServerCapabilitiesService>)
|
||||||
|
@ -94,6 +99,9 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||||
|
|
||||||
private var syncThread: SyncThread? = null
|
private var syncThread: SyncThread? = null
|
||||||
|
|
||||||
|
override val isOpenable: Boolean
|
||||||
|
get() = sessionParamsStore.get(myUserId)?.isTokenValid ?: false
|
||||||
|
|
||||||
@MainThread
|
@MainThread
|
||||||
override fun open() {
|
override fun open() {
|
||||||
assertMainThread()
|
assertMainThread()
|
||||||
|
@ -171,6 +179,14 @@ internal class DefaultSession @Inject constructor(override val sessionParams: Se
|
||||||
|
|
||||||
@Subscribe(threadMode = ThreadMode.MAIN)
|
@Subscribe(threadMode = ThreadMode.MAIN)
|
||||||
fun onGlobalError(globalError: GlobalError) {
|
fun onGlobalError(globalError: GlobalError) {
|
||||||
|
if (globalError is GlobalError.InvalidToken
|
||||||
|
&& globalError.softLogout) {
|
||||||
|
// Mark the token has invalid
|
||||||
|
GlobalScope.launch(Dispatchers.IO) {
|
||||||
|
sessionParamsStore.setTokenInvalid(myUserId)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
sessionListeners.dispatchGlobalError(globalError)
|
sessionListeners.dispatchGlobalError(globalError)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -169,9 +169,14 @@ class MainActivity : VectorBaseActivity() {
|
||||||
// the homeserver has invalidated the token (password changed, device deleted, other security reason
|
// the homeserver has invalidated the token (password changed, device deleted, other security reason
|
||||||
SignedOutActivity.newIntent(this)
|
SignedOutActivity.newIntent(this)
|
||||||
sessionHolder.hasActiveSession() ->
|
sessionHolder.hasActiveSession() ->
|
||||||
// We have a session. In case of soft logout (i.e. restart of the app after a soft logout)
|
// We have a session.
|
||||||
// the app will try to sync and will reenter the soft logout use case
|
// Check it can be opened
|
||||||
|
if(sessionHolder.getActiveSession().isOpenable) {
|
||||||
HomeActivity.newIntent(this)
|
HomeActivity.newIntent(this)
|
||||||
|
} else {
|
||||||
|
// The token is still invalid
|
||||||
|
SoftLogoutActivity.newIntent(this)
|
||||||
|
}
|
||||||
else ->
|
else ->
|
||||||
// First start, or no active session
|
// First start, or no active session
|
||||||
LoginActivity.newIntent(this, null)
|
LoginActivity.newIntent(this, null)
|
||||||
|
|
Loading…
Reference in a new issue