mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
fix: Allow to check multiple app signatures #1421
This commit is contained in:
@@ -33,9 +33,9 @@ import com.kunzisoft.keepass.database.element.node.Node
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.database.element.node.NodeIdUUID
|
||||
import com.kunzisoft.keepass.database.element.node.Type
|
||||
import com.kunzisoft.keepass.model.AppOrigin
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField
|
||||
import com.kunzisoft.keepass.model.EntryInfo
|
||||
import com.kunzisoft.keepass.model.OriginApp
|
||||
import com.kunzisoft.keepass.model.OriginAppEntryField
|
||||
import com.kunzisoft.keepass.model.Passkey
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
@@ -367,9 +367,9 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
||||
return null
|
||||
}
|
||||
|
||||
fun getOriginApp(): OriginApp? {
|
||||
fun getAppOrigin(): AppOrigin? {
|
||||
entryKDBX?.let {
|
||||
return OriginAppEntryField.parseFields { key ->
|
||||
return AppOriginEntryField.parseFields { key ->
|
||||
it.getFieldValue(key)?.toString()
|
||||
}
|
||||
}
|
||||
@@ -494,7 +494,7 @@ class Entry : Node, EntryVersionedInterface<Group> {
|
||||
entryInfo.otpModel = getOtpElement()?.otpModel
|
||||
// Add Passkey
|
||||
entryInfo.passkey = getPasskey()
|
||||
entryInfo.originApp = getOriginApp()
|
||||
entryInfo.appOrigin = getAppOrigin()
|
||||
if (!raw) {
|
||||
// Replace parameter fields by generated OTP fields
|
||||
entryInfo.customFields = OtpEntryFields.generateAutoFields(entryInfo.customFields)
|
||||
|
||||
@@ -23,8 +23,39 @@ import android.os.Parcelable
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@Parcelize
|
||||
data class OriginApp(
|
||||
val appId: String? = null,
|
||||
val appSignature: String? = null,
|
||||
val webDomain: String? = null
|
||||
data class AppOrigin(
|
||||
val appIdentifiers: MutableList<AppIdentifier> = mutableListOf(),
|
||||
val webDomains: MutableList<String> = mutableListOf()
|
||||
) : Parcelable {
|
||||
|
||||
fun addIdentifier(appIdentifier: AppIdentifier) {
|
||||
appIdentifiers.add(appIdentifier)
|
||||
}
|
||||
|
||||
fun addWebDomain(webDomain: String) {
|
||||
this.webDomains.add(webDomain)
|
||||
}
|
||||
|
||||
fun removeAppElement(appIdentifier: AppIdentifier) {
|
||||
appIdentifiers.remove(appIdentifier)
|
||||
}
|
||||
|
||||
fun removeWebDomain(webDomain: String) {
|
||||
this.webDomains.remove(webDomain)
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
appIdentifiers.clear()
|
||||
webDomains.clear()
|
||||
}
|
||||
|
||||
fun isEmpty(): Boolean {
|
||||
return appIdentifiers.isEmpty() && webDomains.isEmpty()
|
||||
}
|
||||
}
|
||||
|
||||
@Parcelize
|
||||
data class AppIdentifier(
|
||||
val id: String,
|
||||
val signature: String? = null,
|
||||
) : Parcelable
|
||||
@@ -21,25 +21,51 @@ package com.kunzisoft.keepass.model
|
||||
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.security.ProtectedString
|
||||
import com.kunzisoft.keepass.model.EntryInfo.Companion.suffixFieldNamePosition
|
||||
|
||||
object OriginAppEntryField {
|
||||
object AppOriginEntryField {
|
||||
|
||||
const val WEB_DOMAIN_FIELD_NAME = "URL"
|
||||
const val APPLICATION_ID_FIELD_NAME = "AndroidApp"
|
||||
const val APPLICATION_SIGNATURE_FIELD_NAME = "AndroidApp Signature"
|
||||
|
||||
/**
|
||||
* Parse fields of an entry to retrieve a an OriginApp
|
||||
* Parse fields of an entry to retrieve a an AppOrigin
|
||||
*/
|
||||
fun parseFields(getField: (id: String) -> String?): OriginApp {
|
||||
val appIdField = getField(APPLICATION_ID_FIELD_NAME)
|
||||
val appSignatureField = getField(APPLICATION_SIGNATURE_FIELD_NAME)
|
||||
val webDomainField = getField(WEB_DOMAIN_FIELD_NAME)
|
||||
return OriginApp(
|
||||
appId = appIdField,
|
||||
appSignature = appSignatureField,
|
||||
webDomain = webDomainField
|
||||
)
|
||||
fun parseFields(getField: (id: String) -> String?): AppOrigin {
|
||||
val appOrigin = AppOrigin()
|
||||
// Get Application identifiers
|
||||
generateSequence(0) { it + 1 }
|
||||
.map { position ->
|
||||
val appId = getField(APPLICATION_ID_FIELD_NAME + suffixFieldNamePosition(position))
|
||||
val appSignature = getField(APPLICATION_SIGNATURE_FIELD_NAME + suffixFieldNamePosition(position))
|
||||
// Pair them up, if appId is null, we stop
|
||||
if (appId != null) {
|
||||
appId to (appSignature ?: "")
|
||||
} else {
|
||||
// Stop
|
||||
null
|
||||
}
|
||||
}.takeWhile { it != null }
|
||||
.forEach { pair ->
|
||||
appOrigin.addIdentifier(
|
||||
AppIdentifier(pair!!.first, pair.second)
|
||||
)
|
||||
}
|
||||
// Get Domains
|
||||
var domainFieldPosition = 0
|
||||
while (true) {
|
||||
val domainKey = WEB_DOMAIN_FIELD_NAME + suffixFieldNamePosition(domainFieldPosition)
|
||||
val domainValue = getField(domainKey)
|
||||
if (domainValue != null) {
|
||||
appOrigin.addWebDomain(domainValue)
|
||||
domainFieldPosition++
|
||||
} else {
|
||||
break // No more domain found
|
||||
}
|
||||
}
|
||||
|
||||
return appOrigin
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -102,10 +128,16 @@ object OriginAppEntryField {
|
||||
}
|
||||
}
|
||||
|
||||
fun EntryInfo.setOriginApp(originApp: OriginApp?, customFieldsAllowed: Boolean) {
|
||||
if (originApp != null) {
|
||||
setApplicationId(originApp.appId, originApp.appSignature)
|
||||
setWebDomain(originApp.webDomain, null, customFieldsAllowed)
|
||||
/**
|
||||
* Assign an AppOrigin to an EntryInfo,
|
||||
* Only if [customFieldsAllowed] is true
|
||||
*/
|
||||
fun EntryInfo.setAppOrigin(appOrigin: AppOrigin?, customFieldsAllowed: Boolean) {
|
||||
appOrigin?.appIdentifiers?.forEach { appIdentifier ->
|
||||
setApplicationId(appIdentifier.id, appIdentifier.signature)
|
||||
}
|
||||
appOrigin?.webDomains?.forEach { webDomain ->
|
||||
setWebDomain(webDomain, null, customFieldsAllowed)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,10 +27,10 @@ import com.kunzisoft.keepass.database.element.Database
|
||||
import com.kunzisoft.keepass.database.element.Field
|
||||
import com.kunzisoft.keepass.database.element.Tags
|
||||
import com.kunzisoft.keepass.database.element.entry.AutoType
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField.setAppOrigin
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField.setApplicationId
|
||||
import com.kunzisoft.keepass.model.AppOriginEntryField.setWebDomain
|
||||
import com.kunzisoft.keepass.model.CreditCardEntryFields.setCreditCard
|
||||
import com.kunzisoft.keepass.model.OriginAppEntryField.setApplicationId
|
||||
import com.kunzisoft.keepass.model.OriginAppEntryField.setOriginApp
|
||||
import com.kunzisoft.keepass.model.OriginAppEntryField.setWebDomain
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isPasskeyExclusion
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.setPasskey
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
@@ -59,7 +59,7 @@ class EntryInfo : NodeInfo {
|
||||
var autoType: AutoType = AutoType()
|
||||
var otpModel: OtpModel? = null
|
||||
var passkey: Passkey? = null
|
||||
var originApp: OriginApp? = null
|
||||
var appOrigin: AppOrigin? = null
|
||||
var isTemplate: Boolean = false
|
||||
|
||||
constructor() : super()
|
||||
@@ -80,7 +80,7 @@ class EntryInfo : NodeInfo {
|
||||
autoType = parcel.readParcelableCompat() ?: autoType
|
||||
otpModel = parcel.readParcelableCompat() ?: otpModel
|
||||
passkey = parcel.readParcelableCompat() ?: passkey
|
||||
originApp = parcel.readParcelableCompat() ?: originApp
|
||||
appOrigin = parcel.readParcelableCompat() ?: appOrigin
|
||||
isTemplate = parcel.readBooleanCompat()
|
||||
}
|
||||
|
||||
@@ -103,7 +103,7 @@ class EntryInfo : NodeInfo {
|
||||
parcel.writeParcelable(autoType, flags)
|
||||
parcel.writeParcelable(otpModel, flags)
|
||||
parcel.writeParcelable(passkey, flags)
|
||||
parcel.writeParcelable(originApp, flags)
|
||||
parcel.writeParcelable(appOrigin, flags)
|
||||
parcel.writeBooleanCompat(isTemplate)
|
||||
}
|
||||
|
||||
@@ -138,13 +138,6 @@ class EntryInfo : NodeInfo {
|
||||
} ?: customFields.add(field)
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a field name suffix depending on the field position
|
||||
*/
|
||||
private fun suffixFieldNamePosition(position: Int): String {
|
||||
return if (position > 0) "_$position" else ""
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a field to the custom fields list with a suffix position,
|
||||
* replace if name already exists
|
||||
@@ -218,8 +211,8 @@ class EntryInfo : NodeInfo {
|
||||
registerInfo.password?.let { password = it }
|
||||
setCreditCard(registerInfo.creditCard)
|
||||
setPasskey(registerInfo.passkey)
|
||||
setOriginApp(
|
||||
registerInfo.originApp,
|
||||
setAppOrigin(
|
||||
registerInfo.appOrigin,
|
||||
database?.allowEntryCustomFields() == true
|
||||
)
|
||||
}
|
||||
@@ -250,7 +243,7 @@ class EntryInfo : NodeInfo {
|
||||
if (autoType != other.autoType) return false
|
||||
if (otpModel != other.otpModel) return false
|
||||
if (passkey != other.passkey) return false
|
||||
if (originApp != other.originApp) return false
|
||||
if (appOrigin != other.appOrigin) return false
|
||||
if (isTemplate != other.isTemplate) return false
|
||||
|
||||
return true
|
||||
@@ -271,7 +264,7 @@ class EntryInfo : NodeInfo {
|
||||
result = 31 * result + autoType.hashCode()
|
||||
result = 31 * result + (otpModel?.hashCode() ?: 0)
|
||||
result = 31 * result + (passkey?.hashCode() ?: 0)
|
||||
result = 31 * result + (originApp?.hashCode() ?: 0)
|
||||
result = 31 * result + (appOrigin?.hashCode() ?: 0)
|
||||
result = 31 * result + isTemplate.hashCode()
|
||||
return result
|
||||
}
|
||||
@@ -279,6 +272,13 @@ class EntryInfo : NodeInfo {
|
||||
|
||||
companion object {
|
||||
|
||||
/**
|
||||
* Create a field name suffix depending on the field position
|
||||
*/
|
||||
fun suffixFieldNamePosition(position: Int): String {
|
||||
return if (position > 0) "_$position" else ""
|
||||
}
|
||||
|
||||
@JvmField
|
||||
val CREATOR: Parcelable.Creator<EntryInfo> = object : Parcelable.Creator<EntryInfo> {
|
||||
override fun createFromParcel(parcel: Parcel): EntryInfo {
|
||||
|
||||
@@ -10,7 +10,7 @@ data class RegisterInfo(
|
||||
val password: String? = null,
|
||||
val creditCard: CreditCard? = null,
|
||||
val passkey: Passkey? = null,
|
||||
val originApp: OriginApp? = null
|
||||
val appOrigin: AppOrigin? = null
|
||||
): Parcelable {
|
||||
|
||||
constructor(parcel: Parcel) : this(
|
||||
@@ -19,7 +19,7 @@ data class RegisterInfo(
|
||||
password = parcel.readString() ?: "",
|
||||
creditCard = parcel.readParcelableCompat(),
|
||||
passkey = parcel.readParcelableCompat(),
|
||||
originApp = parcel.readParcelableCompat()
|
||||
appOrigin = parcel.readParcelableCompat()
|
||||
)
|
||||
|
||||
override fun writeToParcel(parcel: Parcel, flags: Int) {
|
||||
@@ -28,7 +28,7 @@ data class RegisterInfo(
|
||||
parcel.writeString(password)
|
||||
parcel.writeParcelable(creditCard, flags)
|
||||
parcel.writeParcelable(passkey, flags)
|
||||
parcel.writeParcelable(originApp, flags)
|
||||
parcel.writeParcelable(appOrigin, flags)
|
||||
}
|
||||
|
||||
override fun describeContents(): Int {
|
||||
|
||||
Reference in New Issue
Block a user