mirror of
https://github.com/bitwarden/android.git
synced 2024-10-31 07:05:35 +03:00
BITAU-172 Rename Authenticator Bridge SDK (#3959)
This commit is contained in:
parent
3d0dd2996e
commit
4f34f6da21
48 changed files with 212 additions and 207 deletions
|
@ -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)
|
||||||
|
|
BIN
app/libs/authenticatorbridge-0.1.0-SNAPSHOT-release.aar
Normal file
BIN
app/libs/authenticatorbridge-0.1.0-SNAPSHOT-release.aar
Normal file
Binary file not shown.
Binary file not shown.
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
@ -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?
|
||||||
|
}
|
|
@ -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()
|
|
@ -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?
|
|
||||||
}
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
||||||
}
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
|
@ -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
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -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
|
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.bitwarden.authenticatorbridge.model;
|
||||||
|
|
||||||
|
parcelable EncryptedAddTotpLoginItemData;
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.bitwarden.authenticatorbridge.model;
|
||||||
|
|
||||||
|
parcelable EncryptedSharedAccountData;
|
|
@ -0,0 +1,3 @@
|
||||||
|
package com.bitwarden.authenticatorbridge.model;
|
||||||
|
|
||||||
|
parcelable SymmetricEncryptionKeyData;
|
|
@ -1,3 +1,3 @@
|
||||||
package com.bitwarden.bridge.model;
|
package com.bitwarden.authenticatorbridge.model;
|
||||||
|
|
||||||
parcelable SymmetricEncryptionKeyFingerprintData;
|
parcelable SymmetricEncryptionKeyFingerprintData;
|
|
@ -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.
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -1,4 +1,4 @@
|
||||||
package com.bitwarden.bridge.model
|
package com.bitwarden.authenticatorbridge.model
|
||||||
|
|
||||||
import java.time.Instant
|
import java.time.Instant
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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,
|
|
@ -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.
|
||||||
*/
|
*/
|
|
@ -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
|
|
@ -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);
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
package com.bitwarden.bridge.model;
|
|
||||||
|
|
||||||
parcelable EncryptedAddTotpLoginItemData;
|
|
|
@ -1,3 +0,0 @@
|
||||||
package com.bitwarden.bridge.model;
|
|
||||||
|
|
||||||
parcelable EncryptedSharedAccountData;
|
|
|
@ -1,3 +0,0 @@
|
||||||
package com.bitwarden.bridge.model;
|
|
||||||
|
|
||||||
parcelable SymmetricEncryptionKeyData;
|
|
|
@ -46,4 +46,4 @@ buildCache {
|
||||||
|
|
||||||
rootProject.name = "Bitwarden"
|
rootProject.name = "Bitwarden"
|
||||||
include(":app")
|
include(":app")
|
||||||
include(":bridge")
|
include(":authenticatorbridge")
|
||||||
|
|
Loading…
Reference in a new issue