mirror of
https://github.com/bitwarden/android.git
synced 2026-03-11 12:44:17 -05:00
Run detekt on authenticatorbridge module (#4940)
This commit is contained in:
@@ -1,7 +1,5 @@
|
||||
package com.bitwarden.authenticatorbridge.manager
|
||||
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import com.bitwarden.authenticatorbridge.IAuthenticatorBridgeService
|
||||
import com.bitwarden.authenticatorbridge.manager.model.AccountSyncState
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
|
||||
@@ -7,7 +7,6 @@ import android.content.ServiceConnection
|
||||
import android.content.pm.PackageManager.NameNotFoundException
|
||||
import android.os.Build
|
||||
import android.os.IBinder
|
||||
import android.util.Log
|
||||
import androidx.lifecycle.DefaultLifecycleObserver
|
||||
import androidx.lifecycle.LifecycleOwner
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
@@ -46,7 +45,8 @@ private const val AUTHENTICATOR_BRIDGE_SERVICE_CLASS =
|
||||
internal class AuthenticatorBridgeManagerImpl(
|
||||
private val connectionType: AuthenticatorBridgeConnectionType,
|
||||
private val symmetricKeyStorageProvider: SymmetricKeyStorageProvider,
|
||||
callbackProvider: AuthenticatorBridgeCallbackProvider = StubAuthenticatorBridgeCallbackProvider(),
|
||||
callbackProvider: AuthenticatorBridgeCallbackProvider =
|
||||
StubAuthenticatorBridgeCallbackProvider(),
|
||||
context: Context,
|
||||
processLifecycleOwner: LifecycleOwner = ProcessLifecycleOwner.get(),
|
||||
) : AuthenticatorBridgeManager {
|
||||
@@ -67,7 +67,7 @@ internal class AuthenticatorBridgeManagerImpl(
|
||||
isBuildVersionBelow(Build.VERSION_CODES.S) -> AccountSyncState.OsVersionNotSupported
|
||||
!isBitwardenAppInstalled() -> AccountSyncState.AppNotInstalled
|
||||
else -> AccountSyncState.Loading
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -117,7 +117,7 @@ internal class AuthenticatorBridgeManagerImpl(
|
||||
}
|
||||
?.fold(
|
||||
onFailure = { false },
|
||||
onSuccess = { true }
|
||||
onSuccess = { true },
|
||||
)
|
||||
?: false
|
||||
|
||||
@@ -201,7 +201,6 @@ internal class AuthenticatorBridgeManagerImpl(
|
||||
return
|
||||
},
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
if (symmetricKeyStorageProvider.symmetricKey == null) {
|
||||
|
||||
@@ -30,7 +30,7 @@ sealed class AccountSyncState {
|
||||
/**
|
||||
* OS version can't support account syncing.
|
||||
*/
|
||||
data object OsVersionNotSupported: AccountSyncState()
|
||||
data object OsVersionNotSupported : AccountSyncState()
|
||||
|
||||
/**
|
||||
* Accounts successfully synced.
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
package com.bitwarden.authenticatorbridge.model
|
||||
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Domain level model representing shared account data.
|
||||
*
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
package com.bitwarden.authenticatorbridge.model
|
||||
|
||||
import kotlinx.serialization.Contextual
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import java.time.Instant
|
||||
|
||||
/**
|
||||
* Models a serializable list of shared accounts to be shared with other applications.
|
||||
@@ -46,5 +44,3 @@ internal data class SharedAccountDataJson(
|
||||
val totpUris: List<String>,
|
||||
)
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
@file:Suppress("TooManyFunctions")
|
||||
|
||||
package com.bitwarden.authenticatorbridge.util
|
||||
|
||||
import android.security.keystore.KeyProperties
|
||||
@@ -11,7 +13,6 @@ import com.bitwarden.authenticatorbridge.model.SharedAccountDataJson
|
||||
import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyData
|
||||
import com.bitwarden.authenticatorbridge.model.SymmetricEncryptionKeyFingerprintData
|
||||
import com.bitwarden.authenticatorbridge.model.toByteArrayContainer
|
||||
import kotlinx.serialization.encodeToString
|
||||
import java.security.MessageDigest
|
||||
import javax.crypto.Cipher
|
||||
import javax.crypto.KeyGenerator
|
||||
@@ -25,6 +26,7 @@ import javax.crypto.spec.SecretKeySpec
|
||||
* This is intended to be used for implementing
|
||||
* [IAuthenticatorBridgeService.getSymmetricEncryptionKeyData].
|
||||
*/
|
||||
@Suppress("MagicNumber")
|
||||
fun generateSecretKey(): Result<SecretKey> = runCatching {
|
||||
val keygen = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES)
|
||||
keygen.init(256)
|
||||
@@ -35,8 +37,9 @@ fun generateSecretKey(): Result<SecretKey> = runCatching {
|
||||
* Generate a fingerprint for the given symmetric key.
|
||||
*
|
||||
* This is intended to be used for implementing
|
||||
* [IAuthenticatorBridgeService.checkSymmetricEncryptionKeyFingerprint], which allows callers of the service
|
||||
* to verify that they have the correct symmetric key without actually having to send the key.
|
||||
* [IAuthenticatorBridgeService.checkSymmetricEncryptionKeyFingerprint], which allows callers of the
|
||||
* service to verify that they have the correct symmetric key without actually having to send the
|
||||
* key.
|
||||
*/
|
||||
fun SymmetricEncryptionKeyData.toFingerprint(): Result<SymmetricEncryptionKeyFingerprintData> =
|
||||
runCatching {
|
||||
@@ -87,7 +90,7 @@ internal fun EncryptedSharedAccountData.decrypt(
|
||||
val cipher = generateCipher()
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, iv)
|
||||
val decryptedModel = JSON.decodeFromString<SharedAccountDataJson>(
|
||||
cipher.doFinal(this.encryptedAccountsJson.byteArray).decodeToString()
|
||||
cipher.doFinal(this.encryptedAccountsJson.byteArray).decodeToString(),
|
||||
)
|
||||
decryptedModel.toDomainModel()
|
||||
}
|
||||
@@ -130,7 +133,7 @@ fun EncryptedAddTotpLoginItemData.decrypt(
|
||||
val cipher = generateCipher()
|
||||
cipher.init(Cipher.DECRYPT_MODE, key, iv)
|
||||
val decryptedModel = JSON.decodeFromString<AddTotpLoginItemDataJson>(
|
||||
cipher.doFinal(this.encryptedTotpUriJson.byteArray).decodeToString()
|
||||
cipher.doFinal(this.encryptedTotpUriJson.byteArray).decodeToString(),
|
||||
)
|
||||
decryptedModel.toDomainModel()
|
||||
}
|
||||
@@ -158,7 +161,7 @@ private fun generateCipher(): Cipher =
|
||||
Cipher.getInstance(
|
||||
KeyProperties.KEY_ALGORITHM_AES + "/" +
|
||||
KeyProperties.BLOCK_MODE_CBC + "/" +
|
||||
"PKCS5PADDING"
|
||||
"PKCS5PADDING",
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -173,7 +176,7 @@ private fun SharedAccountData.toJsonModel() = SharedAccountDataJson(
|
||||
email = account.email,
|
||||
totpUris = account.totpUris,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -188,7 +191,7 @@ private fun SharedAccountDataJson.toDomainModel() = SharedAccountData(
|
||||
email = account.email,
|
||||
totpUris = account.totpUris,
|
||||
)
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
/**
|
||||
@@ -199,7 +202,8 @@ private fun AddTotpLoginItemDataJson.toDomainModel() = AddTotpLoginItemData(
|
||||
)
|
||||
|
||||
/**
|
||||
* Helper function for converting [AddTotpLoginItemData] to a serializable [AddTotpLoginItemDataJson].
|
||||
* Helper function for converting [AddTotpLoginItemData] to a serializable
|
||||
* [AddTotpLoginItemDataJson].
|
||||
*/
|
||||
private fun AddTotpLoginItemData.toJsonModel() = AddTotpLoginItemDataJson(
|
||||
totpUri = totpUri,
|
||||
|
||||
@@ -164,6 +164,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
verify { context.bindService(any(), any(), Context.BIND_AUTO_CREATE) }
|
||||
}
|
||||
|
||||
@Suppress("MaxLineLength")
|
||||
@Test
|
||||
fun `onStart when Bitwarden app is present and bindService succeeds should set state to Loading before service calls back`() {
|
||||
val mockIntent: Intent = mockk()
|
||||
@@ -195,7 +196,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
@@ -224,7 +225,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
@@ -243,7 +244,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
fakeSymmetricKeyStorageProvider.symmetricKey = SYMMETRIC_KEY
|
||||
every {
|
||||
mockBridgeService.checkSymmetricEncryptionKeyFingerprint(
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull()
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull(),
|
||||
)
|
||||
} returns true
|
||||
val serviceConnection = slot<ServiceConnection>()
|
||||
@@ -257,7 +258,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
@@ -278,7 +279,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
fakeSymmetricKeyStorageProvider.symmetricKey = SYMMETRIC_KEY
|
||||
every {
|
||||
mockBridgeService.checkSymmetricEncryptionKeyFingerprint(
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull()
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull(),
|
||||
)
|
||||
} returns false
|
||||
every {
|
||||
@@ -295,7 +296,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
@@ -313,7 +314,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
@Suppress("MaxLineLength")
|
||||
fun `onAccountsSync should set AccountSyncState to decrypted response`() {
|
||||
val expectedAccounts = listOf<SharedAccountData.Account>(
|
||||
mockk()
|
||||
mockk(),
|
||||
)
|
||||
val encryptedAccounts: EncryptedSharedAccountData = mockk()
|
||||
val decryptedAccounts: SharedAccountData = mockk {
|
||||
@@ -323,7 +324,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
every { encryptedAccounts.decrypt(SYMMETRIC_KEY) } returns Result.success(decryptedAccounts)
|
||||
every {
|
||||
mockBridgeService.checkSymmetricEncryptionKeyFingerprint(
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull()
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull(),
|
||||
)
|
||||
} returns true
|
||||
fakeSymmetricKeyStorageProvider.symmetricKey = SYMMETRIC_KEY
|
||||
@@ -340,7 +341,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
@@ -363,7 +364,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
val encryptedAccounts: EncryptedSharedAccountData = mockk()
|
||||
every {
|
||||
mockBridgeService.checkSymmetricEncryptionKeyFingerprint(
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull()
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull(),
|
||||
)
|
||||
} returns true
|
||||
fakeSymmetricKeyStorageProvider.symmetricKey = SYMMETRIC_KEY
|
||||
@@ -380,7 +381,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
@@ -406,7 +407,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
every { encryptedAccounts.decrypt(SYMMETRIC_KEY) } returns Result.failure(RuntimeException())
|
||||
every {
|
||||
mockBridgeService.checkSymmetricEncryptionKeyFingerprint(
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull()
|
||||
SYMMETRIC_KEY.toFingerprint().getOrNull(),
|
||||
)
|
||||
} returns true
|
||||
fakeSymmetricKeyStorageProvider.symmetricKey = SYMMETRIC_KEY
|
||||
@@ -423,7 +424,7 @@ class AuthenticatorBridgeManagerTest {
|
||||
context.bindService(
|
||||
any(),
|
||||
capture(serviceConnection),
|
||||
Context.BIND_AUTO_CREATE
|
||||
Context.BIND_AUTO_CREATE,
|
||||
)
|
||||
} returns true
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ class AuthenticatorBridgeConnectionTypeExtensionsTest {
|
||||
fun `toPackageName RELEASE should map to correct release package`() {
|
||||
assertEquals(
|
||||
"com.x8bit.bitwarden",
|
||||
AuthenticatorBridgeConnectionType.RELEASE.toPackageName()
|
||||
AuthenticatorBridgeConnectionType.RELEASE.toPackageName(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ class AuthenticatorBridgeConnectionTypeExtensionsTest {
|
||||
fun `toPackageName DEV should map to correct dev package`() {
|
||||
assertEquals(
|
||||
"com.x8bit.bitwarden.dev",
|
||||
AuthenticatorBridgeConnectionType.DEV.toPackageName()
|
||||
AuthenticatorBridgeConnectionType.DEV.toPackageName(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ class EncryptionUtilTest {
|
||||
@Test
|
||||
fun `toFingerprint should return success when there are no internal exceptions`() {
|
||||
val keyData = SymmetricEncryptionKeyData(
|
||||
symmetricEncryptionKey = generateSecretKey().getOrThrow().encoded.toByteArrayContainer()
|
||||
symmetricEncryptionKey = generateSecretKey().getOrThrow().encoded.toByteArrayContainer(),
|
||||
)
|
||||
val result = keyData.toFingerprint()
|
||||
assertTrue(result.isSuccess)
|
||||
@@ -49,7 +49,7 @@ class EncryptionUtilTest {
|
||||
mockkStatic(MessageDigest::class)
|
||||
every { MessageDigest.getInstance("SHA-256") } throws NoSuchAlgorithmException()
|
||||
val keyData = SymmetricEncryptionKeyData(
|
||||
symmetricEncryptionKey = generateSecretKey().getOrThrow().encoded.toByteArrayContainer()
|
||||
symmetricEncryptionKey = generateSecretKey().getOrThrow().encoded.toByteArrayContainer(),
|
||||
)
|
||||
val result = keyData.toFingerprint()
|
||||
assertTrue(result.isFailure)
|
||||
@@ -100,7 +100,7 @@ class EncryptionUtilTest {
|
||||
.decrypt(SYMMETRIC_KEY)
|
||||
assertEquals(
|
||||
SHARED_ACCOUNT_DATA,
|
||||
result.getOrThrow()
|
||||
result.getOrThrow(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -148,7 +148,7 @@ class EncryptionUtilTest {
|
||||
.decrypt(SYMMETRIC_KEY)
|
||||
assertEquals(
|
||||
ADD_TOTP_ITEM,
|
||||
result.getOrThrow()
|
||||
result.getOrThrow(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -168,16 +168,16 @@ private val SHARED_ACCOUNT_DATA = SharedAccountData(
|
||||
email = "johnyapples@test.com",
|
||||
environmentLabel = "bitwarden.com",
|
||||
totpUris = listOf("test.com"),
|
||||
)
|
||||
)
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
private val ADD_TOTP_ITEM = AddTotpLoginItemData(
|
||||
totpUri = "test.com"
|
||||
totpUri = "test.com",
|
||||
)
|
||||
|
||||
private val SYMMETRIC_KEY = SymmetricEncryptionKeyData(
|
||||
symmetricEncryptionKey = generateSecretKey().getOrThrow().encoded.toByteArrayContainer()
|
||||
symmetricEncryptionKey = generateSecretKey().getOrThrow().encoded.toByteArrayContainer(),
|
||||
)
|
||||
|
||||
private val ENCRYPTED_SHARED_ACCOUNT_DATA =
|
||||
|
||||
Reference in New Issue
Block a user