Sort credential list by registrable domain
Validate Gradle Wrapper / Validation (push) Canceled after 0s
Validate Gradle Wrapper / Validation (push) Canceled after 0s
This commit is contained in:
@@ -58,6 +58,7 @@ dependencies {
|
||||
implementation(libs.androidx.credentials)
|
||||
implementation(libs.kotlinx.coroutines.android)
|
||||
implementation(libs.material)
|
||||
implementation(libs.etldx)
|
||||
testImplementation(libs.junit)
|
||||
androidTestImplementation(libs.androidx.junit)
|
||||
androidTestImplementation(libs.androidx.espresso.core)
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
package pl.lebihan.authnkey
|
||||
|
||||
import pl.lebihan.etldx.InvalidDomainNameException
|
||||
import pl.lebihan.etldx.PublicSuffixList
|
||||
|
||||
/** An rpId split into the parts we order by. Both parts are already lower cased. */
|
||||
private class DomainKey(val registrable: String, val subdomain: String)
|
||||
|
||||
private fun PublicSuffixList.keyFor(rpId: String): DomainKey =
|
||||
try {
|
||||
val domain = split(rpId)
|
||||
// registrableDomain is null when the rpId is a public suffix itself
|
||||
DomainKey(domain.registrableDomain ?: domain.name, domain.subdomain.orEmpty())
|
||||
} catch (_: InvalidDomainNameException) {
|
||||
// The RP registered something that is not a domain name.
|
||||
DomainKey(rpId.lowercase(), "")
|
||||
}
|
||||
|
||||
/**
|
||||
* Orders credentials by registrable domain, then by subdomain, then by user name.
|
||||
*
|
||||
* Sorting on the eTLD+1 keeps `example.com`, `login.example.com` and `account.example.com` together
|
||||
* under E instead of scattering them across the list.
|
||||
*/
|
||||
fun List<CredentialItem>.sortedByRegistrableDomain(psl: PublicSuffixList): List<CredentialItem> {
|
||||
val keys = map { it.rpId }.distinct().associateWith(psl::keyFor)
|
||||
return sortedWith(
|
||||
compareBy<CredentialItem> { keys.getValue(it.rpId).registrable }
|
||||
.thenBy { keys.getValue(it.rpId).subdomain }
|
||||
.thenBy(String.CASE_INSENSITIVE_ORDER) {
|
||||
it.credential.userName ?: it.credential.userDisplayName ?: ""
|
||||
}
|
||||
)
|
||||
}
|
||||
@@ -861,13 +861,17 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
val credentialItems = rpsWithCredentials.flatMap { rpWithCreds ->
|
||||
rpWithCreds.credentials?.map { cred ->
|
||||
CredentialItem(
|
||||
rpId = rpWithCreds.relyingParty.rpId ?: rpWithCreds.relyingParty.rpIdHash.toHex(),
|
||||
credential = cred
|
||||
)
|
||||
} ?: emptyList()
|
||||
val credentialItems = withContext(Dispatchers.IO) {
|
||||
val psl = PublicSuffixes.get(this@MainActivity)
|
||||
rpsWithCredentials.flatMap { rpWithCreds ->
|
||||
rpWithCreds.credentials?.map { cred ->
|
||||
CredentialItem(
|
||||
rpId = rpWithCreds.relyingParty.rpId
|
||||
?: rpWithCreds.relyingParty.rpIdHash.toHex(),
|
||||
credential = cred
|
||||
)
|
||||
} ?: emptyList()
|
||||
}.sortedByRegistrableDomain(psl)
|
||||
}
|
||||
|
||||
showCredentialsDialog(metadata, credentialItems)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
package pl.lebihan.authnkey
|
||||
|
||||
import android.content.Context
|
||||
import pl.lebihan.etldx.PublicSuffixList
|
||||
|
||||
/**
|
||||
* Holds the parsed public suffix list.
|
||||
*
|
||||
* Parsing walks the whole list, so it is done once and the instance kept. [PublicSuffixList] is
|
||||
* immutable and thread safe.
|
||||
*/
|
||||
object PublicSuffixes {
|
||||
|
||||
@Volatile
|
||||
private var instance: PublicSuffixList? = null
|
||||
|
||||
/** Returns the list, parsing it on first use. Call from a background thread. */
|
||||
fun get(context: Context): PublicSuffixList =
|
||||
instance ?: synchronized(this) {
|
||||
instance ?: PublicSuffixList(
|
||||
context.applicationContext.resources.openRawResource(R.raw.public_suffix_list)
|
||||
).also { instance = it }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,6 +9,7 @@ appcompat = "1.7.1"
|
||||
kotlinxCoroutinesAndroid = "1.11.0"
|
||||
credentials = "1.6.0"
|
||||
material = "1.14.0"
|
||||
etldx = "0.1.0"
|
||||
|
||||
[libraries]
|
||||
androidx-core-ktx = { group = "androidx.core", name = "core-ktx", version.ref = "coreKtx" }
|
||||
@@ -19,6 +20,7 @@ androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version
|
||||
androidx-credentials = { group = "androidx.credentials", name = "credentials", version.ref = "credentials" }
|
||||
kotlinx-coroutines-android = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-android", version.ref = "kotlinxCoroutinesAndroid" }
|
||||
material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||
etldx = { module = "com.github.mimi89999:etldx", version.ref = "etldx" }
|
||||
|
||||
[plugins]
|
||||
android-application = { id = "com.android.application", version.ref = "agp" }
|
||||
|
||||
@@ -16,6 +16,10 @@ dependencyResolutionManagement {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url = uri("https://jitpack.io")
|
||||
content { includeGroup("com.github.mimi89999") }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user