mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: User Verified response flag
This commit is contained in:
@@ -46,13 +46,15 @@ import com.kunzisoft.keepass.credentialprovider.EntrySelectionHelper.setActivity
|
||||
import com.kunzisoft.keepass.credentialprovider.SpecialMode
|
||||
import com.kunzisoft.keepass.credentialprovider.TypeMode
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.AndroidPrivilegedApp
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.UserVerificationRequirement
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.ALLOWED_AUTHENTICATORS
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.addAppOrigin
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.addAuthCode
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.addUserVerificationRequired
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.addUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.getUserVerificationCondition
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.getUserVerifiedWithAuth
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.isAuthenticatorsAllowed
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.isUserVerificationRequired
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.removeUserVerificationRequired
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.removeUserVerification
|
||||
import com.kunzisoft.keepass.credentialprovider.viewmodel.CredentialLauncherViewModel
|
||||
import com.kunzisoft.keepass.credentialprovider.viewmodel.PasskeyLauncherViewModel
|
||||
import com.kunzisoft.keepass.database.ContextualDatabase
|
||||
@@ -91,16 +93,17 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
// To manage https://github.com/Kunzisoft/KeePassDX/issues/2283
|
||||
if (intent.isUserVerificationRequired()) {
|
||||
val userVerificationCondition = intent.getUserVerificationCondition()
|
||||
if (userVerificationCondition) {
|
||||
if (isAuthenticatorsAllowed().not()) {
|
||||
intent.removeUserVerificationRequired()
|
||||
intent.removeUserVerification()
|
||||
sendBroadcast(Intent(LOCK_ACTION))
|
||||
}
|
||||
}
|
||||
// super.onCreate must be after UserVerification to allow database lock
|
||||
super.onCreate(savedInstanceState)
|
||||
// Biometric must be after super.onCreate
|
||||
if (intent.isUserVerificationRequired()) {
|
||||
if (userVerificationCondition) {
|
||||
if (isAuthenticatorsAllowed()) {
|
||||
BiometricPrompt(
|
||||
this, ContextCompat.getMainExecutor(this),
|
||||
@@ -127,7 +130,7 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
result: BiometricPrompt.AuthenticationResult
|
||||
) {
|
||||
super.onAuthenticationSucceeded(result)
|
||||
passkeyLauncherViewModel.launchAction(intent, mSpecialMode)
|
||||
passkeyLauncherViewModel.launchAction(userVerified = true, intent, mSpecialMode)
|
||||
}
|
||||
override fun onAuthenticationFailed() {
|
||||
super.onAuthenticationFailed()
|
||||
@@ -146,7 +149,7 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
|
||||
lifecycleScope.launch {
|
||||
// Initialize the parameters
|
||||
passkeyLauncherViewModel.initialize()
|
||||
passkeyLauncherViewModel.initialize(userVerified = intent.getUserVerifiedWithAuth())
|
||||
// Retrieve the UI
|
||||
passkeyLauncherViewModel.uiState.collect { uiState ->
|
||||
when (uiState) {
|
||||
@@ -340,7 +343,8 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
searchInfo: SearchInfo? = null,
|
||||
appOrigin: AppOrigin? = null,
|
||||
nodeId: UUID? = null,
|
||||
userVerificationRequired: Boolean = false
|
||||
userVerification: UserVerificationRequirement = UserVerificationRequirement.PREFERRED,
|
||||
userVerifiedWithAuth: Boolean = true
|
||||
): PendingIntent? {
|
||||
return PendingIntent.getActivity(
|
||||
context,
|
||||
@@ -352,7 +356,7 @@ class PasskeyLauncherActivity : DatabaseLockActivity() {
|
||||
addAppOrigin(appOrigin)
|
||||
addNodeId(nodeId)
|
||||
addAuthCode(nodeId)
|
||||
addUserVerificationRequired(userVerificationRequired)
|
||||
addUserVerification(userVerification, userVerifiedWithAuth)
|
||||
},
|
||||
PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_UPDATE_CURRENT
|
||||
)
|
||||
|
||||
@@ -157,9 +157,9 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
val credentialIdList = publicKeyCredentialRequestOptions.allowCredentials
|
||||
.map { b64Encode(it.id) }
|
||||
val searchInfo = buildPasskeySearchInfo(relyingPartyId, credentialIdList)
|
||||
val userVerificationRequired = publicKeyCredentialRequestOptions
|
||||
.userVerification == UserVerificationRequirement.REQUIRED
|
||||
Log.d(TAG, "Build passkey search for UV $userVerificationRequired, " +
|
||||
//val userVerification = publicKeyCredentialRequestOptions.userVerification
|
||||
val userVerification = UserVerificationRequirement.REQUIRED
|
||||
Log.d(TAG, "Build passkey search for UV $userVerification, " +
|
||||
"RP $relyingPartyId and Credential IDs $credentialIdList")
|
||||
SearchHelper.checkAutoSearchInfo(
|
||||
context = this,
|
||||
@@ -170,7 +170,7 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
passkeyEntries = passkeyEntries,
|
||||
searchInfo = searchInfo,
|
||||
option = option,
|
||||
userVerificationRequired = userVerificationRequired
|
||||
userVerification = userVerification
|
||||
) {
|
||||
Log.d(TAG, "Add pending intent for passkey selection with found items")
|
||||
for (passkeyEntry in items) {
|
||||
@@ -179,7 +179,8 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
nodeId = passkeyEntry.id,
|
||||
appOrigin = passkeyEntry.appOrigin,
|
||||
userVerificationRequired = userVerificationRequired
|
||||
userVerification = userVerification,
|
||||
userVerifiedWithAuth = false
|
||||
)?.let { usagePendingIntent ->
|
||||
val passkey = passkeyEntry.passkey
|
||||
passkeyEntries.add(
|
||||
@@ -208,7 +209,7 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
passkeyEntries = passkeyEntries,
|
||||
searchInfo = searchInfo,
|
||||
option = option,
|
||||
userVerificationRequired = userVerificationRequired
|
||||
userVerification = userVerification,
|
||||
) {
|
||||
Log.w(TAG, "No passkey found in the database with this relying party : $relyingPartyId")
|
||||
if (credentialIdList.isEmpty()) {
|
||||
@@ -217,7 +218,8 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
searchInfo = searchInfo,
|
||||
userVerificationRequired = userVerificationRequired
|
||||
userVerification = userVerification,
|
||||
userVerifiedWithAuth = false
|
||||
)?.let { pendingIntent ->
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
@@ -250,7 +252,8 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
searchInfo = searchInfo
|
||||
searchInfo = searchInfo,
|
||||
userVerifiedWithAuth = true
|
||||
)?.let { pendingIntent ->
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
@@ -277,15 +280,16 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
passkeyEntries: MutableList<CredentialEntry>,
|
||||
searchInfo: SearchInfo,
|
||||
option: BeginGetPublicKeyCredentialOption,
|
||||
userVerificationRequired: Boolean,
|
||||
userVerification: UserVerificationRequirement,
|
||||
standardAction: () -> Unit
|
||||
) {
|
||||
if (userVerificationRequired && isAuthenticatorsAllowed().not()) {
|
||||
if (userVerification == UserVerificationRequirement.REQUIRED && isAuthenticatorsAllowed().not()) {
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
specialMode = SpecialMode.SELECTION,
|
||||
searchInfo = searchInfo,
|
||||
userVerificationRequired = true
|
||||
userVerification = userVerification,
|
||||
userVerifiedWithAuth = true
|
||||
)?.let { pendingIntent ->
|
||||
passkeyEntries.add(
|
||||
PublicKeyCredentialEntry(
|
||||
|
||||
@@ -60,6 +60,7 @@ import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredential
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialCreationParameters
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialRequestOptions
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredentialUsageParameters
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.data.UserVerificationRequirement
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PrivilegedAllowLists.getOriginFromPrivilegedAllowLists
|
||||
import com.kunzisoft.keepass.model.AndroidOrigin
|
||||
import com.kunzisoft.keepass.model.AppOrigin
|
||||
@@ -67,7 +68,9 @@ import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.Passkey
|
||||
import com.kunzisoft.keepass.utils.AppUtil
|
||||
import com.kunzisoft.keepass.utils.StringUtil.toHexString
|
||||
import com.kunzisoft.keepass.utils.getEnumExtra
|
||||
import com.kunzisoft.keepass.utils.getParcelableExtraCompat
|
||||
import com.kunzisoft.keepass.utils.putEnumExtra
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.withContext
|
||||
import java.io.IOException
|
||||
@@ -95,7 +98,8 @@ object PasskeyHelper {
|
||||
private const val EXTRA_APP_ORIGIN = "com.kunzisoft.keepass.extra.appOrigin"
|
||||
private const val EXTRA_TIMESTAMP = "com.kunzisoft.keepass.extra.timestamp"
|
||||
private const val EXTRA_AUTHENTICATION_CODE = "com.kunzisoft.keepass.extra.authenticationCode"
|
||||
private const val EXTRA_UV_REQUIRED = "com.kunzisoft.keepass.extra.userVerification"
|
||||
private const val EXTRA_USER_VERIFICATION = "com.kunzisoft.keepass.extra.userVerification"
|
||||
private const val EXTRA_USER_VERIFIED_WITH_AUTH = "com.kunzisoft.keepass.extra.userVerifiedWithAuth"
|
||||
|
||||
private const val SEPARATOR = "_"
|
||||
|
||||
@@ -113,26 +117,46 @@ object PasskeyHelper {
|
||||
private val internalSecureRandom: SecureRandom = SecureRandom()
|
||||
|
||||
/**
|
||||
* Add the user verification to the intent
|
||||
* Add the User Verification to the intent
|
||||
*/
|
||||
fun Intent.addUserVerificationRequired(userVerification: Boolean) {
|
||||
putExtra(EXTRA_UV_REQUIRED, userVerification)
|
||||
fun Intent.addUserVerification(
|
||||
userVerification: UserVerificationRequirement,
|
||||
userVerifiedWithAuth: Boolean
|
||||
) {
|
||||
putEnumExtra(EXTRA_USER_VERIFICATION, userVerification)
|
||||
putExtra(EXTRA_USER_VERIFIED_WITH_AUTH, userVerifiedWithAuth)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user verification is required
|
||||
* Get the User Verification from the intent
|
||||
*/
|
||||
fun Intent.isUserVerificationRequired(): Boolean {
|
||||
return getBooleanExtra(EXTRA_UV_REQUIRED, false)
|
||||
fun Intent.getUserVerificationCondition(): Boolean {
|
||||
return (getEnumExtra<UserVerificationRequirement>(EXTRA_USER_VERIFICATION)
|
||||
?: UserVerificationRequirement.PREFERRED) == UserVerificationRequirement.REQUIRED
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the user verification from the intent
|
||||
* Define if the User is verified with authentification from the intent
|
||||
*/
|
||||
fun Intent.removeUserVerificationRequired() {
|
||||
removeExtra(EXTRA_UV_REQUIRED)
|
||||
fun Intent.getUserVerifiedWithAuth(): Boolean {
|
||||
return getBooleanExtra(EXTRA_USER_VERIFIED_WITH_AUTH, true)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the User Verification from the intent
|
||||
*/
|
||||
fun Intent.removeUserVerification() {
|
||||
removeExtra(EXTRA_USER_VERIFICATION)
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove the User verified with auth from the intent
|
||||
*/
|
||||
fun Intent.removeUserVerifiedWithAuth() {
|
||||
removeExtra(EXTRA_USER_VERIFIED_WITH_AUTH)
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Allowed authenticators for the User Verification
|
||||
*/
|
||||
@@ -622,6 +646,7 @@ object PasskeyHelper {
|
||||
requestOptions: PublicKeyCredentialRequestOptions,
|
||||
clientDataResponse: ClientDataResponse,
|
||||
passkey: Passkey,
|
||||
userVerified: Boolean,
|
||||
defaultBackupEligibility: Boolean,
|
||||
defaultBackupState: Boolean
|
||||
): PublicKeyCredential {
|
||||
@@ -630,7 +655,7 @@ object PasskeyHelper {
|
||||
response = AuthenticatorAssertionResponse(
|
||||
requestOptions = requestOptions,
|
||||
userPresent = true,
|
||||
userVerified = true,
|
||||
userVerified = userVerified,
|
||||
backupEligibility = passkey.backupEligibility ?: defaultBackupEligibility,
|
||||
backupState = passkey.backupState ?: defaultBackupState,
|
||||
userHandle = passkey.userHandle,
|
||||
|
||||
@@ -24,8 +24,8 @@ import com.kunzisoft.keepass.credentialprovider.passkey.data.PublicKeyCredential
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.buildCreatePublicKeyCredentialResponse
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.buildPasskeyPublicKeyCredential
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.checkSecurity
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.getUserVerificationCondition
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.getVerifiedGETClientDataResponse
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.isUserVerificationRequired
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.removeAppOrigin
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.removePasskey
|
||||
import com.kunzisoft.keepass.credentialprovider.passkey.util.PasskeyHelper.retrieveAppOrigin
|
||||
@@ -65,14 +65,16 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
private var mPasskey: Passkey? = null
|
||||
|
||||
private var mLockDatabaseAfterSelection: Boolean = false
|
||||
private var mUserVerified: Boolean = true
|
||||
private var mBackupEligibility: Boolean = true
|
||||
private var mBackupState: Boolean = false
|
||||
|
||||
private val mUiState = MutableStateFlow<UIState>(UIState.Loading)
|
||||
val uiState: StateFlow<UIState> = mUiState
|
||||
|
||||
fun initialize() {
|
||||
fun initialize(userVerified: Boolean) {
|
||||
mLockDatabaseAfterSelection = PreferencesUtil.isPasskeyCloseDatabaseEnable(getApplication())
|
||||
mUserVerified = userVerified
|
||||
mBackupEligibility = PreferencesUtil.isPasskeyBackupEligibilityEnable(getApplication())
|
||||
mBackupState = PreferencesUtil.isPasskeyBackupStateEnable(getApplication())
|
||||
}
|
||||
@@ -151,9 +153,11 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
}
|
||||
|
||||
fun launchAction(
|
||||
userVerified: Boolean,
|
||||
intent: Intent,
|
||||
specialMode: SpecialMode,
|
||||
) {
|
||||
this.mUserVerified = userVerified
|
||||
super.launchActionIfNeeded(intent, specialMode, mDatabase)
|
||||
}
|
||||
|
||||
@@ -162,7 +166,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
specialMode: SpecialMode,
|
||||
database: ContextualDatabase?
|
||||
) {
|
||||
if (intent.isUserVerificationRequired()) {
|
||||
if (intent.getUserVerificationCondition()) {
|
||||
if (database != null) {
|
||||
onDatabaseRetrieved(database)
|
||||
}
|
||||
@@ -321,6 +325,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
appOrigin = appOrigin
|
||||
),
|
||||
passkey = passkey,
|
||||
userVerified = mUserVerified,
|
||||
defaultBackupEligibility = mBackupEligibility,
|
||||
defaultBackupState = mBackupState
|
||||
)
|
||||
@@ -377,6 +382,7 @@ class PasskeyLauncherViewModel(application: Application): CredentialLauncherView
|
||||
appOrigin = appOrigin
|
||||
),
|
||||
passkey = passkey,
|
||||
userVerified = mUserVerified,
|
||||
defaultBackupEligibility = mBackupEligibility,
|
||||
defaultBackupState = mBackupState
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user