mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: Passwordless for multiple CredentialIds
This commit is contained in:
@@ -950,14 +950,14 @@ class GroupActivity : DatabaseLockActivity(),
|
||||
}
|
||||
|
||||
private fun errorIfNeededForPasskeySelection(searchInfo: SearchInfo?) {
|
||||
if (mTypeMode == TypeMode.PASSKEY && searchInfo?.credentialId != null) {
|
||||
if (mTypeMode == TypeMode.PASSKEY && searchInfo?.credentialIds.isNullOrEmpty().not()) {
|
||||
removeSearch()
|
||||
// Build response with the entry selected
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
|
||||
buildPasskeyErrorAndSetResult(
|
||||
resources = resources,
|
||||
relyingPartyId = searchInfo.relyingParty,
|
||||
credentialId = searchInfo.credentialId
|
||||
credentialIds = searchInfo.credentialIds
|
||||
)
|
||||
}
|
||||
onValidateSpecialMode()
|
||||
|
||||
@@ -91,12 +91,13 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
private fun buildPasskeySearchInfo(relyingParty: String, credentialId: String? = null): SearchInfo {
|
||||
private fun buildPasskeySearchInfo(
|
||||
relyingParty: String,
|
||||
credentialIds: List<String> = listOf()
|
||||
): SearchInfo {
|
||||
return SearchInfo().apply {
|
||||
credentialId?.let {
|
||||
this.credentialId = it
|
||||
}
|
||||
this.relyingParty = relyingParty
|
||||
this.credentialIds = credentialIds
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,9 +146,10 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
|
||||
val publicKeyCredentialRequestOptions = PublicKeyCredentialRequestOptions(option.requestJson)
|
||||
val relyingPartyId = publicKeyCredentialRequestOptions.rpId
|
||||
val credentialId = publicKeyCredentialRequestOptions.allowCredentials.firstOrNull()?.id?.let { b64Encode(it) }
|
||||
val searchInfo = buildPasskeySearchInfo(relyingPartyId, credentialId)
|
||||
Log.d(TAG, "Build passkey search for relying party $relyingPartyId, credentialId $credentialId")
|
||||
val credentialIdList = publicKeyCredentialRequestOptions.allowCredentials
|
||||
.map { b64Encode(it.id) }
|
||||
val searchInfo = buildPasskeySearchInfo(relyingPartyId, credentialIdList)
|
||||
Log.d(TAG, "Build passkey search for relying party $relyingPartyId, credentialIds $credentialIdList")
|
||||
SearchHelper.checkAutoSearchInfo(
|
||||
context = this,
|
||||
database = mDatabase,
|
||||
@@ -181,7 +183,7 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
},
|
||||
onItemNotFound = { _ ->
|
||||
Log.w(TAG, "No passkey found in the database with this relying party : $relyingPartyId")
|
||||
if (credentialId == null) {
|
||||
if (credentialIdList.isEmpty()) {
|
||||
Log.d(TAG, "Add pending intent for passkey selection in opened database")
|
||||
PasskeyLauncherActivity.getPendingIntent(
|
||||
context = applicationContext,
|
||||
@@ -207,7 +209,7 @@ class PasskeyProviderService : CredentialProviderService() {
|
||||
getString(
|
||||
R.string.error_passkey_credential_id,
|
||||
relyingPartyId,
|
||||
credentialId
|
||||
credentialIdList
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
@@ -207,12 +207,12 @@ object PasskeyHelper {
|
||||
fun Activity.buildPasskeyErrorAndSetResult(
|
||||
resources: Resources,
|
||||
relyingPartyId: String?,
|
||||
credentialId: String?
|
||||
credentialIds: List<String>
|
||||
) {
|
||||
val error = resources.getString(
|
||||
R.string.error_passkey_credential_id,
|
||||
relyingPartyId,
|
||||
credentialId
|
||||
credentialIds
|
||||
)
|
||||
Log.e(javaClass.name, error)
|
||||
Toast.makeText(
|
||||
|
||||
@@ -94,7 +94,7 @@ object SearchHelper {
|
||||
callback.invoke(
|
||||
SearchParameters().apply {
|
||||
searchQuery = query
|
||||
searchOption = optionString()
|
||||
searchOptions = optionsString()
|
||||
allowEmptyQuery = false
|
||||
searchInTitles = false
|
||||
searchInUsernames = false
|
||||
|
||||
@@ -775,5 +775,5 @@
|
||||
<string name="passkey_backup_eligibility">Passkey Backup Eligibility</string>
|
||||
<string name="passkey_backup_state">Passkey Backup State</string>
|
||||
<string name="error_passkey_result">Unable to return the passkey</string>
|
||||
<string name="error_passkey_credential_id">No passkey found with relying party %1$s and credentialId %2$s</string>
|
||||
<string name="error_passkey_credential_id">No passkey found with relying party %1$s and credentialIds %2$s</string>
|
||||
</resources>
|
||||
@@ -27,9 +27,9 @@ import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField.isAppId
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField.isAppIdSignature
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField.isWebDomain
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isCredentialId
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isPasskey
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isRelyingParty
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isCredentialId
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOTP
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOTPURIField
|
||||
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||
@@ -178,7 +178,7 @@ class SearchHelper {
|
||||
}
|
||||
if (searchParameters.searchInRelyingParty) {
|
||||
val relyingParty = searchParameters.searchQuery
|
||||
val credentialId = searchParameters.searchOption
|
||||
val credentialIds = searchParameters.searchOptions
|
||||
val containsRelyingParty = entry.getExtraFields().any { field ->
|
||||
field.isRelyingParty()
|
||||
&& checkSearchQuery(
|
||||
@@ -191,17 +191,20 @@ class SearchHelper {
|
||||
}
|
||||
)
|
||||
}
|
||||
val containsCredentialId = if(credentialId == null) true
|
||||
// Check empty to allow any credential if not defined
|
||||
val containsCredentialId = if(credentialIds.isEmpty()) true
|
||||
else entry.getExtraFields().any { field ->
|
||||
field.isCredentialId()
|
||||
&& checkSearchQuery(
|
||||
stringToCheck = field.protectedValue.stringValue,
|
||||
searchParameters = SearchParameters().apply {
|
||||
searchQuery = credentialId
|
||||
caseSensitive = false
|
||||
isRegex = false
|
||||
}
|
||||
)
|
||||
&& credentialIds.any { credentialId ->
|
||||
checkSearchQuery(
|
||||
stringToCheck = field.protectedValue.stringValue,
|
||||
searchParameters = SearchParameters().apply {
|
||||
searchQuery = credentialId
|
||||
caseSensitive = false
|
||||
isRegex = false
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
return containsRelyingParty && containsCredentialId
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ import android.os.Parcelable
|
||||
class SearchParameters() : Parcelable{
|
||||
var searchQuery: String = ""
|
||||
// Add an optional string to search with the main search query
|
||||
var searchOption: String? = null
|
||||
var searchOptions: List<String> = listOf()
|
||||
var allowEmptyQuery = true
|
||||
var caseSensitive = false
|
||||
var isRegex = false
|
||||
|
||||
@@ -35,7 +35,7 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
return if (webDomain == null) null else field
|
||||
}
|
||||
var relyingParty: String? = null
|
||||
var credentialId: String? = null
|
||||
var credentialIds: List<String> = listOf()
|
||||
var otpString: String? = null
|
||||
|
||||
constructor()
|
||||
@@ -47,7 +47,7 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
webDomain = toCopy?.webDomain
|
||||
webScheme = toCopy?.webScheme
|
||||
relyingParty = toCopy?.relyingParty
|
||||
credentialId = toCopy?.credentialId
|
||||
credentialIds = toCopy?.credentialIds ?: listOf()
|
||||
otpString = toCopy?.otpString
|
||||
}
|
||||
|
||||
@@ -63,8 +63,9 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
webScheme = if (readScheme.isNullOrEmpty()) null else readScheme
|
||||
val readRelyingParty = parcel.readString()
|
||||
relyingParty = if (readRelyingParty.isNullOrEmpty()) null else readRelyingParty
|
||||
val readCredentialId = parcel.readString()
|
||||
credentialId = if (readCredentialId.isNullOrEmpty()) null else readCredentialId
|
||||
val readCredentialIdList = mutableListOf<String>()
|
||||
parcel.readStringList(readCredentialIdList)
|
||||
credentialIds = readCredentialIdList.toList()
|
||||
val readOtp = parcel.readString()
|
||||
otpString = if (readOtp.isNullOrEmpty()) null else readOtp
|
||||
}
|
||||
@@ -80,7 +81,7 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
parcel.writeString(webDomain ?: "")
|
||||
parcel.writeString(webScheme ?: "")
|
||||
parcel.writeString(relyingParty ?: "")
|
||||
parcel.writeString(credentialId ?: "")
|
||||
parcel.writeStringList(credentialIds)
|
||||
parcel.writeString(otpString ?: "")
|
||||
}
|
||||
|
||||
@@ -99,7 +100,7 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
&& webDomain == null
|
||||
&& webScheme == null
|
||||
&& relyingParty == null
|
||||
&& credentialId == null
|
||||
&& credentialIds.isEmpty()
|
||||
&& otpString == null
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
if (webDomain != other.webDomain) return false
|
||||
if (webScheme != other.webScheme) return false
|
||||
if (relyingParty != other.relyingParty) return false
|
||||
if (credentialId != other.credentialId) return false
|
||||
if (credentialIds != other.credentialIds) return false
|
||||
if (otpString != other.otpString) return false
|
||||
|
||||
return true
|
||||
@@ -146,7 +147,7 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
result = 31 * result + (webDomain?.hashCode() ?: 0)
|
||||
result = 31 * result + (webScheme?.hashCode() ?: 0)
|
||||
result = 31 * result + (relyingParty?.hashCode() ?: 0)
|
||||
result = 31 * result + (credentialId?.hashCode() ?: 0)
|
||||
result = 31 * result + (credentialIds.hashCode())
|
||||
result = 31 * result + (otpString?.hashCode() ?: 0)
|
||||
return result
|
||||
}
|
||||
@@ -155,8 +156,8 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
return otpString ?: webDomain ?: applicationId ?: relyingParty ?: tag ?: ""
|
||||
}
|
||||
|
||||
fun optionString(): String? {
|
||||
return if (isPasskeySearch && credentialId != null) credentialId else null
|
||||
fun optionsString(): List<String> {
|
||||
return if (isPasskeySearch && credentialIds.isNotEmpty()) credentialIds else listOf()
|
||||
}
|
||||
|
||||
fun toRegisterInfo(): RegisterInfo {
|
||||
|
||||
Reference in New Issue
Block a user