summaryrefslogtreecommitdiffhomepage
path: root/android/app/src/main
diff options
context:
space:
mode:
authorDavid Göransson <david.goransson90@gmail.com>2023-12-14 16:23:09 +0100
committerAlbin <albin@mullvad.net>2023-12-14 16:54:21 +0100
commitf33b1f76eac937b579ef589cc047da8f3421f630 (patch)
tree89e54908a6c5f7162813213bec00bfa425e521a0 /android/app/src/main
parent0d4451264d129bc6bcc8ae30bf12dc807f8ab3bc (diff)
downloadmullvadvpn-f33b1f76eac937b579ef589cc047da8f3421f630.tar.xz
mullvadvpn-f33b1f76eac937b579ef589cc047da8f3421f630.zip
Add OutOfTimeUseCase
Diffstat (limited to 'android/app/src/main')
-rw-r--r--android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt77
1 files changed, 77 insertions, 0 deletions
diff --git a/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt
new file mode 100644
index 0000000000..ba7ce83172
--- /dev/null
+++ b/android/app/src/main/kotlin/net/mullvad/mullvadvpn/usecase/OutOfTimeUseCase.kt
@@ -0,0 +1,77 @@
+package net.mullvad.mullvadvpn.usecase
+
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flow
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.onStart
+import net.mullvad.mullvadvpn.lib.ipc.Event
+import net.mullvad.mullvadvpn.lib.ipc.MessageHandler
+import net.mullvad.mullvadvpn.lib.ipc.events
+import net.mullvad.mullvadvpn.model.AccountExpiry
+import net.mullvad.mullvadvpn.model.TunnelState
+import net.mullvad.mullvadvpn.repository.AccountRepository
+import net.mullvad.talpid.tunnel.ErrorStateCause
+import org.joda.time.DateTime
+
+const val accountRefreshIntervalMillis = 60L * 1000L // 1 minute
+const val bufferTimeMillis = 60L * 1000L // 1 minute
+
+class OutOfTimeUseCase(
+ private val repository: AccountRepository,
+ private val messageHandler: MessageHandler
+) {
+
+ fun isOutOfTime(): Flow<Boolean?> =
+ combine(pastAccountExpiry(), isTunnelBlockedBecauseOutOfTime()) {
+ accountExpiryHasPast,
+ tunnelOutOfTime ->
+ reduce(accountExpiryHasPast, tunnelOutOfTime)
+ }
+ .distinctUntilChanged()
+
+ private fun reduce(vararg outOfTimeProperty: Boolean?): Boolean? =
+ when {
+ // If any advertises as out of time
+ outOfTimeProperty.any { it == true } -> true
+ // If all advertise as not out of time
+ outOfTimeProperty.all { it == false } -> false
+ // If some are unknown
+ else -> null
+ }
+
+ private fun isTunnelBlockedBecauseOutOfTime() =
+ messageHandler
+ .events<Event.TunnelStateChange>()
+ .map { it.tunnelState.isTunnelErrorStateDueToExpiredAccount() }
+ .onStart { emit(false) }
+
+ private fun TunnelState.isTunnelErrorStateDueToExpiredAccount(): Boolean {
+ return ((this as? TunnelState.Error)?.errorState?.cause as? ErrorStateCause.AuthFailed)
+ ?.isCausedByExpiredAccount()
+ ?: false
+ }
+
+ private fun pastAccountExpiry(): Flow<Boolean?> =
+ combine(
+ repository.accountExpiryState.map {
+ if (it is AccountExpiry.Available) {
+ it.date()
+ } else {
+ null
+ }
+ },
+ timeFlow()
+ ) { expiryDate, time ->
+ expiryDate?.isBefore(time.plus(bufferTimeMillis))
+ }
+
+ private fun timeFlow() = flow {
+ while (true) {
+ emit(DateTime.now())
+ delay(accountRefreshIntervalMillis)
+ }
+ }
+}