BITAU-172 Rename Authenticator Bridge SDK (#3959)

This commit is contained in:
Andrew Haisting 2024-09-24 17:09:27 -05:00 committed by GitHub
parent 3d0dd2996e
commit 4f34f6da21
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
48 changed files with 212 additions and 207 deletions

View file

@ -136,7 +136,7 @@ dependencies {
} }
// TODO: this should use a versioned AAR instead of referencing a local AAR BITAU-94 // TODO: this should use a versioned AAR instead of referencing a local AAR BITAU-94
implementation(files("libs/bridge-0.1.0-SNAPSHOT-release.aar")) implementation(files("libs/authenticatorbridge-0.1.0-SNAPSHOT-release.aar"))
implementation(libs.androidx.activity.compose) implementation(libs.androidx.activity.compose)
implementation(libs.androidx.appcompat) implementation(libs.androidx.appcompat)

View file

@ -20,8 +20,8 @@ import com.x8bit.bitwarden.data.platform.manager.AssetManager
import com.x8bit.bitwarden.data.platform.manager.AssetManagerImpl import com.x8bit.bitwarden.data.platform.manager.AssetManagerImpl
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManagerImpl import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManagerImpl
import com.x8bit.bitwarden.data.platform.processor.BridgeServiceProcessor import com.x8bit.bitwarden.data.platform.processor.AuthenticatorBridgeProcessor
import com.x8bit.bitwarden.data.platform.processor.BridgeServiceProcessorImpl import com.x8bit.bitwarden.data.platform.processor.AuthenticatorBridgeProcessorImpl
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager import com.x8bit.bitwarden.data.platform.manager.CrashLogsManager
import com.x8bit.bitwarden.data.platform.manager.CrashLogsManagerImpl import com.x8bit.bitwarden.data.platform.manager.CrashLogsManagerImpl
import com.x8bit.bitwarden.data.platform.manager.DebugMenuFeatureFlagManagerImpl import com.x8bit.bitwarden.data.platform.manager.DebugMenuFeatureFlagManagerImpl
@ -51,7 +51,7 @@ import com.x8bit.bitwarden.data.platform.manager.garbage.GarbageCollectionManage
import com.x8bit.bitwarden.data.platform.manager.garbage.GarbageCollectionManagerImpl import com.x8bit.bitwarden.data.platform.manager.garbage.GarbageCollectionManagerImpl
import com.x8bit.bitwarden.data.platform.manager.restriction.RestrictionManager import com.x8bit.bitwarden.data.platform.manager.restriction.RestrictionManager
import com.x8bit.bitwarden.data.platform.manager.restriction.RestrictionManagerImpl import com.x8bit.bitwarden.data.platform.manager.restriction.RestrictionManagerImpl
import com.x8bit.bitwarden.data.platform.repository.BridgeRepository import com.x8bit.bitwarden.data.platform.repository.AuthenticatorBridgeRepository
import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepository import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepository
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
import com.x8bit.bitwarden.data.platform.repository.ServerConfigRepository import com.x8bit.bitwarden.data.platform.repository.ServerConfigRepository
@ -80,12 +80,12 @@ object PlatformManagerModule {
@Provides @Provides
@Singleton @Singleton
fun provideBridgeServiceProcessor( fun provideAuthenticatorBridgeProcessor(
bridgeRepository: BridgeRepository, authenticatorBridgeRepository: AuthenticatorBridgeRepository,
dispatcherManager: DispatcherManager, dispatcherManager: DispatcherManager,
featureFlagManager: FeatureFlagManager, featureFlagManager: FeatureFlagManager,
): BridgeServiceProcessor = BridgeServiceProcessorImpl( ): AuthenticatorBridgeProcessor = AuthenticatorBridgeProcessorImpl(
bridgeRepository = bridgeRepository, authenticatorBridgeRepository = authenticatorBridgeRepository,
dispatcherManager = dispatcherManager, dispatcherManager = dispatcherManager,
featureFlagManager = featureFlagManager, featureFlagManager = featureFlagManager,
) )

View file

@ -0,0 +1,16 @@
package com.x8bit.bitwarden.data.platform.processor
import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
/**
* Provides implementation of [IAuthenticatorBridgeService] APIs in an injectable and testable
* manner.
*/
interface AuthenticatorBridgeProcessor {
/**
* Binder that implements [IAuthenticatorBridgeService]. Null can be returned to represent a
* no-op binder.
*/
val binder: IAuthenticatorBridgeService.Stub?
}

View file

@ -4,36 +4,36 @@ import android.content.Intent
import android.os.Build import android.os.Build
import android.os.IInterface import android.os.IInterface
import android.os.RemoteCallbackList import android.os.RemoteCallbackList
import com.bitwarden.bridge.IBridgeService import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
import com.bitwarden.bridge.IBridgeServiceCallback import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeServiceCallback
import com.bitwarden.bridge.model.EncryptedAddTotpLoginItemData import com.bitwarden.authenticatorbridge.model.EncryptedAddTotpLoginItemData
import com.bitwarden.bridge.model.SymmetricEncryptionKeyData import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyData
import com.bitwarden.bridge.model.SymmetricEncryptionKeyFingerprintData import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyFingerprintData
import com.bitwarden.bridge.util.NATIVE_BRIDGE_SDK_VERSION import com.bitwarden.authenticatorbridge.util.AUTHENTICATOR_BRIDGE_SDK_VERSION
import com.bitwarden.bridge.util.encrypt import com.bitwarden.authenticatorbridge.util.encrypt
import com.bitwarden.bridge.util.toFingerprint import com.bitwarden.authenticatorbridge.util.toFingerprint
import com.bitwarden.bridge.util.toSymmetricEncryptionKeyData import com.bitwarden.authenticatorbridge.util.toSymmetricEncryptionKeyData
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import com.x8bit.bitwarden.data.platform.repository.BridgeRepository import com.x8bit.bitwarden.data.platform.repository.AuthenticatorBridgeRepository
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
/** /**
* Default implementation of [BridgeServiceProcessor]. * Default implementation of [AuthenticatorBridgeProcessor].
*/ */
class BridgeServiceProcessorImpl( class AuthenticatorBridgeProcessorImpl(
private val bridgeRepository: BridgeRepository, private val authenticatorBridgeRepository: AuthenticatorBridgeRepository,
private val featureFlagManager: FeatureFlagManager, private val featureFlagManager: FeatureFlagManager,
dispatcherManager: DispatcherManager, dispatcherManager: DispatcherManager,
) : BridgeServiceProcessor { ) : AuthenticatorBridgeProcessor {
private val callbacks by lazy { RemoteCallbackList<IBridgeServiceCallback>() } private val callbacks by lazy { RemoteCallbackList<IAuthenticatorBridgeServiceCallback>() }
private val scope by lazy { CoroutineScope(dispatcherManager.default) } private val scope by lazy { CoroutineScope(dispatcherManager.default) }
override val binder: IBridgeService.Stub? override val binder: IAuthenticatorBridgeService.Stub?
get() { get() {
return if ( return if (
!featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) || !featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) ||
@ -51,16 +51,16 @@ class BridgeServiceProcessorImpl(
/** /**
* Default implementation of the bridge service binder. * Default implementation of the bridge service binder.
*/ */
private val defaultBinder = object : IBridgeService.Stub() { private val defaultBinder = object : IAuthenticatorBridgeService.Stub() {
override fun getVersionNumber(): String = NATIVE_BRIDGE_SDK_VERSION override fun getVersionNumber(): String = AUTHENTICATOR_BRIDGE_SDK_VERSION
override fun checkSymmetricEncryptionKeyFingerprint( override fun checkSymmetricEncryptionKeyFingerprint(
symmetricKeyFingerprint: SymmetricEncryptionKeyFingerprintData?, symmetricKeyFingerprint: SymmetricEncryptionKeyFingerprintData?,
): Boolean { ): Boolean {
if (symmetricKeyFingerprint == null) return false if (symmetricKeyFingerprint == null) return false
val localSymmetricKeyFingerprint = val localSymmetricKeyFingerprint =
bridgeRepository.authenticatorSyncSymmetricKey authenticatorBridgeRepository.authenticatorSyncSymmetricKey
?.toSymmetricEncryptionKeyData() ?.toSymmetricEncryptionKeyData()
?.toFingerprint() ?.toFingerprint()
?.getOrNull() ?.getOrNull()
@ -68,14 +68,18 @@ class BridgeServiceProcessorImpl(
} }
override fun getSymmetricEncryptionKeyData(): SymmetricEncryptionKeyData? = override fun getSymmetricEncryptionKeyData(): SymmetricEncryptionKeyData? =
bridgeRepository.authenticatorSyncSymmetricKey?.toSymmetricEncryptionKeyData() authenticatorBridgeRepository
.authenticatorSyncSymmetricKey
?.toSymmetricEncryptionKeyData()
override fun registerBridgeServiceCallback(callback: IBridgeServiceCallback?) { override fun registerBridgeServiceCallback(callback: IAuthenticatorBridgeServiceCallback?) {
if (callback == null) return if (callback == null) return
callbacks.register(callback) callbacks.register(callback)
} }
override fun unregisterBridgeServiceCallback(callback: IBridgeServiceCallback?) { override fun unregisterBridgeServiceCallback(
callback: IAuthenticatorBridgeServiceCallback?,
) {
if (callback == null) return if (callback == null) return
callbacks.unregister(callback) callbacks.unregister(callback)
} }
@ -84,7 +88,7 @@ class BridgeServiceProcessorImpl(
val symmetricEncryptionKey = symmetricEncryptionKeyData ?: return val symmetricEncryptionKey = symmetricEncryptionKeyData ?: return
scope.launch { scope.launch {
// Encrypt the shared account data with the symmetric key: // Encrypt the shared account data with the symmetric key:
val encryptedSharedAccountData = bridgeRepository val encryptedSharedAccountData = authenticatorBridgeRepository
.getSharedAccounts() .getSharedAccounts()
.encrypt(symmetricEncryptionKey) .encrypt(symmetricEncryptionKey)
.getOrNull() .getOrNull()

View file

@ -1,14 +0,0 @@
package com.x8bit.bitwarden.data.platform.processor
import com.bitwarden.bridge.IBridgeService
/**
* Provides access to [IBridgeService] APIs in an injectable and testable manner.
*/
interface BridgeServiceProcessor {
/**
* Binder that implements [IBridgeService]. Null can be returned to represent a no-op binder.
*/
val binder: IBridgeService.Stub?
}

View file

@ -1,11 +1,12 @@
package com.x8bit.bitwarden.data.platform.repository package com.x8bit.bitwarden.data.platform.repository
import com.bitwarden.bridge.model.SharedAccountData import com.bitwarden.authenticatorbridge.model.SharedAccountData
/** /**
* Provides an API for querying disk sources required by Bridge service implementation. * Provides an API for querying disk sources required by Authenticator Bridge
* service implementation.
*/ */
interface BridgeRepository { interface AuthenticatorBridgeRepository {
/** /**
* The currently persisted authenticator sync symmetric key. This key is used for * The currently persisted authenticator sync symmetric key. This key is used for

View file

@ -1,6 +1,6 @@
package com.x8bit.bitwarden.data.platform.repository package com.x8bit.bitwarden.data.platform.repository
import com.bitwarden.bridge.model.SharedAccountData import com.bitwarden.authenticatorbridge.model.SharedAccountData
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.repository.AuthRepository import com.x8bit.bitwarden.data.auth.repository.AuthRepository
import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource import com.x8bit.bitwarden.data.platform.datasource.disk.SettingsDiskSource
@ -14,16 +14,16 @@ import com.x8bit.bitwarden.data.vault.repository.util.toEncryptedSdkCipher
import kotlinx.coroutines.flow.first import kotlinx.coroutines.flow.first
/** /**
* Default implementation of [BridgeRepository]. * Default implementation of [AuthenticatorBridgeRepository].
*/ */
class BridgeRepositoryImpl( class AuthenticatorBridgeRepositoryImpl(
private val authRepository: AuthRepository, private val authRepository: AuthRepository,
private val authDiskSource: AuthDiskSource, private val authDiskSource: AuthDiskSource,
private val vaultRepository: VaultRepository, private val vaultRepository: VaultRepository,
private val vaultDiskSource: VaultDiskSource, private val vaultDiskSource: VaultDiskSource,
private val vaultSdkSource: VaultSdkSource, private val vaultSdkSource: VaultSdkSource,
private val settingsDiskSource: SettingsDiskSource, private val settingsDiskSource: SettingsDiskSource,
) : BridgeRepository { ) : AuthenticatorBridgeRepository {
override val authenticatorSyncSymmetricKey: ByteArray? override val authenticatorSyncSymmetricKey: ByteArray?
get() = authDiskSource.authenticatorSyncSymmetricKey get() = authDiskSource.authenticatorSyncSymmetricKey

View file

@ -1,7 +1,7 @@
package com.x8bit.bitwarden.data.platform.repository package com.x8bit.bitwarden.data.platform.repository
import android.view.autofill.AutofillManager import android.view.autofill.AutofillManager
import com.bitwarden.bridge.util.generateSecretKey import com.bitwarden.authenticatorbridge.util.generateSecretKey
import com.x8bit.bitwarden.BuildConfig import com.x8bit.bitwarden.BuildConfig
import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource import com.x8bit.bitwarden.data.auth.datasource.disk.AuthDiskSource
import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation import com.x8bit.bitwarden.data.auth.repository.model.PolicyInformation

View file

@ -13,8 +13,8 @@ import com.x8bit.bitwarden.data.platform.datasource.network.service.ConfigServic
import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager import com.x8bit.bitwarden.data.platform.manager.BiometricsEncryptionManager
import com.x8bit.bitwarden.data.platform.manager.PolicyManager import com.x8bit.bitwarden.data.platform.manager.PolicyManager
import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager import com.x8bit.bitwarden.data.platform.manager.dispatcher.DispatcherManager
import com.x8bit.bitwarden.data.platform.repository.BridgeRepository import com.x8bit.bitwarden.data.platform.repository.AuthenticatorBridgeRepository
import com.x8bit.bitwarden.data.platform.repository.BridgeRepositoryImpl import com.x8bit.bitwarden.data.platform.repository.AuthenticatorBridgeRepositoryImpl
import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepository import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepository
import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepositoryImpl import com.x8bit.bitwarden.data.platform.repository.DebugMenuRepositoryImpl
import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository import com.x8bit.bitwarden.data.platform.repository.EnvironmentRepository
@ -42,14 +42,14 @@ object PlatformRepositoryModule {
@Provides @Provides
@Singleton @Singleton
fun providesBridgeRepository( fun providesAuthenticatorBridgeRepository(
authRepository: AuthRepository, authRepository: AuthRepository,
authDiskSource: AuthDiskSource, authDiskSource: AuthDiskSource,
vaultRepository: VaultRepository, vaultRepository: VaultRepository,
vaultDiskSource: VaultDiskSource, vaultDiskSource: VaultDiskSource,
vaultSdkSource: VaultSdkSource, vaultSdkSource: VaultSdkSource,
settingsDiskSource: SettingsDiskSource, settingsDiskSource: SettingsDiskSource,
): BridgeRepository = BridgeRepositoryImpl( ): AuthenticatorBridgeRepository = AuthenticatorBridgeRepositoryImpl(
authRepository = authRepository, authRepository = authRepository,
authDiskSource = authDiskSource, authDiskSource = authDiskSource,
vaultRepository = vaultRepository, vaultRepository = vaultRepository,

View file

@ -0,0 +1,27 @@
package com.x8bit.bitwarden.data.platform.service
import android.app.Service
import android.content.Intent
import com.x8bit.bitwarden.data.platform.annotation.OmitFromCoverage
import com.x8bit.bitwarden.data.platform.processor.AuthenticatorBridgeProcessor
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/**
* Service exposed via a custom permission
*/
@AndroidEntryPoint
@OmitFromCoverage
class AuthenticatorBridgeService : Service() {
@Inject
lateinit var authenticatorBridgeProcessor: AuthenticatorBridgeProcessor
/**
* When binding this service, delegate logic to the [AuthenticatorBridgeProcessor].
*
* Note that [AuthenticatorBridgeProcessor.binder] can return a null binder, which the OS
* will accept but never connect to, effectively making a null binder a noop binder.
*/
override fun onBind(intent: Intent) = authenticatorBridgeProcessor.binder
}

View file

@ -1,27 +0,0 @@
package com.x8bit.bitwarden.data.platform.service
import android.app.Service
import android.content.Intent
import com.x8bit.bitwarden.data.platform.processor.BridgeServiceProcessor
import com.bitwarden.bridge.IBridgeService
import dagger.hilt.android.AndroidEntryPoint
import javax.inject.Inject
/**
* Service exposed via a custom permission
*/
@AndroidEntryPoint
class BridgeService : Service() {
@Inject
lateinit var bridgeServiceProcessor: BridgeServiceProcessor
/**
* When binding this service, logic to the [BridgeServiceProcessor], which implements
* [IBridgeService].
*
* Note that [BridgeServiceProcessor.binder] can return a null binder, which the OS will accept
* but never connect to, effectively making a null binder a noop binder.
*/
override fun onBind(intent: Intent) = bridgeServiceProcessor.binder
}

View file

@ -2,7 +2,7 @@ package com.x8bit.bitwarden.data.auth.datasource.disk
import androidx.core.content.edit import androidx.core.content.edit
import app.cash.turbine.test import app.cash.turbine.test
import com.bitwarden.bridge.util.generateSecretKey import com.bitwarden.authenticatorbridge.util.generateSecretKey
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountTokensJson
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson

View file

@ -2,19 +2,19 @@ package com.x8bit.bitwarden.data.platform.processor
import android.os.Build import android.os.Build
import android.os.RemoteCallbackList import android.os.RemoteCallbackList
import com.bitwarden.bridge.IBridgeService import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
import com.bitwarden.bridge.IBridgeServiceCallback import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeServiceCallback
import com.bitwarden.bridge.model.EncryptedSharedAccountData import com.bitwarden.authenticatorbridge.model.EncryptedSharedAccountData
import com.bitwarden.bridge.model.SharedAccountData import com.bitwarden.authenticatorbridge.model.SharedAccountData
import com.bitwarden.bridge.util.NATIVE_BRIDGE_SDK_VERSION import com.bitwarden.authenticatorbridge.util.AUTHENTICATOR_BRIDGE_SDK_VERSION
import com.bitwarden.bridge.util.encrypt import com.bitwarden.authenticatorbridge.util.encrypt
import com.bitwarden.bridge.util.generateSecretKey import com.bitwarden.authenticatorbridge.util.generateSecretKey
import com.bitwarden.bridge.util.toFingerprint import com.bitwarden.authenticatorbridge.util.toFingerprint
import com.bitwarden.bridge.util.toSymmetricEncryptionKeyData import com.bitwarden.authenticatorbridge.util.toSymmetricEncryptionKeyData
import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager import com.x8bit.bitwarden.data.platform.base.FakeDispatcherManager
import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager import com.x8bit.bitwarden.data.platform.manager.FeatureFlagManager
import com.x8bit.bitwarden.data.platform.manager.model.FlagKey import com.x8bit.bitwarden.data.platform.manager.model.FlagKey
import com.x8bit.bitwarden.data.platform.repository.BridgeRepository import com.x8bit.bitwarden.data.platform.repository.AuthenticatorBridgeRepository
import com.x8bit.bitwarden.data.platform.util.asSuccess import com.x8bit.bitwarden.data.platform.util.asSuccess
import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow import com.x8bit.bitwarden.data.platform.util.isBuildVersionBelow
import io.mockk.coEvery import io.mockk.coEvery
@ -34,17 +34,17 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
class BridgeServiceProcessorTest { class AuthenticatorBridgeProcessorTest {
private val featureFlagManager = mockk<FeatureFlagManager>() private val featureFlagManager = mockk<FeatureFlagManager>()
private val bridgeRepository = mockk<BridgeRepository>() private val authenticatorBridgeRepository = mockk<AuthenticatorBridgeRepository>()
private lateinit var bridgeServiceProcessor: BridgeServiceProcessorImpl private lateinit var bridgeServiceProcessor: AuthenticatorBridgeProcessorImpl
@BeforeEach @BeforeEach
fun setup() { fun setup() {
bridgeServiceProcessor = BridgeServiceProcessorImpl( bridgeServiceProcessor = AuthenticatorBridgeProcessorImpl(
bridgeRepository = bridgeRepository, authenticatorBridgeRepository = authenticatorBridgeRepository,
featureFlagManager = featureFlagManager, featureFlagManager = featureFlagManager,
dispatcherManager = FakeDispatcherManager(), dispatcherManager = FakeDispatcherManager(),
) )
@ -88,7 +88,7 @@ class BridgeServiceProcessorTest {
fun `versionNumber should match version of compiled bridge sdk`() { fun `versionNumber should match version of compiled bridge sdk`() {
val binder = getDefaultBinder() val binder = getDefaultBinder()
assertEquals( assertEquals(
NATIVE_BRIDGE_SDK_VERSION, AUTHENTICATOR_BRIDGE_SDK_VERSION,
binder.versionNumber, binder.versionNumber,
) )
} }
@ -98,7 +98,7 @@ class BridgeServiceProcessorTest {
fun `checkSymmetricEncryptionKeyFingerprint should return false when given fingerprint is null`() { fun `checkSymmetricEncryptionKeyFingerprint should return false when given fingerprint is null`() {
val binder = getDefaultBinder() val binder = getDefaultBinder()
// Set disk symmetric key to null so that it is technically equal to given null fingerprint: // Set disk symmetric key to null so that it is technically equal to given null fingerprint:
every { bridgeRepository.authenticatorSyncSymmetricKey } returns null every { authenticatorBridgeRepository.authenticatorSyncSymmetricKey } returns null
// Binder should still return false in this case: // Binder should still return false in this case:
assertFalse(binder.checkSymmetricEncryptionKeyFingerprint(null)) assertFalse(binder.checkSymmetricEncryptionKeyFingerprint(null))
} }
@ -107,7 +107,7 @@ class BridgeServiceProcessorTest {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
fun `checkSymmetricEncryptionKeyFingerprint should return false if fingerprint doesn't match`() { fun `checkSymmetricEncryptionKeyFingerprint should return false if fingerprint doesn't match`() {
val binder = getDefaultBinder() val binder = getDefaultBinder()
every { bridgeRepository.authenticatorSyncSymmetricKey } returns ByteArray(1) every { authenticatorBridgeRepository.authenticatorSyncSymmetricKey } returns ByteArray(1)
assertFalse(binder.checkSymmetricEncryptionKeyFingerprint(SYMMETRIC_KEY_FINGERPRINT)) assertFalse(binder.checkSymmetricEncryptionKeyFingerprint(SYMMETRIC_KEY_FINGERPRINT))
} }
@ -116,7 +116,7 @@ class BridgeServiceProcessorTest {
fun `checkSymmetricEncryptionKeyFingerprint should return true if fingerprint does match`() { fun `checkSymmetricEncryptionKeyFingerprint should return true if fingerprint does match`() {
val binder = getDefaultBinder() val binder = getDefaultBinder()
every { every {
bridgeRepository.authenticatorSyncSymmetricKey authenticatorBridgeRepository.authenticatorSyncSymmetricKey
} returns SYMMETRIC_KEY.symmetricEncryptionKey.byteArray } returns SYMMETRIC_KEY.symmetricEncryptionKey.byteArray
assertTrue(binder.checkSymmetricEncryptionKeyFingerprint(SYMMETRIC_KEY_FINGERPRINT)) assertTrue(binder.checkSymmetricEncryptionKeyFingerprint(SYMMETRIC_KEY_FINGERPRINT))
} }
@ -125,7 +125,7 @@ class BridgeServiceProcessorTest {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
fun `getSymmetricEncryptionKeyData should return null when there is no symmetric key stored on disk`() { fun `getSymmetricEncryptionKeyData should return null when there is no symmetric key stored on disk`() {
val binder = getDefaultBinder() val binder = getDefaultBinder()
every { bridgeRepository.authenticatorSyncSymmetricKey } returns null every { authenticatorBridgeRepository.authenticatorSyncSymmetricKey } returns null
assertNull(binder.symmetricEncryptionKeyData) assertNull(binder.symmetricEncryptionKeyData)
} }
@ -134,7 +134,7 @@ class BridgeServiceProcessorTest {
fun `getSymmetricEncryptionKeyData should return the symmetric key stored on disk`() { fun `getSymmetricEncryptionKeyData should return the symmetric key stored on disk`() {
val binder = getDefaultBinder() val binder = getDefaultBinder()
every { every {
bridgeRepository.authenticatorSyncSymmetricKey authenticatorBridgeRepository.authenticatorSyncSymmetricKey
} returns SYMMETRIC_KEY.symmetricEncryptionKey.byteArray } returns SYMMETRIC_KEY.symmetricEncryptionKey.byteArray
assertEquals(SYMMETRIC_KEY, binder.symmetricEncryptionKeyData) assertEquals(SYMMETRIC_KEY, binder.symmetricEncryptionKeyData)
} }
@ -144,7 +144,7 @@ class BridgeServiceProcessorTest {
private var lastAccountsSync: EncryptedSharedAccountData? = null private var lastAccountsSync: EncryptedSharedAccountData? = null
private val serviceCallback = object : IBridgeServiceCallback.Stub() { private val serviceCallback = object : IAuthenticatorBridgeServiceCallback.Stub() {
override fun onAccountsSync(data: EncryptedSharedAccountData?) { override fun onAccountsSync(data: EncryptedSharedAccountData?) {
lastAccountsSync = data lastAccountsSync = data
} }
@ -155,15 +155,15 @@ class BridgeServiceProcessorTest {
// Setup RemoteCallbackList to call back to serviceCallback: // Setup RemoteCallbackList to call back to serviceCallback:
mockkConstructor(RemoteCallbackList::class) mockkConstructor(RemoteCallbackList::class)
every { every {
anyConstructed<RemoteCallbackList<IBridgeServiceCallback>>() anyConstructed<RemoteCallbackList<IAuthenticatorBridgeServiceCallback>>()
.register(serviceCallback) .register(serviceCallback)
} returns true } returns true
every { every {
anyConstructed<RemoteCallbackList<IBridgeServiceCallback>>() anyConstructed<RemoteCallbackList<IAuthenticatorBridgeServiceCallback>>()
.beginBroadcast() .beginBroadcast()
} returns 1 } returns 1
every { every {
anyConstructed<RemoteCallbackList<IBridgeServiceCallback>>() anyConstructed<RemoteCallbackList<IAuthenticatorBridgeServiceCallback>>()
.getBroadcastItem(0) .getBroadcastItem(0)
} returns serviceCallback } returns serviceCallback
lastAccountsSync = null lastAccountsSync = null
@ -171,7 +171,7 @@ class BridgeServiceProcessorTest {
@Test @Test
fun `syncAccounts when symmetricEncryptionKeyData is null should do nothing`() { fun `syncAccounts when symmetricEncryptionKeyData is null should do nothing`() {
every { bridgeRepository.authenticatorSyncSymmetricKey } returns null every { authenticatorBridgeRepository.authenticatorSyncSymmetricKey } returns null
getDefaultBinder().syncAccounts() getDefaultBinder().syncAccounts()
assertNull(lastAccountsSync) assertNull(lastAccountsSync)
} }
@ -181,25 +181,25 @@ class BridgeServiceProcessorTest {
val sharedAccountData = mockk<SharedAccountData>() val sharedAccountData = mockk<SharedAccountData>()
val expected = mockk<EncryptedSharedAccountData>() val expected = mockk<EncryptedSharedAccountData>()
every { every {
bridgeRepository.authenticatorSyncSymmetricKey authenticatorBridgeRepository.authenticatorSyncSymmetricKey
} returns SYMMETRIC_KEY.symmetricEncryptionKey.byteArray } returns SYMMETRIC_KEY.symmetricEncryptionKey.byteArray
coEvery { bridgeRepository.getSharedAccounts() } returns sharedAccountData coEvery { authenticatorBridgeRepository.getSharedAccounts() } returns sharedAccountData
mockkStatic(SharedAccountData::encrypt) mockkStatic(SharedAccountData::encrypt)
every { sharedAccountData.encrypt(SYMMETRIC_KEY) } returns expected.asSuccess() every { sharedAccountData.encrypt(SYMMETRIC_KEY) } returns expected.asSuccess()
getDefaultBinder().syncAccounts() getDefaultBinder().syncAccounts()
assertEquals(expected, lastAccountsSync) assertEquals(expected, lastAccountsSync)
coVerify { bridgeRepository.getSharedAccounts() } coVerify { authenticatorBridgeRepository.getSharedAccounts() }
} }
} }
/** /**
* Helper function for accessing the default implementation of [IBridgeService.Stub]. This * Helper function for accessing the default implementation of
* is particularly useful because the binder is nullable on [BridgeServiceProcessor] behind * [IAuthenticatorBridgeService.Stub]. This is particularly useful because the binder
* a feature flag. * is nullable on [AuthenticatorBridgeProcessor] behind a feature flag.
*/ */
private fun getDefaultBinder(): IBridgeService.Stub { private fun getDefaultBinder(): IAuthenticatorBridgeService.Stub {
mockkStatic(::isBuildVersionBelow) mockkStatic(::isBuildVersionBelow)
every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns false every { isBuildVersionBelow(Build.VERSION_CODES.S) } returns false
every { featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) } returns true every { featureFlagManager.getFeatureFlag(FlagKey.AuthenticatorSync) } returns true

View file

@ -1,8 +1,8 @@
package com.x8bit.bitwarden.data.platform.repository package com.x8bit.bitwarden.data.platform.repository
import com.bitwarden.bridge.model.SharedAccountData import com.bitwarden.authenticatorbridge.model.SharedAccountData
import com.bitwarden.bridge.util.generateSecretKey import com.bitwarden.authenticatorbridge.util.generateSecretKey
import com.bitwarden.bridge.util.toSymmetricEncryptionKeyData import com.bitwarden.authenticatorbridge.util.toSymmetricEncryptionKeyData
import com.bitwarden.vault.Cipher import com.bitwarden.vault.Cipher
import com.bitwarden.vault.CipherView import com.bitwarden.vault.CipherView
import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource import com.x8bit.bitwarden.data.auth.datasource.disk.util.FakeAuthDiskSource
@ -36,7 +36,7 @@ import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import java.time.Instant import java.time.Instant
class BridgeRepositoryTest { class AuthenticatorBridgeRepositoryTest {
private val authRepository = mockk<AuthRepository>() private val authRepository = mockk<AuthRepository>()
private val vaultSdkSource = mockk<VaultSdkSource>() private val vaultSdkSource = mockk<VaultSdkSource>()
@ -45,7 +45,7 @@ class BridgeRepositoryTest {
private val fakeAuthDiskSource = FakeAuthDiskSource() private val fakeAuthDiskSource = FakeAuthDiskSource()
private val fakeSettingsDiskSource = FakeSettingsDiskSource() private val fakeSettingsDiskSource = FakeSettingsDiskSource()
private val bridgeRepository = BridgeRepositoryImpl( private val authenticatorBridgeRepository = AuthenticatorBridgeRepositoryImpl(
authRepository = authRepository, authRepository = authRepository,
authDiskSource = fakeAuthDiskSource, authDiskSource = fakeAuthDiskSource,
vaultRepository = vaultRepository, vaultRepository = vaultRepository,
@ -129,7 +129,7 @@ class BridgeRepositoryTest {
@Suppress("MaxLineLength") @Suppress("MaxLineLength")
fun `syncAccounts with user 1 vault unlocked and all data present should send expected shared accounts data`() = fun `syncAccounts with user 1 vault unlocked and all data present should send expected shared accounts data`() =
runTest { runTest {
val sharedAccounts = bridgeRepository.getSharedAccounts() val sharedAccounts = authenticatorBridgeRepository.getSharedAccounts()
assertEquals( assertEquals(
BOTH_ACCOUNT_SUCCESS, BOTH_ACCOUNT_SUCCESS,
sharedAccounts, sharedAccounts,
@ -155,7 +155,7 @@ class BridgeRepositoryTest {
fun `syncAccounts when userStateFlow is null should return an empty list`() = runTest { fun `syncAccounts when userStateFlow is null should return an empty list`() = runTest {
every { authRepository.userStateFlow } returns MutableStateFlow(null) every { authRepository.userStateFlow } returns MutableStateFlow(null)
val sharedData = bridgeRepository.getSharedAccounts() val sharedData = authenticatorBridgeRepository.getSharedAccounts()
assertTrue(sharedData.accounts.isEmpty()) assertTrue(sharedData.accounts.isEmpty())
verify { authRepository.userStateFlow } verify { authRepository.userStateFlow }
@ -172,7 +172,7 @@ class BridgeRepositoryTest {
assertEquals( assertEquals(
SharedAccountData(listOf(USER_2_SHARED_ACCOUNT)), SharedAccountData(listOf(USER_2_SHARED_ACCOUNT)),
bridgeRepository.getSharedAccounts(), authenticatorBridgeRepository.getSharedAccounts(),
) )
verify { authRepository.userStateFlow } verify { authRepository.userStateFlow }
@ -199,7 +199,7 @@ class BridgeRepositoryTest {
} returns VaultUnlockResult.Success } returns VaultUnlockResult.Success
every { vaultRepository.lockVault(USER_1_ID) } returns Unit every { vaultRepository.lockVault(USER_1_ID) } returns Unit
val sharedAccounts = bridgeRepository.getSharedAccounts() val sharedAccounts = authenticatorBridgeRepository.getSharedAccounts()
assertEquals( assertEquals(
BOTH_ACCOUNT_SUCCESS, BOTH_ACCOUNT_SUCCESS,
sharedAccounts, sharedAccounts,
@ -232,7 +232,7 @@ class BridgeRepositoryTest {
@Test @Test
fun `syncAccounts when getLastSyncTime is null should omit account from list`() = runTest { fun `syncAccounts when getLastSyncTime is null should omit account from list`() = runTest {
fakeSettingsDiskSource.storeLastSyncTime(USER_1_ID, null) fakeSettingsDiskSource.storeLastSyncTime(USER_1_ID, null)
val sharedAccounts = bridgeRepository.getSharedAccounts() val sharedAccounts = authenticatorBridgeRepository.getSharedAccounts()
assertEquals(SharedAccountData(listOf(USER_2_SHARED_ACCOUNT)), sharedAccounts) assertEquals(SharedAccountData(listOf(USER_2_SHARED_ACCOUNT)), sharedAccounts)
verify { vaultRepository.vaultUnlockDataStateFlow } verify { vaultRepository.vaultUnlockDataStateFlow }
verify { vaultDiskSource.getCiphers(USER_1_ID) } verify { vaultDiskSource.getCiphers(USER_1_ID) }
@ -261,7 +261,7 @@ class BridgeRepositoryTest {
vaultRepository.unlockVaultWithDecryptedUserKey(USER_1_ID, USER_1_UNLOCK_KEY) vaultRepository.unlockVaultWithDecryptedUserKey(USER_1_ID, USER_1_UNLOCK_KEY)
} returns VaultUnlockResult.InvalidStateError } returns VaultUnlockResult.InvalidStateError
val sharedAccounts = bridgeRepository.getSharedAccounts() val sharedAccounts = authenticatorBridgeRepository.getSharedAccounts()
assertEquals(SharedAccountData(listOf(USER_2_SHARED_ACCOUNT)), sharedAccounts) assertEquals(SharedAccountData(listOf(USER_2_SHARED_ACCOUNT)), sharedAccounts)
assertNull(fakeAuthDiskSource.getAuthenticatorSyncUnlockKey(USER_1_ID)) assertNull(fakeAuthDiskSource.getAuthenticatorSyncUnlockKey(USER_1_ID))
verify { vaultRepository.vaultUnlockDataStateFlow } verify { vaultRepository.vaultUnlockDataStateFlow }
@ -298,7 +298,7 @@ class BridgeRepositoryTest {
) )
every { vaultRepository.vaultUnlockDataStateFlow } returns vaultUnlockStateFlow every { vaultRepository.vaultUnlockDataStateFlow } returns vaultUnlockStateFlow
val deferred = async { val deferred = async {
val sharedAccounts = bridgeRepository.getSharedAccounts() val sharedAccounts = authenticatorBridgeRepository.getSharedAccounts()
assertEquals(BOTH_ACCOUNT_SUCCESS, sharedAccounts) assertEquals(BOTH_ACCOUNT_SUCCESS, sharedAccounts)
} }
@ -336,12 +336,12 @@ class BridgeRepositoryTest {
@Test @Test
fun `authenticatorSyncSymmetricKey should read from authDiskSource`() { fun `authenticatorSyncSymmetricKey should read from authDiskSource`() {
fakeAuthDiskSource.authenticatorSyncSymmetricKey = null fakeAuthDiskSource.authenticatorSyncSymmetricKey = null
assertNull(bridgeRepository.authenticatorSyncSymmetricKey) assertNull(authenticatorBridgeRepository.authenticatorSyncSymmetricKey)
val syncKey = generateSecretKey().getOrThrow().encoded val syncKey = generateSecretKey().getOrThrow().encoded
fakeAuthDiskSource.authenticatorSyncSymmetricKey = syncKey fakeAuthDiskSource.authenticatorSyncSymmetricKey = syncKey
assertEquals(syncKey, bridgeRepository.authenticatorSyncSymmetricKey) assertEquals(syncKey, authenticatorBridgeRepository.authenticatorSyncSymmetricKey)
} }
} }

View file

@ -2,7 +2,7 @@ package com.x8bit.bitwarden.data.platform.repository
import android.view.autofill.AutofillManager import android.view.autofill.AutofillManager
import app.cash.turbine.test import app.cash.turbine.test
import com.bitwarden.bridge.util.generateSecretKey import com.bitwarden.authenticatorbridge.util.generateSecretKey
import com.bitwarden.core.DerivePinKeyResponse import com.bitwarden.core.DerivePinKeyResponse
import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.AccountJson
import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson import com.x8bit.bitwarden.data.auth.datasource.disk.model.EnvironmentUrlDataJson

View file

@ -1,4 +1,4 @@
# Bitwarden Native Bridge SDK # Authenticator Bridge SDK
## Contents ## Contents
@ -22,7 +22,7 @@
To build an AAR for inclusion in consumer applications, run: To build an AAR for inclusion in consumer applications, run:
```sh ```sh
$ ./gradlew bridge:assembleRelease $ ./gradlew authenticatorbridge:assembleRelease
``` ```
## Versioning ## Versioning

View file

@ -11,7 +11,7 @@ plugins {
} }
android { android {
namespace = "com.bitwarden.bridge" namespace = "com.bitwarden.authenticatorbridge"
compileSdk = libs.versions.compileSdk.get().toInt() compileSdk = libs.versions.compileSdk.get().toInt()
defaultConfig { defaultConfig {
@ -46,7 +46,7 @@ android {
outputs outputs
.map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl } .map { it as com.android.build.gradle.internal.api.BaseVariantOutputImpl }
.forEach { output -> .forEach { output ->
val outputFileName = "bridge-${version}-SNAPSHOT-${variant.baseName}.aar" val outputFileName = "authenticatorbridge-${version}-SNAPSHOT-${variant.baseName}.aar"
output.outputFileName = outputFileName output.outputFileName = outputFileName
} }
} }

View file

@ -1,20 +1,20 @@
package com.bitwarden.bridge; package com.bitwarden.authenticatorbridge;
import com.bitwarden.bridge.model.EncryptedAddTotpLoginItemData; import com.bitwarden.authenticatorbridge.model.EncryptedAddTotpLoginItemData;
import com.bitwarden.bridge.model.SymmetricEncryptionKeyData; import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyData;
import com.bitwarden.bridge.model.SymmetricEncryptionKeyFingerprintData; import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyFingerprintData;
import com.bitwarden.bridge.IBridgeServiceCallback; import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeServiceCallback;
interface IBridgeService { interface IAuthenticatorBridgeService {
// ============== // ==============
// Configuration // Configuration
// ============== // ==============
// Returns the version number string of the Bridge SDK. This is useful so that callers // Returns the version number string of the Authenticator Bridge SDK. This is useful so that
// can compare the version of their Bridge SDK with this value and ensure that the two are // callers can compare the version of their Authenticator Bridge SDK with this value and
// compatible. // ensure that the two are compatible.
// //
// For more info about versioning the Bridge SDK, see the Bridge SDK README. // For more info about versioning the Authenticator Bridge SDK, see the README.
String getVersionNumber(); String getVersionNumber();
// Returns true when the given symmetric fingerprint data matches that contained by the SDK. // Returns true when the given symmetric fingerprint data matches that contained by the SDK.
@ -32,10 +32,10 @@ interface IBridgeService {
// ============== // ==============
// Register the given callback to receive updates after syncAccounts is called. // Register the given callback to receive updates after syncAccounts is called.
void registerBridgeServiceCallback(IBridgeServiceCallback callback); void registerBridgeServiceCallback(IAuthenticatorBridgeServiceCallback callback);
// Unregister the given callback from receiving updates. // Unregister the given callback from receiving updates.
void unregisterBridgeServiceCallback(IBridgeServiceCallback callback); void unregisterBridgeServiceCallback(IAuthenticatorBridgeServiceCallback callback);
// ============== // ==============
// Data Syncing // Data Syncing

View file

@ -0,0 +1,10 @@
package com.bitwarden.authenticatorbridge;
import com.bitwarden.authenticatorbridge.model.EncryptedSharedAccountData;
interface IAuthenticatorBridgeServiceCallback {
// This function will be called when there is updated shared account data.
void onAccountsSync(in EncryptedSharedAccountData data);
}

View file

@ -0,0 +1,3 @@
package com.bitwarden.authenticatorbridge.model;
parcelable EncryptedAddTotpLoginItemData;

View file

@ -0,0 +1,3 @@
package com.bitwarden.authenticatorbridge.model;
parcelable EncryptedSharedAccountData;

View file

@ -0,0 +1,3 @@
package com.bitwarden.authenticatorbridge.model;
parcelable SymmetricEncryptionKeyData;

View file

@ -1,3 +1,3 @@
package com.bitwarden.bridge.model; package com.bitwarden.authenticatorbridge.model;
parcelable SymmetricEncryptionKeyFingerprintData; parcelable SymmetricEncryptionKeyFingerprintData;

View file

@ -1,7 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import android.os.Parcelable
import kotlinx.parcelize.Parcelize
/** /**
* Domain level model for a TOTP item to be added to the Bitwarden app. * Domain level model for a TOTP item to be added to the Bitwarden app.

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import java.time.Instant import java.time.Instant

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import kotlinx.serialization.Contextual import kotlinx.serialization.Contextual
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize

View file

@ -1,4 +1,4 @@
package com.bitwarden.bridge.model package com.bitwarden.authenticatorbridge.model
import android.os.Parcelable import android.os.Parcelable
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize

View file

@ -1,6 +1,6 @@
package com.bitwarden.bridge.util package com.bitwarden.authenticatorbridge.util
import com.bitwarden.bridge.BuildConfig import com.bitwarden.authenticatorbridge.BuildConfig
import kotlinx.serialization.KSerializer import kotlinx.serialization.KSerializer
import kotlinx.serialization.descriptors.PrimitiveKind import kotlinx.serialization.descriptors.PrimitiveKind
import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor import kotlinx.serialization.descriptors.PrimitiveSerialDescriptor
@ -13,12 +13,12 @@ import kotlinx.serialization.modules.contextual
import java.time.Instant import java.time.Instant
/** /**
* Version of the native bridge sdk. * Version of the Authenticator Bridge SDK.
*/ */
const val NATIVE_BRIDGE_SDK_VERSION = BuildConfig.VERSION const val AUTHENTICATOR_BRIDGE_SDK_VERSION = BuildConfig.VERSION
/** /**
* Common instance of [Json] that should be used throughout the app. * Common instance of [Json] that should be used throughout the SDK.
*/ */
internal val JSON = Json { internal val JSON = Json {
// If there are keys returned by the server not modeled by a serializable class, // If there are keys returned by the server not modeled by a serializable class,

View file

@ -1,16 +1,16 @@
package com.bitwarden.bridge.util package com.bitwarden.authenticatorbridge.util
import android.security.keystore.KeyProperties import android.security.keystore.KeyProperties
import com.bitwarden.bridge.IBridgeService import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
import com.bitwarden.bridge.model.AddTotpLoginItemData import com.bitwarden.authenticatorbridge.model.AddTotpLoginItemData
import com.bitwarden.bridge.model.AddTotpLoginItemDataJson import com.bitwarden.authenticatorbridge.model.AddTotpLoginItemDataJson
import com.bitwarden.bridge.model.EncryptedAddTotpLoginItemData import com.bitwarden.authenticatorbridge.model.EncryptedAddTotpLoginItemData
import com.bitwarden.bridge.model.EncryptedSharedAccountData import com.bitwarden.authenticatorbridge.model.EncryptedSharedAccountData
import com.bitwarden.bridge.model.SharedAccountData import com.bitwarden.authenticatorbridge.model.SharedAccountData
import com.bitwarden.bridge.model.SharedAccountDataJson import com.bitwarden.authenticatorbridge.model.SharedAccountDataJson
import com.bitwarden.bridge.model.SymmetricEncryptionKeyData import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyData
import com.bitwarden.bridge.model.SymmetricEncryptionKeyFingerprintData import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyFingerprintData
import com.bitwarden.bridge.model.toByteArrayContainer import com.bitwarden.authenticatorbridge.model.toByteArrayContainer
import kotlinx.serialization.encodeToString import kotlinx.serialization.encodeToString
import java.security.MessageDigest import java.security.MessageDigest
import javax.crypto.Cipher import javax.crypto.Cipher
@ -22,7 +22,8 @@ import javax.crypto.spec.SecretKeySpec
/** /**
* Generate a symmetric [SecretKey] that will used for encrypting IPC traffic. * Generate a symmetric [SecretKey] that will used for encrypting IPC traffic.
* *
* This is intended to be used for implementing [IBridgeService.getSymmetricEncryptionKeyData]. * This is intended to be used for implementing
* [IAuthenticatorBridgeService.getSymmetricEncryptionKeyData].
*/ */
fun generateSecretKey(): Result<SecretKey> = runCatching { fun generateSecretKey(): Result<SecretKey> = runCatching {
val keygen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES) val keygen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES)
@ -34,7 +35,7 @@ fun generateSecretKey(): Result<SecretKey> = runCatching {
* Generate a fingerprint for the given symmetric key. * Generate a fingerprint for the given symmetric key.
* *
* This is intended to be used for implementing * This is intended to be used for implementing
* [IBridgeService.checkSymmetricEncryptionKeyFingerprint], which allows callers of the service * [IAuthenticatorBridgeService.checkSymmetricEncryptionKeyFingerprint], which allows callers of the service
* to verify that they have the correct symmetric key without actually having to send the key. * to verify that they have the correct symmetric key without actually having to send the key.
*/ */
fun SymmetricEncryptionKeyData.toFingerprint(): Result<SymmetricEncryptionKeyFingerprintData> = fun SymmetricEncryptionKeyData.toFingerprint(): Result<SymmetricEncryptionKeyFingerprintData> =
@ -48,7 +49,8 @@ fun SymmetricEncryptionKeyData.toFingerprint(): Result<SymmetricEncryptionKeyFin
/** /**
* Encrypt [SharedAccountData]. * Encrypt [SharedAccountData].
* *
* This is intended to be used by the main Bitwarden app during a [IBridgeService.syncAccounts] call. * This is intended to be used by the main Bitwarden app during a
* [IAuthenticatorBridgeService.syncAccounts] call.
* *
* @param symmetricEncryptionKeyData Symmetric key used for encryption. * @param symmetricEncryptionKeyData Symmetric key used for encryption.
*/ */

View file

@ -1,17 +1,16 @@
package com.bitwarden.bridge.util package com.bitwarden.authenticatorbridge.util
import android.security.keystore.KeyProperties import android.security.keystore.KeyProperties
import com.bitwarden.bridge.model.AddTotpLoginItemData import com.bitwarden.authenticatorbridge.model.AddTotpLoginItemData
import com.bitwarden.bridge.model.SharedAccountData import com.bitwarden.authenticatorbridge.model.SharedAccountData
import com.bitwarden.bridge.model.SymmetricEncryptionKeyData import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyData
import com.bitwarden.bridge.model.toByteArrayContainer import com.bitwarden.authenticatorbridge.model.toByteArrayContainer
import io.mockk.every import io.mockk.every
import io.mockk.mockkStatic import io.mockk.mockkStatic
import io.mockk.unmockkStatic import io.mockk.unmockkStatic
import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertNotNull import org.junit.jupiter.api.Assertions.assertNotNull
import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import java.security.MessageDigest import java.security.MessageDigest
import java.security.NoSuchAlgorithmException import java.security.NoSuchAlgorithmException

View file

@ -1,10 +0,0 @@
package com.bitwarden.bridge;
import com.bitwarden.bridge.model.EncryptedSharedAccountData;
interface IBridgeServiceCallback {
// This function will be called when there is updated shared account data.
void onAccountsSync(in EncryptedSharedAccountData data);
}

View file

@ -1,3 +0,0 @@
package com.bitwarden.bridge.model;
parcelable EncryptedAddTotpLoginItemData;

View file

@ -1,3 +0,0 @@
package com.bitwarden.bridge.model;
parcelable EncryptedSharedAccountData;

View file

@ -1,3 +0,0 @@
package com.bitwarden.bridge.model;
parcelable SymmetricEncryptionKeyData;

View file

@ -46,4 +46,4 @@ buildCache {
rootProject.name = "Bitwarden" rootProject.name = "Bitwarden"
include(":app") include(":app")
include(":bridge") include(":authenticatorbridge")