PM-24688: Use the realtime elapse time to determine vault lock timeouts (#5684)

This commit is contained in:
David Perez authored and GitHub committed 2025-08-13 15:04:19 +00:00
1 parent 1e2bc4aa70
commit 3ed63ef5eb
9 files changed
+55 -6

No files matched your search

@@ -3,6 +3,8 @@ package com.x8bit.bitwarden.data.platform.manager.di
import android.app.Application
import android.content.Context
import androidx.core.content.getSystemService
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import com.bitwarden.core.data.manager.realtime.RealtimeManagerImpl
import com.bitwarden.core.data.manager.toast.ToastManager
import com.bitwarden.core.data.manager.toast.ToastManagerImpl
import com.bitwarden.data.manager.DispatcherManager
@@ -198,6 +200,10 @@ object PlatformManagerModule {
toastManager = toastManager,
)
@Provides
@Singleton
fun provideRealtimeManager(): RealtimeManager = RealtimeManagerImpl()
@Provides
@Singleton
fun provideToastManager(
@@ -7,6 +7,7 @@ import android.content.IntentFilter
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoMethod
import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import com.bitwarden.core.data.repository.util.bufferedMutableSharedFlow
import com.bitwarden.core.data.util.asSuccess
import com.bitwarden.core.data.util.concurrentMapOf
@@ -77,6 +78,7 @@ private const val MAXIMUM_INVALID_UNLOCK_ATTEMPTS = 5
@Suppress("TooManyFunctions", "LongParameterList")
class VaultLockManagerImpl(
private val clock: Clock,
private val realtimeManager: RealtimeManager,
private val authDiskSource: AuthDiskSource,
private val authSdkSource: AuthSdkSource,
private val vaultSdkSource: VaultSdkSource,
@@ -613,7 +615,7 @@ class VaultLockManagerImpl(
handleTimeoutAction(userId = userId, vaultTimeoutAction = vaultTimeoutAction)
},
vaultTimeoutAction = vaultTimeoutAction,
startTimeMs = clock.millis(),
startTimeMs = realtimeManager.elapsedRealtimeMs,
durationMs = delayMs,
)
}
@@ -674,11 +676,12 @@ class VaultLockManagerImpl(
private inner class ScreenStateBroadcastReceiver : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
userIdTimerJobMap.map { (userId, data) ->
val durationSoFarMs = (realtimeManager.elapsedRealtimeMs - data.startTimeMs)
.coerceAtLeast(minimumValue = 0L)
handleTimeoutActionWithDelay(
userId = userId,
vaultTimeoutAction = data.vaultTimeoutAction,
delayMs = data.durationMs - (clock.millis() - data.startTimeMs)
.coerceAtLeast(minimumValue = 0L),
delayMs = data.durationMs - durationSoFarMs,
)
}
}
@@ -1,6 +1,7 @@
package com.x8bit.bitwarden.data.vault.manager.di
import android.content.Context
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import com.bitwarden.data.manager.DispatcherManager
import com.bitwarden.network.service.CiphersService
import com.bitwarden.network.service.DownloadService
@@ -73,6 +74,7 @@ object VaultManagerModule {
fun provideVaultLockManager(
@ApplicationContext context: Context,
clock: Clock,
realtimeManager: RealtimeManager,
authDiskSource: AuthDiskSource,
authSdkSource: AuthSdkSource,
vaultSdkSource: VaultSdkSource,
@@ -85,6 +87,7 @@ object VaultManagerModule {
VaultLockManagerImpl(
context = context,
clock = clock,
realtimeManager = realtimeManager,
authDiskSource = authDiskSource,
authSdkSource = authSdkSource,
vaultSdkSource = vaultSdkSource,
@@ -8,6 +8,7 @@ import app.cash.turbine.test
import com.bitwarden.core.InitOrgCryptoRequest
import com.bitwarden.core.InitUserCryptoMethod
import com.bitwarden.core.InitUserCryptoRequest
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import com.bitwarden.core.data.util.asFailure
import com.bitwarden.core.data.util.asSuccess
import com.bitwarden.crypto.HashPurpose
@@ -100,10 +101,14 @@ class VaultLockManagerTest {
}
private val testDispatcher = UnconfinedTestDispatcher()
private val fakeDispatcherManager = FakeDispatcherManager(unconfined = testDispatcher)
private val realtimeManager: RealtimeManager = mockk {
every { elapsedRealtimeMs } returns FIXED_CLOCK.millis()
}
private val vaultLockManager: VaultLockManager = VaultLockManagerImpl(
context = context,
clock = FIXED_CLOCK,
realtimeManager = realtimeManager,
authDiskSource = fakeAuthDiskSource,
authSdkSource = authSdkSource,
vaultSdkSource = vaultSdkSource,
@@ -1,7 +1,7 @@
package com.bitwarden.authenticator.data.auth.repository
import android.os.SystemClock
import com.bitwarden.authenticator.data.auth.datasource.disk.AuthDiskSource
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import javax.inject.Inject
/**
@@ -9,7 +9,7 @@ import javax.inject.Inject
*/
class AuthRepositoryImpl @Inject constructor(
private val authDiskSource: AuthDiskSource,
private val elapsedRealtimeMillisProvider: () -> Long = { SystemClock.elapsedRealtime() },
private val realtimeManager: RealtimeManager,
) : AuthRepository {
/**
@@ -17,7 +17,7 @@ class AuthRepositoryImpl @Inject constructor(
*/
override fun updateLastActiveTime() {
authDiskSource.storeLastActiveTimeMillis(
lastActiveTimeMillis = elapsedRealtimeMillisProvider(),
lastActiveTimeMillis = realtimeManager.elapsedRealtimeMs,
)
}
}
@@ -3,6 +3,7 @@ package com.bitwarden.authenticator.data.auth.repository.di
import com.bitwarden.authenticator.data.auth.datasource.disk.AuthDiskSource
import com.bitwarden.authenticator.data.auth.repository.AuthRepository
import com.bitwarden.authenticator.data.auth.repository.AuthRepositoryImpl
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import dagger.Module
import dagger.Provides
import dagger.hilt.InstallIn
@@ -18,7 +19,9 @@ object AuthRepositoryModule {
@Provides
fun provideAuthRepository(
authDiskSource: AuthDiskSource,
realtimeManager: RealtimeManager,
): AuthRepository = AuthRepositoryImpl(
authDiskSource = authDiskSource,
realtimeManager = realtimeManager,
)
}
@@ -20,6 +20,8 @@ import com.bitwarden.authenticator.data.platform.manager.imports.ImportManager
import com.bitwarden.authenticator.data.platform.manager.imports.ImportManagerImpl
import com.bitwarden.authenticator.data.platform.repository.DebugMenuRepository
import com.bitwarden.authenticator.data.platform.repository.SettingsRepository
import com.bitwarden.core.data.manager.realtime.RealtimeManager
import com.bitwarden.core.data.manager.realtime.RealtimeManagerImpl
import com.bitwarden.core.data.manager.toast.ToastManager
import com.bitwarden.core.data.manager.toast.ToastManagerImpl
import com.bitwarden.data.manager.DispatcherManager
@@ -49,6 +51,10 @@ object PlatformManagerModule {
toastManager = toastManager,
)
@Provides
@Singleton
fun provideRealtimeManager(): RealtimeManager = RealtimeManagerImpl()
@Provides
@Singleton
fun provideToastManager(
@@ -0,0 +1,11 @@
package com.bitwarden.core.data.manager.realtime
/**
* An manager interface for accessing the system realtime clock.
*/
interface RealtimeManager {
/**
* Returns milliseconds since the device has booted up, this includes time spent in sleep.
*/
val elapsedRealtimeMs: Long
}
@@ -0,0 +1,12 @@
package com.bitwarden.core.data.manager.realtime
import android.os.SystemClock
import com.bitwarden.annotation.OmitFromCoverage
/**
* The default implementation of the [RealtimeManager].
*/
@OmitFromCoverage
class RealtimeManagerImpl : RealtimeManager {
override val elapsedRealtimeMs: Long get() = SystemClock.elapsedRealtime()
}