mirror of
https://github.com/Kunzisoft/KeePassDX.git
synced 2025-12-04 15:49:33 +01:00
@@ -55,7 +55,6 @@ import com.kunzisoft.keepass.database.merge.DatabaseKDBXMerger
|
||||
import com.kunzisoft.keepass.database.search.SearchHelper
|
||||
import com.kunzisoft.keepass.database.search.SearchParameters
|
||||
import com.kunzisoft.keepass.hardware.HardwareKey
|
||||
import com.kunzisoft.keepass.model.SearchInfo
|
||||
import com.kunzisoft.keepass.tasks.ProgressTaskUpdater
|
||||
import com.kunzisoft.keepass.utils.SingletonHolder
|
||||
import com.kunzisoft.keepass.utils.StringUtil.toFormattedColorInt
|
||||
@@ -886,12 +885,12 @@ open class Database {
|
||||
}
|
||||
|
||||
fun createVirtualGroupFromSearchInfo(
|
||||
searchInfo: SearchInfo,
|
||||
searchParameters: SearchParameters,
|
||||
max: Int = Integer.MAX_VALUE
|
||||
): Group? {
|
||||
return mSearchHelper.createVirtualGroupWithSearchResult(
|
||||
database = this,
|
||||
searchParameters = searchInfo.buildSearchParameters(),
|
||||
searchParameters = searchParameters,
|
||||
fromGroup = null,
|
||||
max = max
|
||||
)
|
||||
|
||||
@@ -24,10 +24,13 @@ import com.kunzisoft.keepass.database.element.Entry
|
||||
import com.kunzisoft.keepass.database.element.Group
|
||||
import com.kunzisoft.keepass.database.element.node.NodeHandler
|
||||
import com.kunzisoft.keepass.database.element.node.NodeId
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.FIELD_RELYING_PARTY
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isPasskeyExclusion
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_FIELD
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOtpExclusion
|
||||
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.isPasskey
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isRelyingParty
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOTP
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOTPURIField
|
||||
import com.kunzisoft.keepass.utils.UUIDUtils.asHexString
|
||||
import com.kunzisoft.keepass.utils.inTheSameDomainAs
|
||||
|
||||
@@ -124,8 +127,10 @@ class SearchHelper {
|
||||
/**
|
||||
* Return true if the search query in search parameters is found in available parameters
|
||||
*/
|
||||
fun searchInEntry(entry: Entry,
|
||||
searchParameters: SearchParameters): Boolean {
|
||||
fun searchInEntry(
|
||||
entry: Entry,
|
||||
searchParameters: SearchParameters
|
||||
): Boolean {
|
||||
// Not found if the search string is empty
|
||||
if (searchParameters.searchQuery.isEmpty())
|
||||
return searchParameters.allowEmptyQuery
|
||||
@@ -149,16 +154,32 @@ class SearchHelper {
|
||||
if (checkSearchQuery(entry.password, searchParameters))
|
||||
return true
|
||||
}
|
||||
if (searchParameters.searchInAppIds) {
|
||||
if (entry.getExtraFields().any { field ->
|
||||
field.isAppId()
|
||||
&& checkSearchQuery(field.protectedValue.stringValue, searchParameters)
|
||||
})
|
||||
return true
|
||||
}
|
||||
if (searchParameters.searchInUrls) {
|
||||
if (checkSearchQuery(entry.url, searchParameters) { stringToCheck, word ->
|
||||
if (searchParameters.searchByDomain) {
|
||||
try {
|
||||
stringToCheck.inTheSameDomainAs(word, sameSubDomain = true)
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
specialWebDomainComparison(searchParameters, stringToCheck, word)
|
||||
}) {
|
||||
return true
|
||||
} else if (entry.getExtraFields().any { field ->
|
||||
field.isWebDomain()
|
||||
&& checkSearchQuery(field.protectedValue.stringValue, searchParameters) { stringToCheck, word ->
|
||||
specialWebDomainComparison(searchParameters, stringToCheck, word)
|
||||
}
|
||||
} else null
|
||||
})
|
||||
}) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
if (searchParameters.searchInRelyingParty) {
|
||||
if(entry.getExtraFields().any { field ->
|
||||
field.isRelyingParty()
|
||||
&& checkSearchQuery(field.protectedValue.stringValue, searchParameters)
|
||||
})
|
||||
return true
|
||||
}
|
||||
if (searchParameters.searchInNotes) {
|
||||
@@ -171,24 +192,20 @@ class SearchHelper {
|
||||
return true
|
||||
}
|
||||
if (searchParameters.searchInOTP) {
|
||||
if(entry.getExtraFields().any { field ->
|
||||
field.name == OTP_FIELD
|
||||
&& checkSearchQuery(field.protectedValue.stringValue, searchParameters)
|
||||
})
|
||||
return true
|
||||
}
|
||||
if (searchParameters.searchInRelyingParty) {
|
||||
if(entry.getExtraFields().any { field ->
|
||||
field.name == FIELD_RELYING_PARTY
|
||||
&& checkSearchQuery(field.protectedValue.stringValue, searchParameters)
|
||||
if (entry.getExtraFields().any { field ->
|
||||
field.isOTPURIField()
|
||||
&& checkSearchQuery(field.protectedValue.stringValue, searchParameters)
|
||||
})
|
||||
return true
|
||||
}
|
||||
if (searchParameters.searchInOther) {
|
||||
if(entry.getExtraFields().any { field ->
|
||||
field.isOtpExclusion()
|
||||
&& field.isPasskeyExclusion()
|
||||
&& checkSearchQuery(field.protectedValue.toString(), searchParameters)
|
||||
if (entry.getExtraFields().any { field ->
|
||||
!field.isAppId()
|
||||
&& !field.isAppIdSignature()
|
||||
&& !field.isWebDomain()
|
||||
&& !field.isOTP()
|
||||
&& !field.isPasskey()
|
||||
&& checkSearchQuery(field.protectedValue.toString(), searchParameters)
|
||||
})
|
||||
return true
|
||||
}
|
||||
@@ -199,6 +216,23 @@ class SearchHelper {
|
||||
return false
|
||||
}
|
||||
|
||||
private fun specialWebDomainComparison(
|
||||
searchParameters: SearchParameters,
|
||||
stringToCheck: String,
|
||||
word: String
|
||||
): Boolean? {
|
||||
return if (searchParameters.searchByDomain) {
|
||||
try {
|
||||
stringToCheck.inTheSameDomainAs(
|
||||
value = word,
|
||||
sameSubDomain = searchParameters.searchBySubDomain
|
||||
)
|
||||
} catch (_: Exception) {
|
||||
false
|
||||
}
|
||||
} else null
|
||||
}
|
||||
|
||||
private fun checkSearchQuery(
|
||||
stringToCheck: String,
|
||||
searchParameters: SearchParameters,
|
||||
|
||||
@@ -34,11 +34,14 @@ class SearchParameters() : Parcelable{
|
||||
var searchInTitles = true
|
||||
var searchInUsernames = true
|
||||
var searchInPasswords = false
|
||||
var searchInAppIds = true
|
||||
var searchInUrls = true
|
||||
var searchByDomain = false
|
||||
var searchBySubDomain = false
|
||||
var searchInRelyingParty = false
|
||||
var searchInExpired = false
|
||||
var searchInNotes = true
|
||||
var searchInOTP = false
|
||||
var searchInRelyingParty = false
|
||||
var searchInOther = true
|
||||
var searchInUUIDs = false
|
||||
var searchInTags = false
|
||||
@@ -47,7 +50,6 @@ class SearchParameters() : Parcelable{
|
||||
var searchInSearchableGroup = true
|
||||
var searchInRecycleBin = false
|
||||
var searchInTemplates = false
|
||||
var searchByDomain = false
|
||||
|
||||
constructor(parcel: Parcel) : this() {
|
||||
searchQuery = parcel.readString() ?: searchQuery
|
||||
@@ -57,11 +59,14 @@ class SearchParameters() : Parcelable{
|
||||
searchInTitles = parcel.readByte() != 0.toByte()
|
||||
searchInUsernames = parcel.readByte() != 0.toByte()
|
||||
searchInPasswords = parcel.readByte() != 0.toByte()
|
||||
searchInAppIds = parcel.readByte() != 0.toByte()
|
||||
searchInUrls = parcel.readByte() != 0.toByte()
|
||||
searchByDomain = parcel.readByte() != 0.toByte()
|
||||
searchBySubDomain = parcel.readByte() != 0.toByte()
|
||||
searchInRelyingParty = parcel.readByte() != 0.toByte()
|
||||
searchInExpired = parcel.readByte() != 0.toByte()
|
||||
searchInNotes = parcel.readByte() != 0.toByte()
|
||||
searchInOTP = parcel.readByte() != 0.toByte()
|
||||
searchInRelyingParty = parcel.readByte() != 0.toByte()
|
||||
searchInOther = parcel.readByte() != 0.toByte()
|
||||
searchInUUIDs = parcel.readByte() != 0.toByte()
|
||||
searchInTags = parcel.readByte() != 0.toByte()
|
||||
@@ -79,11 +84,14 @@ class SearchParameters() : Parcelable{
|
||||
parcel.writeByte(if (searchInTitles) 1 else 0)
|
||||
parcel.writeByte(if (searchInUsernames) 1 else 0)
|
||||
parcel.writeByte(if (searchInPasswords) 1 else 0)
|
||||
parcel.writeByte(if (searchInAppIds) 1 else 0)
|
||||
parcel.writeByte(if (searchInUrls) 1 else 0)
|
||||
parcel.writeByte(if (searchByDomain) 1 else 0)
|
||||
parcel.writeByte(if (searchBySubDomain) 1 else 0)
|
||||
parcel.writeByte(if (searchInRelyingParty) 1 else 0)
|
||||
parcel.writeByte(if (searchInExpired) 1 else 0)
|
||||
parcel.writeByte(if (searchInNotes) 1 else 0)
|
||||
parcel.writeByte(if (searchInOTP) 1 else 0)
|
||||
parcel.writeByte(if (searchInRelyingParty) 1 else 0)
|
||||
parcel.writeByte(if (searchInOther) 1 else 0)
|
||||
parcel.writeByte(if (searchInUUIDs) 1 else 0)
|
||||
parcel.writeByte(if (searchInTags) 1 else 0)
|
||||
|
||||
@@ -139,4 +139,25 @@ object AppOriginEntryField {
|
||||
setWebDomain(webOrigin.origin, null, customFieldsAllowed)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the current field is an application id
|
||||
*/
|
||||
fun Field.isAppId(): Boolean {
|
||||
return this.name.startsWith(APPLICATION_ID_FIELD_NAME)
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the current field is an application id signature
|
||||
*/
|
||||
fun Field.isAppIdSignature(): Boolean {
|
||||
return this.name.startsWith(APPLICATION_SIGNATURE_FIELD_NAME)
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the current field is a web domain
|
||||
*/
|
||||
fun Field.isWebDomain(): Boolean {
|
||||
return this.name.startsWith(WEB_DOMAIN_FIELD_NAME)
|
||||
}
|
||||
}
|
||||
@@ -31,11 +31,11 @@ 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.PasskeyEntryFields.isPasskeyExclusion
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.isPasskey
|
||||
import com.kunzisoft.keepass.model.PasskeyEntryFields.setPasskey
|
||||
import com.kunzisoft.keepass.otp.OtpElement
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.OTP_TOKEN_FIELD
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOtpExclusion
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.isOTP
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields.setOtp
|
||||
import com.kunzisoft.keepass.utils.readBooleanCompat
|
||||
import com.kunzisoft.keepass.utils.readListCompat
|
||||
@@ -109,8 +109,7 @@ class EntryInfo : NodeInfo {
|
||||
|
||||
fun getCustomFieldsForFilling(): List<Field> {
|
||||
return customFields.filter {
|
||||
!it.isOtpExclusion()
|
||||
&& !it.isPasskeyExclusion()
|
||||
!it.isOTP() && !it.isPasskey()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -112,9 +112,9 @@ object PasskeyEntryFields {
|
||||
}
|
||||
|
||||
/**
|
||||
* Field ignored for a search or a form filling
|
||||
* Detect if the current field is a Passkey
|
||||
*/
|
||||
fun Field.isPasskeyExclusion(): Boolean {
|
||||
fun Field.isPasskey(): Boolean {
|
||||
return when(name) {
|
||||
PASSKEY_FIELD -> true
|
||||
FIELD_USERNAME -> true
|
||||
@@ -125,4 +125,11 @@ object PasskeyEntryFields {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the current field is a Passkey relying party
|
||||
*/
|
||||
fun Field.isRelyingParty(): Boolean {
|
||||
return name == FIELD_RELYING_PARTY
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import android.content.res.Resources
|
||||
import android.net.Uri
|
||||
import android.os.Parcel
|
||||
import android.os.Parcelable
|
||||
import com.kunzisoft.keepass.database.search.SearchParameters
|
||||
import com.kunzisoft.keepass.otp.OtpEntryFields
|
||||
import com.kunzisoft.keepass.utils.ObjectNameResource
|
||||
import com.kunzisoft.keepass.utils.readBooleanCompat
|
||||
@@ -97,36 +96,26 @@ class SearchInfo : ObjectNameResource, Parcelable {
|
||||
&& relyingParty == null
|
||||
&& otpString == null
|
||||
}
|
||||
|
||||
private fun isADomainSearch(): Boolean {
|
||||
return toString() == webDomain && webDomain != null
|
||||
}
|
||||
|
||||
var isAPasskeySearch: Boolean = false
|
||||
var isTagSearch: Boolean = false
|
||||
get() = tag != null
|
||||
private set
|
||||
|
||||
var query: String? = null
|
||||
var isAppIdSearch: Boolean = false
|
||||
get() = applicationId != null
|
||||
private set
|
||||
|
||||
fun buildSearchParameters(): SearchParameters {
|
||||
return SearchParameters().apply {
|
||||
searchQuery = query ?: this@SearchInfo.toString()
|
||||
allowEmptyQuery = false
|
||||
searchInTitles = !isAPasskeySearch
|
||||
searchInUsernames = false
|
||||
searchInPasswords = false
|
||||
searchInUrls = !isAPasskeySearch
|
||||
searchByDomain = isADomainSearch()
|
||||
searchInNotes = false
|
||||
searchInOTP = false
|
||||
searchInOther = true
|
||||
searchInUUIDs = false
|
||||
searchInTags = false
|
||||
searchInRelyingParty = isAPasskeySearch
|
||||
searchInCurrentGroup = false
|
||||
searchInSearchableGroup = true
|
||||
searchInRecycleBin = false
|
||||
searchInTemplates = false
|
||||
}
|
||||
}
|
||||
var isDomainSearch: Boolean = false
|
||||
get() = webDomain != null
|
||||
private set
|
||||
|
||||
var isPasskeySearch: Boolean = false
|
||||
get() = relyingParty != null
|
||||
private set
|
||||
|
||||
var isOTPSearch: Boolean = false
|
||||
get() = otpString != null
|
||||
private set
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
|
||||
@@ -39,7 +39,7 @@ object OtpEntryFields {
|
||||
private val TAG = OtpEntryFields::class.java.name
|
||||
|
||||
// Field from KeePassXC
|
||||
const val OTP_FIELD = "otp"
|
||||
private const val OTP_FIELD = "otp"
|
||||
|
||||
// URL parameters (https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
|
||||
private const val OTP_SCHEME = "otpauth"
|
||||
@@ -508,9 +508,9 @@ object OtpEntryFields {
|
||||
}
|
||||
|
||||
/**
|
||||
* Field ignored for a search or a form filling
|
||||
* Detect if the current field is an OTP
|
||||
*/
|
||||
fun Field.isOtpExclusion(): Boolean {
|
||||
fun Field.isOTP(): Boolean {
|
||||
return when(name) {
|
||||
OTP_FIELD -> true
|
||||
TOTP_SEED_FIELD -> true
|
||||
@@ -530,4 +530,11 @@ object OtpEntryFields {
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Detect if the current field is an OTP URI
|
||||
*/
|
||||
fun Field.isOTPURIField(): Boolean {
|
||||
return name == OTP_FIELD
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user