Properly unregister from the ntfy app when the user logs out.

This commit is contained in:
Benoit Marty 2024-11-15 12:31:23 +01:00 committed by Benoit Marty
parent 022cd93653
commit 7a7b5d2dd0
15 changed files with 110 additions and 77 deletions

View file

@ -15,21 +15,14 @@ import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.pushstore.api.UserPushStore
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject
@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class, boundType = UserPushStoreFactory::class)
@ContributesBinding(AppScope::class)
class DefaultUserPushStoreFactory @Inject constructor(
@ApplicationContext private val context: Context,
private val sessionObserver: SessionObserver,
) : UserPushStoreFactory, SessionListener {
init {
observeSessions()
}
) : UserPushStoreFactory {
// We can have only one class accessing a single data store, so keep a cache of them.
private val cache = ConcurrentHashMap<SessionId, UserPushStore>()
override fun getOrCreate(userId: SessionId): UserPushStore {
@ -40,17 +33,4 @@ class DefaultUserPushStoreFactory @Inject constructor(
)
}
}
private fun observeSessions() {
sessionObserver.addListener(this)
}
override suspend fun onSessionCreated(userId: String) {
// Nothing to do
}
override suspend fun onSessionDeleted(userId: String) {
// Delete the store
getOrCreate(SessionId(userId)).reset()
}
}

View file

@ -9,26 +9,17 @@ package io.element.android.libraries.pushstore.impl.clientsecret
import com.squareup.anvil.annotations.ContributesBinding
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.SingleIn
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecret
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecretFactory
import io.element.android.libraries.pushstore.api.clientsecret.PushClientSecretStore
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
import javax.inject.Inject
@SingleIn(AppScope::class)
@ContributesBinding(AppScope::class, boundType = PushClientSecret::class)
@ContributesBinding(AppScope::class)
class DefaultPushClientSecret @Inject constructor(
private val pushClientSecretFactory: PushClientSecretFactory,
private val pushClientSecretStore: PushClientSecretStore,
private val sessionObserver: SessionObserver,
) : PushClientSecret, SessionListener {
init {
observeSessions()
}
) : PushClientSecret {
override suspend fun getSecretForUser(userId: SessionId): String {
val existingSecret = pushClientSecretStore.getSecret(userId)
if (existingSecret != null) {
@ -42,17 +33,4 @@ class DefaultPushClientSecret @Inject constructor(
override suspend fun getUserIdFromSecret(clientSecret: String): SessionId? {
return pushClientSecretStore.getUserIdFromSecret(clientSecret)
}
private fun observeSessions() {
sessionObserver.addListener(this)
}
override suspend fun onSessionCreated(userId: String) {
// Nothing to do
}
override suspend fun onSessionDeleted(userId: String) {
// Delete the secret
pushClientSecretStore.resetSecret(SessionId(userId))
}
}

View file

@ -10,7 +10,6 @@ package io.element.android.libraries.pushstore.impl.clientsecret
import com.google.common.truth.Truth.assertThat
import io.element.android.libraries.matrix.api.core.SessionId
import io.element.android.libraries.pushstore.test.userpushstore.clientsecret.InMemoryPushClientSecretStore
import io.element.android.libraries.sessionstorage.test.observer.NoOpSessionObserver
import kotlinx.coroutines.test.runTest
import org.junit.Test
@ -24,11 +23,10 @@ internal class DefaultPushClientSecretTest {
fun test() = runTest {
val factory = FakePushClientSecretFactory()
val store = InMemoryPushClientSecretStore()
val sut = DefaultPushClientSecret(factory, store, NoOpSessionObserver())
val sut = DefaultPushClientSecret(factory, store)
val secret0 = factory.getSecretForUser(0)
val secret1 = factory.getSecretForUser(1)
val secret2 = factory.getSecretForUser(2)
assertThat(store.getSecrets()).isEmpty()
assertThat(sut.getUserIdFromSecret(secret0)).isNull()
@ -48,16 +46,10 @@ internal class DefaultPushClientSecretTest {
// Unknown secret
assertThat(sut.getUserIdFromSecret(A_UNKNOWN_SECRET)).isNull()
// User signs out
sut.onSessionDeleted(A_USER_ID_0.value)
assertThat(store.getSecrets()).hasSize(1)
// Create a new secret after reset
assertThat(sut.getSecretForUser(A_USER_ID_0)).isEqualTo(secret2)
// Check the store content
assertThat(store.getSecrets()).isEqualTo(
mapOf(
A_USER_ID_0 to secret2,
A_USER_ID_0 to secret0,
A_USER_ID_1 to secret1,
)
)