Skip to content

Commit

Permalink
Extract SecureArea-specific UI into an interface (#393)
Browse files Browse the repository at this point in the history
  • Loading branch information
mitrejcevski authored Nov 15, 2023
1 parent 60fcadc commit 83840ae
Show file tree
Hide file tree
Showing 52 changed files with 1,579 additions and 1,412 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,40 @@
package com.android.identity.wallet.selfsigned
package com.android.mdl.app.selfsigned

import androidx.lifecycle.SavedStateHandle
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import com.android.identity.android.securearea.AndroidKeystoreSecureArea
import com.android.identity.android.storage.AndroidStorageEngine
import com.android.identity.securearea.SecureAreaRepository
import com.android.identity.securearea.SoftwareSecureArea
import com.android.identity.wallet.document.DocumentColor
import com.android.identity.wallet.document.DocumentType
import com.android.identity.wallet.document.SecureAreaImplementationState
import com.android.identity.wallet.selfsigned.AddSelfSignedScreenState.AndroidAuthKeyCurveState
import com.android.identity.wallet.selfsigned.AddSelfSignedScreenState.AuthTypeState
import com.android.identity.wallet.selfsigned.AddSelfSignedScreenState.MdocAuthOptionState
import com.android.identity.wallet.selfsigned.AddSelfSignedScreenState
import com.android.identity.wallet.selfsigned.AddSelfSignedViewModel
import com.android.identity.wallet.util.PreferencesHelper
import com.android.identity.wallet.util.ProvisioningUtil
import com.google.common.truth.Truth.assertThat
import org.junit.jupiter.api.Test
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
class SelfSignedScreenStateTest {

private val savedStateHandle = SavedStateHandle()
private lateinit var repository: SecureAreaRepository

@Before
fun setUp() {
val context = InstrumentationRegistry.getInstrumentation().targetContext
repository = ProvisioningUtil.getInstance(context).secureAreaRepository
val storageDir = PreferencesHelper.getKeystoreBackedStorageLocation(context)
val storageEngine = AndroidStorageEngine.Builder(context, storageDir).build()
val androidKeystoreSecureArea = AndroidKeystoreSecureArea(context, storageEngine)
val softwareSecureArea = SoftwareSecureArea(storageEngine)
repository.addImplementation(androidKeystoreSecureArea)
repository.addImplementation(softwareSecureArea)
}

@Test
fun defaultScreenState() {
Expand Down Expand Up @@ -72,127 +94,6 @@ class SelfSignedScreenStateTest {
.isEqualTo(AddSelfSignedScreenState(cardArt = blue))
}

@Test
fun updateKeystoreImplementation() {
val bouncyCastle = SecureAreaImplementationState.BouncyCastle
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateKeystoreImplementation(bouncyCastle)

assertThat(viewModel.screenState.value).isEqualTo(
AddSelfSignedScreenState(secureAreaImplementationState = bouncyCastle)
)
}

@Test
fun updateUserAuthentication() {
val authenticationOn = true
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateUserAuthentication(authenticationOn)

assertThat(viewModel.screenState.value)
.isEqualTo(AddSelfSignedScreenState(userAuthentication = authenticationOn))
}

@Test
fun updateUserAuthenticationTimeoutSeconds() {
val newValue = 12
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateUserAuthenticationTimeoutSeconds(newValue)

assertThat(viewModel.screenState.value)
.isEqualTo(AddSelfSignedScreenState(userAuthenticationTimeoutSeconds = newValue))
}

@Test
fun updateUserAuthenticationTimeoutSecondsInvalidValue() {
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateUserAuthenticationTimeoutSeconds(1)
viewModel.updateUserAuthenticationTimeoutSeconds(0)
viewModel.updateUserAuthenticationTimeoutSeconds(-1)

assertThat(viewModel.screenState.value)
.isEqualTo(AddSelfSignedScreenState(userAuthenticationTimeoutSeconds = 0))
}

@Test
fun updateAllowedLskfUnlocking() {
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateLskfUnlocking(false)

assertThat(viewModel.screenState.value.allowLSKFUnlocking)
.isEqualTo(AuthTypeState(isEnabled = false, canBeModified = false))
}

@Test
fun updateAllowedLskfUnlockingWhenBiometricIsOff() {
val viewModel = AddSelfSignedViewModel(savedStateHandle)
viewModel.updateBiometricUnlocking(false)

viewModel.updateLskfUnlocking(false)

assertThat(viewModel.screenState.value.allowLSKFUnlocking)
.isEqualTo(AuthTypeState(isEnabled = true, canBeModified = false))
}

@Test
fun updateAllowedBiometricUnlocking() {
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateBiometricUnlocking(false)

assertThat(viewModel.screenState.value.allowBiometricUnlocking)
.isEqualTo(AuthTypeState(isEnabled = false, canBeModified = false))
}

@Test
fun updateAllowedBiometricUnlockingWhenLskfIsOff() {
val viewModel = AddSelfSignedViewModel(savedStateHandle)
viewModel.updateLskfUnlocking(false)

viewModel.updateBiometricUnlocking(false)

assertThat(viewModel.screenState.value.allowBiometricUnlocking)
.isEqualTo(AuthTypeState(isEnabled = true, canBeModified = false))
}

@Test
fun updateStrongBox() {
val enabled = true
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateStrongBox(enabled)

assertThat(viewModel.screenState.value.useStrongBox)
.isEqualTo(AuthTypeState(isEnabled = enabled, canBeModified = false))
}

@Test
fun updateMdocAuthOption() {
val authOption = AddSelfSignedScreenState.MdocAuthStateOption.MAC
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateMdocAuthOption(authOption)

assertThat(viewModel.screenState.value.androidMdocAuthState)
.isEqualTo(MdocAuthOptionState(isEnabled = true, mDocAuthentication = authOption))
}

@Test
fun updateAndroidAuthKeyCurve() {
val x25519 = AddSelfSignedScreenState.AndroidAuthKeyCurveOption.X25519
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updateAndroidAuthKeyCurve(x25519)

assertThat(viewModel.screenState.value.androidAuthKeyCurveState)
.isEqualTo(AndroidAuthKeyCurveState(isEnabled = true, authCurve = x25519))
}

@Test
fun updateValidityInDays() {
val newValue = 15
Expand Down Expand Up @@ -240,17 +141,6 @@ class SelfSignedScreenStateTest {
.isEqualTo(minValidityInDays)
}

@Test
fun updateBouncyCastlePassphrase() {
val newPassphrase = ":irrelevant:"
val viewModel = AddSelfSignedViewModel(savedStateHandle)

viewModel.updatePassphrase(newPassphrase)

assertThat(viewModel.screenState.value)
.isEqualTo(AddSelfSignedScreenState(passphrase = newPassphrase))
}

@Test
fun updateNumberOfMso() {
val msoCount = 2
Expand Down
24 changes: 24 additions & 0 deletions appholder/src/main/java/com/android/identity/wallet/HolderApp.kt
Original file line number Diff line number Diff line change
@@ -1,10 +1,17 @@
package com.android.identity.wallet

import android.app.Application
import android.content.Context
import com.android.identity.android.securearea.AndroidKeystoreSecureArea
import com.android.identity.android.storage.AndroidStorageEngine
import com.android.identity.android.util.AndroidLogPrinter
import com.android.identity.credential.CredentialStore
import com.android.identity.securearea.SecureAreaRepository
import com.android.identity.securearea.SoftwareSecureArea
import com.android.identity.util.Logger
import com.android.identity.wallet.util.PeriodicKeysRefreshWorkRequest
import com.android.identity.wallet.util.PreferencesHelper
import com.android.identity.wallet.util.ProvisioningUtil
import com.google.android.material.color.DynamicColors
import org.bouncycastle.jce.provider.BouncyCastleProvider
import java.security.Security
Expand All @@ -22,4 +29,21 @@ class HolderApp: Application() {
PreferencesHelper.initialize(this)
PeriodicKeysRefreshWorkRequest(this).schedulePeriodicKeysRefreshing()
}

companion object {
fun createCredentialStore(
context: Context,
keystoreEngineRepository: SecureAreaRepository
): CredentialStore {
val storageDir = PreferencesHelper.getKeystoreBackedStorageLocation(context)
val storageEngine = AndroidStorageEngine.Builder(context, storageDir).build()

val androidKeystoreSecureArea = AndroidKeystoreSecureArea(context, storageEngine)
val softwareSecureArea = SoftwareSecureArea(storageEngine)

keystoreEngineRepository.addImplementation(androidKeystoreSecureArea)
keystoreEngineRepository.addImplementation(softwareSecureArea)
return CredentialStore(storageEngine, keystoreEngineRepository)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ import androidx.navigation.findNavController
import androidx.navigation.ui.NavigationUI
import androidx.navigation.ui.NavigationUI.setupActionBarWithNavController
import androidx.navigation.ui.setupWithNavController
import androidx.preference.PreferenceManager
import com.android.identity.mdoc.origininfo.OriginInfo
import com.android.identity.mdoc.origininfo.OriginInfoReferrerUrl
import com.android.identity.util.Logger
Expand All @@ -25,8 +24,6 @@ import com.android.identity.wallet.util.logInfo
import com.android.identity.wallet.util.logWarning
import com.android.identity.wallet.viewmodel.ShareDocumentViewModel
import com.google.android.material.elevation.SurfaceColors
import java.security.Security
import org.bouncycastle.jce.provider.BouncyCastleProvider

class MainActivity : AppCompatActivity() {

Expand Down
Loading

0 comments on commit 83840ae

Please sign in to comment.