Fix session verification incorrectly displaying as 'not verified' when the user opened the app with no network connection.
It turns out `encryptionService.verificationState()` runs a network request that will cause a deadlock when it fails. Also fixed another deadlock that caused the screen to remain blank sometimes after logging in, because DataStore got stuck when checking the `skipVerification` state for some reason I don't fully understand.
This commit is contained in:
parent
a7a2b4727f
commit
16545ce60e
2 changed files with 45 additions and 12 deletions
|
|
@ -119,8 +119,14 @@ class DefaultFtueService @Inject constructor(
|
||||||
emit(SessionVerifiedStatus.NotVerified)
|
emit(SessionVerifiedStatus.NotVerified)
|
||||||
}
|
}
|
||||||
.first()
|
.first()
|
||||||
val skipVerification = suspend { sessionPreferencesStore.isSessionVerificationSkipped().first() }
|
// For some obscure reason we need to call this *before* we check the `readyVerifiedSessionStatus`, otherwise there's a deadlock
|
||||||
return readyVerifiedSessionStatus == SessionVerifiedStatus.NotVerified && !skipVerification()
|
// It seems like a DataStore bug
|
||||||
|
val skipVerification = canSkipVerification()
|
||||||
|
return readyVerifiedSessionStatus == SessionVerifiedStatus.NotVerified && !skipVerification
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun canSkipVerification(): Boolean {
|
||||||
|
return sessionPreferencesStore.isSessionVerificationSkipped().first()
|
||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun needsAnalyticsOptIn(): Boolean {
|
private suspend fun needsAnalyticsOptIn(): Boolean {
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ class RustSessionVerificationService(
|
||||||
private val verificationStateListenerTaskHandle = encryptionService.verificationStateListener(object : VerificationStateListener {
|
private val verificationStateListenerTaskHandle = encryptionService.verificationStateListener(object : VerificationStateListener {
|
||||||
override fun onUpdate(status: VerificationState) {
|
override fun onUpdate(status: VerificationState) {
|
||||||
Timber.d("New verification state: $status")
|
Timber.d("New verification state: $status")
|
||||||
updateVerificationStatus(status)
|
sessionCoroutineScope.launch { updateVerificationStatus() }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -70,7 +70,7 @@ class RustSessionVerificationService(
|
||||||
override fun onUpdate(status: RecoveryState) {
|
override fun onUpdate(status: RecoveryState) {
|
||||||
Timber.d("New recovery state: $status")
|
Timber.d("New recovery state: $status")
|
||||||
// We could check the `RecoveryState`, but it's easier to just use the verification state directly
|
// We could check the `RecoveryState`, but it's easier to just use the verification state directly
|
||||||
updateVerificationStatus(encryptionService.verificationState())
|
sessionCoroutineScope.launch { updateVerificationStatus() }
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
@ -92,15 +92,16 @@ class RustSessionVerificationService(
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// Update initial state in case sliding sync isn't ready
|
// Update initial state in case sliding sync isn't ready
|
||||||
updateVerificationStatus(encryptionService.verificationState())
|
sessionCoroutineScope.launch { updateVerificationStatus() }
|
||||||
|
|
||||||
isReady.onEach { isReady ->
|
isReady.onEach { isReady ->
|
||||||
if (isReady) {
|
if (isReady) {
|
||||||
Timber.d("Starting verification service")
|
Timber.d("Starting verification service")
|
||||||
// Immediate status update
|
// Immediate status update
|
||||||
updateVerificationStatus(encryptionService.verificationState())
|
updateVerificationStatus()
|
||||||
} else {
|
} else {
|
||||||
Timber.d("Stopping verification service")
|
Timber.d("Stopping verification service")
|
||||||
|
updateVerificationStatus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.launchIn(sessionCoroutineScope)
|
.launchIn(sessionCoroutineScope)
|
||||||
|
|
@ -161,8 +162,9 @@ class RustSessionVerificationService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.onSuccess {
|
.onSuccess {
|
||||||
updateVerificationStatus(VerificationState.VERIFIED)
|
// Order here is important, first set the flow state as finished, then update the verification status
|
||||||
_verificationFlowState.value = VerificationFlowState.Finished
|
_verificationFlowState.value = VerificationFlowState.Finished
|
||||||
|
updateVerificationStatus()
|
||||||
}
|
}
|
||||||
.onFailure {
|
.onFailure {
|
||||||
Timber.e(it, "Verification finished, but the Rust SDK still reports the session as unverified.")
|
Timber.e(it, "Verification finished, but the Rust SDK still reports the session as unverified.")
|
||||||
|
|
@ -200,11 +202,36 @@ class RustSessionVerificationService(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateVerificationStatus(verificationState: VerificationState) {
|
private suspend fun updateVerificationStatus() {
|
||||||
_sessionVerifiedStatus.value = when (verificationState) {
|
if (verificationFlowState.value == VerificationFlowState.Finished) {
|
||||||
VerificationState.UNKNOWN -> SessionVerifiedStatus.Unknown
|
// Calling `encryptionService.verificationState()` performs a network call and it will deadlock if there is no network
|
||||||
VerificationState.VERIFIED -> SessionVerifiedStatus.Verified
|
// So we need to check that *only* if we know there is network connection, which is the case when the verification flow just finished
|
||||||
VerificationState.UNVERIFIED -> SessionVerifiedStatus.NotVerified
|
Timber.d("Updating verification status: flow just finished")
|
||||||
|
runCatching {
|
||||||
|
encryptionService.waitForE2eeInitializationTasks()
|
||||||
|
}.onSuccess {
|
||||||
|
_sessionVerifiedStatus.value = when (encryptionService.verificationState()) {
|
||||||
|
VerificationState.UNKNOWN -> SessionVerifiedStatus.Unknown
|
||||||
|
VerificationState.VERIFIED -> SessionVerifiedStatus.Verified
|
||||||
|
VerificationState.UNVERIFIED -> SessionVerifiedStatus.NotVerified
|
||||||
|
}
|
||||||
|
Timber.d("New verification status: ${_sessionVerifiedStatus.value}")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Otherwise, just check the current verification status from the session verification controller instead
|
||||||
|
Timber.d("Updating verification status: flow is pending or was finished some time ago")
|
||||||
|
runCatching {
|
||||||
|
if (!this@RustSessionVerificationService::verificationController.isInitialized) {
|
||||||
|
verificationController = client.getSessionVerificationController()
|
||||||
|
verificationController.setDelegate(this@RustSessionVerificationService)
|
||||||
|
}
|
||||||
|
_sessionVerifiedStatus.value = if (verificationController.isVerified()) {
|
||||||
|
SessionVerifiedStatus.Verified
|
||||||
|
} else {
|
||||||
|
SessionVerifiedStatus.NotVerified
|
||||||
|
}
|
||||||
|
Timber.d("New verification status: ${_sessionVerifiedStatus.value}")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue