fix: Add webOrigin, fix title and add verification state

This commit is contained in:
J-Jamet
2025-08-29 18:41:40 +02:00
parent 4f10d13691
commit f8787ba03d
9 changed files with 258 additions and 181 deletions

View File

@@ -24,38 +24,96 @@ import kotlinx.parcelize.Parcelize
@Parcelize
data class AppOrigin(
val appIdentifiers: MutableList<AppIdentifier> = mutableListOf(),
val webDomains: MutableList<String> = mutableListOf()
val androidOrigins: MutableList<AndroidOrigin> = mutableListOf(),
val webOrigins: MutableList<WebOrigin> = mutableListOf()
) : Parcelable {
fun addIdentifier(appIdentifier: AppIdentifier) {
appIdentifiers.add(appIdentifier)
fun addAndroidOrigin(androidOrigin: AndroidOrigin) {
androidOrigins.add(androidOrigin)
}
fun addWebDomain(webDomain: String) {
this.webDomains.add(webDomain)
fun addWebOrigin(webOrigin: WebOrigin) {
this.webOrigins.add(webOrigin)
}
fun removeAppElement(appIdentifier: AppIdentifier) {
appIdentifiers.remove(appIdentifier)
fun containsVerifiedAndroidOrigin(androidOrigin: AndroidOrigin): Boolean {
return androidOrigins.any {
it.packageName == androidOrigin.packageName
&& it.signature == androidOrigin.signature
&& it.verification.verified
}
}
fun removeWebDomain(webDomain: String) {
this.webDomains.remove(webDomain)
fun containsVerifiedWebOrigin(webOrigin: WebOrigin): Boolean {
return this.webOrigins.any {
it.origin == webOrigin.origin
&& it.verification.verified
}
}
fun firstVerifiedWebOrigin(): WebOrigin? {
return webOrigins.first {
it.verification.verified
}
}
fun clear() {
appIdentifiers.clear()
webDomains.clear()
androidOrigins.clear()
webOrigins.clear()
}
fun isEmpty(): Boolean {
return appIdentifiers.isEmpty() && webDomains.isEmpty()
return androidOrigins.isEmpty() && webOrigins.isEmpty()
}
fun toName(): String? {
return if (androidOrigins.isNotEmpty()) {
androidOrigins.first().packageName
} else if (webOrigins.isNotEmpty()){
webOrigins.first().origin
} else null
}
}
enum class Verification {
MANUALLY_VERIFIED, AUTOMATICALLY_VERIFIED, NOT_VERIFIED;
val verified: Boolean
get() = this == MANUALLY_VERIFIED || this == AUTOMATICALLY_VERIFIED
}
@Parcelize
data class AndroidOrigin(
val packageName: String,
val signature: String? = null,
val verification: Verification = Verification.AUTOMATICALLY_VERIFIED,
) : Parcelable {
fun toAndroidOrigin(): String {
return "androidapp://${packageName}"
}
}
@Parcelize
data class AppIdentifier(
val id: String,
val signature: String? = null,
) : Parcelable
data class WebOrigin(
val origin: String,
val assetLinks: String? = null,
val verification: Verification = Verification.AUTOMATICALLY_VERIFIED,
) : Parcelable {
fun toWebOrigin(): String {
return origin
}
fun defaultAssetLinks(): String {
return "${origin}/.well-known/assetlinks.json"
}
companion object {
const val RELYING_PARTY_DEFAULT_PROTOCOL = "https"
fun fromRelyingParty(relyingParty: String, verification: Verification): WebOrigin = WebOrigin(
origin ="$RELYING_PARTY_DEFAULT_PROTOCOL://$relyingParty",
verification = verification
)
}
}

View File

@@ -48,8 +48,8 @@ object AppOriginEntryField {
}
}.takeWhile { it != null }
.forEach { pair ->
appOrigin.addIdentifier(
AppIdentifier(pair!!.first, pair.second)
appOrigin.addAndroidOrigin(
AndroidOrigin(pair!!.first, pair.second)
)
}
// Get Domains
@@ -58,7 +58,7 @@ object AppOriginEntryField {
val domainKey = WEB_DOMAIN_FIELD_NAME + suffixFieldNamePosition(domainFieldPosition)
val domainValue = getField(domainKey)
if (domainValue != null) {
appOrigin.addWebDomain(domainValue)
appOrigin.addWebOrigin(WebOrigin(origin = domainValue))
domainFieldPosition++
} else {
break // No more domain found
@@ -137,11 +137,12 @@ object AppOriginEntryField {
* Only if [customFieldsAllowed] is true
*/
fun EntryInfo.setAppOrigin(appOrigin: AppOrigin?, customFieldsAllowed: Boolean) {
appOrigin?.appIdentifiers?.forEach { appIdentifier ->
setApplicationId(appIdentifier.id, appIdentifier.signature)
appOrigin?.androidOrigins?.forEach { appIdentifier ->
setApplicationId(appIdentifier.packageName, appIdentifier.signature)
}
appOrigin?.webDomains?.forEach { webDomain ->
setWebDomain(webDomain, null, customFieldsAllowed)
appOrigin?.webOrigins?.forEach { webOrigin ->
if (webOrigin.verification.verified)
setWebDomain(webOrigin.origin, null, customFieldsAllowed)
}
}
}

View File

@@ -176,7 +176,16 @@ class EntryInfo : NodeInfo {
}
/**
* Add searchInfo to current EntryInfo, return true if new data, false if no modification
* Capitalize and remove suffix of a title
*/
fun String.toTitle(): String {
return this.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
}
}
/**
* Add searchInfo to current EntryInfo
*/
fun saveSearchInfo(database: Database?, searchInfo: SearchInfo) {
searchInfo.otpString?.let { otpString ->
@@ -191,20 +200,13 @@ class EntryInfo : NodeInfo {
setApplicationId(applicationId)
}
if (title.isEmpty()) {
title = searchInfo.toTitle()
title = searchInfo.toString().toTitle()
}
}
/**
* Capitalize and remove suffix of web domain to create a title
* Add registerInfo to current EntryInfo
*/
fun SearchInfo.toTitle(): String {
val webDomain = this.webDomain
return webDomain?.substring(0, webDomain.lastIndexOf('.'))?.replaceFirstChar {
if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString()
} ?: this.toString()
}
fun saveRegisterInfo(database: Database?, registerInfo: RegisterInfo) {
saveSearchInfo(database, registerInfo.searchInfo)
registerInfo.username?.let { username = it }
@@ -215,6 +217,9 @@ class EntryInfo : NodeInfo {
registerInfo.appOrigin,
database?.allowEntryCustomFields() == true
)
if (title.isEmpty()) {
title = registerInfo.toString().toTitle()
}
}
fun getVisualTitle(): String {

View File

@@ -1,7 +1,9 @@
package com.kunzisoft.keepass.model
import android.content.res.Resources
import android.os.Parcel
import android.os.Parcelable
import com.kunzisoft.keepass.utils.ObjectNameResource
import com.kunzisoft.keepass.utils.readParcelableCompat
data class RegisterInfo(
@@ -11,12 +13,12 @@ data class RegisterInfo(
val creditCard: CreditCard? = null,
val passkey: Passkey? = null,
val appOrigin: AppOrigin? = null
): Parcelable {
) : ObjectNameResource, Parcelable {
constructor(parcel: Parcel) : this(
searchInfo = parcel.readParcelableCompat() ?: SearchInfo(),
username = parcel.readString() ?: "",
password = parcel.readString() ?: "",
username = parcel.readString(),
password = parcel.readString(),
creditCard = parcel.readParcelableCompat(),
passkey = parcel.readParcelableCompat(),
appOrigin = parcel.readParcelableCompat()
@@ -35,6 +37,20 @@ data class RegisterInfo(
return 0
}
override fun getName(resources: Resources): String {
return username
?: passkey?.relyingParty
?: appOrigin?.toName()
?: searchInfo.getName(resources)
}
override fun toString(): String {
return username
?: passkey?.relyingParty
?: appOrigin?.toName()
?: searchInfo.toString()
}
companion object CREATOR : Parcelable.Creator<RegisterInfo> {
override fun createFromParcel(parcel: Parcel): RegisterInfo {
return RegisterInfo(parcel)