Skip to content

Commit

Permalink
BITAU-69 Check for OS version in AuthenticatorBridgeManager (#4019)
Browse files Browse the repository at this point in the history
  • Loading branch information
ahaisting-livefront authored Oct 3, 2024
1 parent 20383f0 commit 32f2bfb
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 11 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build
import android.os.IBinder
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
Expand All @@ -18,6 +19,7 @@ import com.bitwarden.authenticatorbridge.provider.AuthenticatorBridgeCallbackPro
import com.bitwarden.authenticatorbridge.provider.StubAuthenticatorBridgeCallbackProvider
import com.bitwarden.authenticatorbridge.provider.SymmetricKeyStorageProvider
import com.bitwarden.authenticatorbridge.util.decrypt
import com.bitwarden.authenticatorbridge.util.isBuildVersionBelow
import com.bitwarden.authenticatorbridge.util.toFingerprint
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
Expand Down Expand Up @@ -58,10 +60,10 @@ internal class AuthenticatorBridgeManagerImpl(
*/
private val mutableSharedAccountsStateFlow: MutableStateFlow<AccountSyncState> =
MutableStateFlow(
if (isBitwardenAppInstalled()) {
AccountSyncState.Loading
} else {
AccountSyncState.AppNotInstalled
when {
isBuildVersionBelow(Build.VERSION_CODES.S) -> AccountSyncState.OsVersionNotSupported
!isBitwardenAppInstalled() -> AccountSyncState.AppNotInstalled
else -> AccountSyncState.Loading
}
)

Expand Down Expand Up @@ -102,6 +104,10 @@ internal class AuthenticatorBridgeManagerImpl(
}

private fun bindService() {
if (isBuildVersionBelow(Build.VERSION_CODES.S)) {
mutableSharedAccountsStateFlow.value = AccountSyncState.OsVersionNotSupported
return
}
if (!isBitwardenAppInstalled()) {
mutableSharedAccountsStateFlow.value = AccountSyncState.AppNotInstalled
return
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ sealed class AccountSyncState {
*/
data object Loading : AccountSyncState()

/**
* OS version can't support account syncing.
*/
data object OsVersionNotSupported: AccountSyncState()

/**
* Accounts successfully synced.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.bitwarden.authenticatorbridge.util

import android.os.Build

/**
* Returns true if the current OS build version is below the provided [version].
*
* @see Build.VERSION_CODES
*/
fun isBuildVersionBelow(version: Int): Boolean = version > Build.VERSION.SDK_INT
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.content.pm.PackageManager.NameNotFoundException
import android.os.Build
import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeServiceCallback
import com.bitwarden.authenticatorbridge.manager.model.AccountSyncState
Expand All @@ -15,6 +16,7 @@ import com.bitwarden.authenticatorbridge.util.FakeSymmetricKeyStorageProvider
import com.bitwarden.authenticatorbridge.util.TestAuthenticatorBridgeCallbackProvider
import com.bitwarden.authenticatorbridge.util.decrypt
import com.bitwarden.authenticatorbridge.util.generateSecretKey
import com.bitwarden.authenticatorbridge.util.isBuildVersionBelow
import com.bitwarden.authenticatorbridge.util.toFingerprint
import com.bitwarden.authenticatorbridge.util.toSymmetricEncryptionKeyData
import io.mockk.every
Expand Down Expand Up @@ -45,23 +47,27 @@ class AuthenticatorBridgeManagerTest {
private val fakeSymmetricKeyStorageProvider = FakeSymmetricKeyStorageProvider()
private val testAuthenticatorBridgeCallbackProvider = TestAuthenticatorBridgeCallbackProvider()

private val manager: AuthenticatorBridgeManagerImpl = AuthenticatorBridgeManagerImpl(
context = context,
connectionType = AuthenticatorBridgeConnectionType.DEV,
symmetricKeyStorageProvider = fakeSymmetricKeyStorageProvider,
callbackProvider = testAuthenticatorBridgeCallbackProvider,
processLifecycleOwner = fakeLifecycleOwner,
)
private lateinit var manager: AuthenticatorBridgeManagerImpl

@BeforeEach
fun setup() {
mockkStatic(::isBuildVersionBelow)
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns false
mockkConstructor(Intent::class)
mockkStatic(IAuthenticatorBridgeService.Stub::class)
mockkStatic(EncryptedSharedAccountData::decrypt)
manager = AuthenticatorBridgeManagerImpl(
context = context,
connectionType = AuthenticatorBridgeConnectionType.DEV,
symmetricKeyStorageProvider = fakeSymmetricKeyStorageProvider,
callbackProvider = testAuthenticatorBridgeCallbackProvider,
processLifecycleOwner = fakeLifecycleOwner,
)
}

@AfterEach
fun teardown() {
mockkStatic(::isBuildVersionBelow)
unmockkConstructor(Intent::class)
unmockkStatic(IAuthenticatorBridgeService.Stub::class)
unmockkStatic(EncryptedSharedAccountData::decrypt)
Expand All @@ -87,6 +93,26 @@ class AuthenticatorBridgeManagerTest {
assertEquals(AccountSyncState.AppNotInstalled, manager.accountSyncStateFlow.value)
}

@Test
fun `initial AccountSyncState should be OsVersionNotSupported when OS level is below S`() {
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns true
val manager = AuthenticatorBridgeManagerImpl(
context = context,
connectionType = AuthenticatorBridgeConnectionType.DEV,
symmetricKeyStorageProvider = fakeSymmetricKeyStorageProvider,
callbackProvider = testAuthenticatorBridgeCallbackProvider,
processLifecycleOwner = fakeLifecycleOwner,
)
assertEquals(AccountSyncState.OsVersionNotSupported, manager.accountSyncStateFlow.value)
}

@Test
fun `onStart when OS level is below S should set state to OsVersionNotSupported`() {
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns true
fakeLifecycleOwner.lifecycle.dispatchOnStart()
assertEquals(AccountSyncState.OsVersionNotSupported, manager.accountSyncStateFlow.value)
}

@Test
fun `onStart when bindService fails should set state to error`() {
val mockIntent: Intent = mockk()
Expand Down

0 comments on commit 32f2bfb

Please sign in to comment.