aboutsummaryrefslogtreecommitdiff
path: root/autofill-parser/src
diff options
context:
space:
mode:
Diffstat (limited to 'autofill-parser/src')
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt15
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt22
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt26
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt44
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt52
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt48
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt33
-rw-r--r--autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt16
-rw-r--r--autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt3
-rw-r--r--autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListData.kt5
-rw-r--r--autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListLoader.kt7
11 files changed, 203 insertions, 68 deletions
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt
index e51ab69e..85381254 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillFormParser.kt
@@ -41,7 +41,8 @@ public sealed class FormOrigin(public open val identifier: String) {
when (this) {
is Web -> identifier
is App -> {
- val info = context.packageManager.getApplicationInfo(identifier, PackageManager.GET_META_DATA)
+ val info =
+ context.packageManager.getApplicationInfo(identifier, PackageManager.GET_META_DATA)
val label = context.packageManager.getApplicationLabel(info)
if (untrusted) "“$label”" else "$label"
}
@@ -174,7 +175,10 @@ private class AutofillFormParser(
// the single origin among the detected fillable or saveable fields. If this origin
// is null, but we encountered web origins elsewhere in the AssistStructure, the
// situation is uncertain and Autofill should not be offered.
- webOriginToFormOrigin(context, scenario.allFields.map { it.webOrigin }.toSet().singleOrNull() ?: return null)
+ webOriginToFormOrigin(
+ context,
+ scenario.allFields.map { it.webOrigin }.toSet().singleOrNull() ?: return null
+ )
}
}
}
@@ -204,7 +208,12 @@ private constructor(
): FillableForm? {
val form = AutofillFormParser(context, structure, isManualRequest, customSuffixes)
if (form.formOrigin == null || form.scenario == null) return null
- return FillableForm(form.formOrigin, form.scenario.map { it.autofillId }, form.ignoredIds, form.saveFlags)
+ return FillableForm(
+ form.formOrigin,
+ form.scenario.map { it.autofillId },
+ form.ignoredIds,
+ form.saveFlags
+ )
}
}
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt
index 6c8ae0dd..2de929b9 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillHelper.kt
@@ -49,14 +49,19 @@ public fun computeCertificatesHash(context: Context, appPackage: String): String
// hashes comparable between versions and hence default to using the deprecated API.
@SuppressLint("PackageManagerGetSignatures")
@Suppress("DEPRECATION")
- val signaturesOld = context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNATURES).signatures
+ val signaturesOld =
+ context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNATURES).signatures
val stableHashOld = stableHash(signaturesOld.map { it.toByteArray() })
if (Build.VERSION.SDK_INT >= 28) {
- val info = context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
- val signaturesNew = info.signingInfo.signingCertificateHistory ?: info.signingInfo.apkContentsSigners
+ val info =
+ context.packageManager.getPackageInfo(appPackage, PackageManager.GET_SIGNING_CERTIFICATES)
+ val signaturesNew =
+ info.signingInfo.signingCertificateHistory ?: info.signingInfo.apkContentsSigners
val stableHashNew = stableHash(signaturesNew.map { it.toByteArray() })
if (stableHashNew != stableHashOld)
- tag("CertificatesHash").e { "Mismatch between old and new hash: $stableHashNew != $stableHashOld" }
+ tag("CertificatesHash").e {
+ "Mismatch between old and new hash: $stableHashNew != $stableHashOld"
+ }
}
return stableHashOld
}
@@ -106,7 +111,10 @@ private fun visitViewNodes(structure: AssistStructure, block: (AssistStructure.V
}
}
-private fun visitViewNode(node: AssistStructure.ViewNode, block: (AssistStructure.ViewNode) -> Unit) {
+private fun visitViewNode(
+ node: AssistStructure.ViewNode,
+ block: (AssistStructure.ViewNode) -> Unit
+) {
block(node)
for (i in 0 until node.childCount) {
visitViewNode(node.getChildAt(i), block)
@@ -114,7 +122,9 @@ private fun visitViewNode(node: AssistStructure.ViewNode, block: (AssistStructur
}
@RequiresApi(Build.VERSION_CODES.O)
-internal fun AssistStructure.findNodeByAutofillId(autofillId: AutofillId): AssistStructure.ViewNode? {
+internal fun AssistStructure.findNodeByAutofillId(
+ autofillId: AutofillId
+): AssistStructure.ViewNode? {
var node: AssistStructure.ViewNode? = null
visitViewNodes(this) { if (it.autofillId == autofillId) node = it }
return node
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt
index 3583d705..11b85b66 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillScenario.kt
@@ -56,9 +56,15 @@ public sealed class AutofillScenario<out T : Any> {
username = clientState.getParcelable(BUNDLE_KEY_USERNAME_ID)
fillUsername = clientState.getBoolean(BUNDLE_KEY_FILL_USERNAME)
otp = clientState.getParcelable(BUNDLE_KEY_OTP_ID)
- currentPassword.addAll(clientState.getParcelableArrayList(BUNDLE_KEY_CURRENT_PASSWORD_IDS) ?: emptyList())
- newPassword.addAll(clientState.getParcelableArrayList(BUNDLE_KEY_NEW_PASSWORD_IDS) ?: emptyList())
- genericPassword.addAll(clientState.getParcelableArrayList(BUNDLE_KEY_GENERIC_PASSWORD_IDS) ?: emptyList())
+ currentPassword.addAll(
+ clientState.getParcelableArrayList(BUNDLE_KEY_CURRENT_PASSWORD_IDS) ?: emptyList()
+ )
+ newPassword.addAll(
+ clientState.getParcelableArrayList(BUNDLE_KEY_NEW_PASSWORD_IDS) ?: emptyList()
+ )
+ genericPassword.addAll(
+ clientState.getParcelableArrayList(BUNDLE_KEY_GENERIC_PASSWORD_IDS) ?: emptyList()
+ )
}
.build()
} catch (e: Throwable) {
@@ -227,7 +233,9 @@ public fun Dataset.Builder.fillWith(
}
}
-internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(transform: (T) -> S): AutofillScenario<S> {
+internal inline fun <T : Any, S : Any> AutofillScenario<T>.map(
+ transform: (T) -> S
+): AutofillScenario<S> {
val builder = AutofillScenario.Builder<S>()
builder.username = username?.let(transform)
builder.fillUsername = fillUsername
@@ -253,7 +261,10 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
putParcelable(AutofillScenario.BUNDLE_KEY_USERNAME_ID, username)
putBoolean(AutofillScenario.BUNDLE_KEY_FILL_USERNAME, fillUsername)
putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp)
- putParcelableArrayList(AutofillScenario.BUNDLE_KEY_CURRENT_PASSWORD_IDS, ArrayList(currentPassword))
+ putParcelableArrayList(
+ AutofillScenario.BUNDLE_KEY_CURRENT_PASSWORD_IDS,
+ ArrayList(currentPassword)
+ )
putParcelableArrayList(AutofillScenario.BUNDLE_KEY_NEW_PASSWORD_IDS, ArrayList(newPassword))
}
}
@@ -262,7 +273,10 @@ internal fun AutofillScenario<AutofillId>.toBundle(): Bundle =
putParcelable(AutofillScenario.BUNDLE_KEY_USERNAME_ID, username)
putBoolean(AutofillScenario.BUNDLE_KEY_FILL_USERNAME, fillUsername)
putParcelable(AutofillScenario.BUNDLE_KEY_OTP_ID, otp)
- putParcelableArrayList(AutofillScenario.BUNDLE_KEY_GENERIC_PASSWORD_IDS, ArrayList(genericPassword))
+ putParcelableArrayList(
+ AutofillScenario.BUNDLE_KEY_GENERIC_PASSWORD_IDS,
+ ArrayList(genericPassword)
+ )
}
}
}
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt
index ed264233..7303efc5 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategy.kt
@@ -9,11 +9,14 @@ import androidx.annotation.RequiresApi
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Certain
import com.github.androidpasswordstore.autofillparser.CertaintyLevel.Likely
-private inline fun <T> Pair<T, T>.all(predicate: T.() -> Boolean) = predicate(first) && predicate(second)
+private inline fun <T> Pair<T, T>.all(predicate: T.() -> Boolean) =
+ predicate(first) && predicate(second)
-private inline fun <T> Pair<T, T>.any(predicate: T.() -> Boolean) = predicate(first) || predicate(second)
+private inline fun <T> Pair<T, T>.any(predicate: T.() -> Boolean) =
+ predicate(first) || predicate(second)
-private inline fun <T> Pair<T, T>.none(predicate: T.() -> Boolean) = !predicate(first) && !predicate(second)
+private inline fun <T> Pair<T, T>.none(predicate: T.() -> Boolean) =
+ !predicate(first) && !predicate(second)
/**
* The strategy used to detect [AutofillScenario] s; expressed using the DSL implemented in
@@ -32,7 +35,8 @@ internal val autofillStrategy = strategy {
}
currentPassword(optional = true) {
takeSingle { alreadyMatched ->
- val adjacentToNewPasswords = directlyPrecedes(alreadyMatched) || directlyFollows(alreadyMatched)
+ val adjacentToNewPasswords =
+ directlyPrecedes(alreadyMatched) || directlyFollows(alreadyMatched)
// The Autofill framework has not hint that applies to current passwords only.
// In this scenario, we have already matched fields a pair of fields with a specific
// new password hint, so we take a generic Autofill password hint to mean a current
@@ -109,7 +113,9 @@ internal val autofillStrategy = strategy {
rule(applyInSingleOriginMode = true) {
newPassword { takeSingle { hasHintNewPassword && isFocused } }
username(optional = true) {
- takeSingle { alreadyMatched -> usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull()) }
+ takeSingle { alreadyMatched ->
+ usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull())
+ }
}
}
@@ -119,7 +125,9 @@ internal val autofillStrategy = strategy {
rule(applyInSingleOriginMode = true) {
currentPassword { takeSingle { hasAutocompleteHintCurrentPassword && isFocused } }
username(optional = true) {
- takeSingle { alreadyMatched -> usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull()) }
+ takeSingle { alreadyMatched ->
+ usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull())
+ }
}
}
@@ -129,7 +137,9 @@ internal val autofillStrategy = strategy {
rule(applyInSingleOriginMode = true) {
genericPassword { takeSingle { passwordCertainty >= Likely && isFocused } }
username(optional = true) {
- takeSingle { alreadyMatched -> usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull()) }
+ takeSingle { alreadyMatched ->
+ usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull())
+ }
}
}
@@ -139,12 +149,16 @@ internal val autofillStrategy = strategy {
rule {
username { takeSingle { hasHintUsername && isFocused } }
currentPassword(matchHidden = true) {
- takeSingle { alreadyMatched -> directlyFollows(alreadyMatched.singleOrNull()) && couldBeTwoStepHiddenPassword }
+ takeSingle { alreadyMatched ->
+ directlyFollows(alreadyMatched.singleOrNull()) && couldBeTwoStepHiddenPassword
+ }
}
}
// Match a single focused OTP field.
- rule(applyInSingleOriginMode = true) { otp { takeSingle { otpCertainty >= Likely && isFocused } } }
+ rule(applyInSingleOriginMode = true) {
+ otp { takeSingle { otpCertainty >= Likely && isFocused } }
+ }
// Match a single focused username field without a password field.
rule(applyInSingleOriginMode = true) {
@@ -162,7 +176,9 @@ internal val autofillStrategy = strategy {
// This rule can apply in single origin mode since even though the password field may not be
// focused at the time the rule runs, the fill suggestion will only show if it ever receives
// focus.
- rule(applyInSingleOriginMode = true) { currentPassword { takeSingle { hasAutocompleteHintCurrentPassword } } }
+ rule(applyInSingleOriginMode = true) {
+ currentPassword { takeSingle { hasAutocompleteHintCurrentPassword } }
+ }
// See above.
rule(applyInSingleOriginMode = true) { genericPassword { takeSingle { true } } }
@@ -171,10 +187,14 @@ internal val autofillStrategy = strategy {
rule(applyInSingleOriginMode = true, applyOnManualRequestOnly = true) {
genericPassword { takeSingle { isFocused } }
username(optional = true) {
- takeSingle { alreadyMatched -> usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull()) }
+ takeSingle { alreadyMatched ->
+ usernameCertainty >= Likely && directlyPrecedes(alreadyMatched.singleOrNull())
+ }
}
}
// Match any focused username field on manual request.
- rule(applyInSingleOriginMode = true, applyOnManualRequestOnly = true) { username { takeSingle { isFocused } } }
+ rule(applyInSingleOriginMode = true, applyOnManualRequestOnly = true) {
+ username { takeSingle { isFocused } }
+ }
}
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
index c6886d15..3d7f9849 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/AutofillStrategyDsl.kt
@@ -20,28 +20,41 @@ internal interface FieldMatcher {
class Builder {
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
- private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> = mutableListOf()
+ private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
+ mutableListOf()
private var takePair: (Pair<FormField, FormField>.(List<FormField>) -> Boolean)? = null
- private var tieBreakersPair: MutableList<Pair<FormField, FormField>.(List<FormField>) -> Boolean> = mutableListOf()
+ private var tieBreakersPair:
+ MutableList<Pair<FormField, FormField>.(List<FormField>) -> Boolean> =
+ mutableListOf()
fun takeSingle(block: FormField.(alreadyMatched: List<FormField>) -> Boolean = { true }) {
- check(takeSingle == null && takePair == null) { "Every block can only have at most one take{Single,Pair} block" }
+ check(takeSingle == null && takePair == null) {
+ "Every block can only have at most one take{Single,Pair} block"
+ }
takeSingle = block
}
fun breakTieOnSingle(block: FormField.(alreadyMatched: List<FormField>) -> Boolean) {
- check(takeSingle != null) { "Every block needs a takeSingle block before a breakTieOnSingle block" }
+ check(takeSingle != null) {
+ "Every block needs a takeSingle block before a breakTieOnSingle block"
+ }
check(takePair == null) { "takePair cannot be mixed with breakTieOnSingle" }
tieBreakersSingle.add(block)
}
- fun takePair(block: Pair<FormField, FormField>.(alreadyMatched: List<FormField>) -> Boolean = { true }) {
- check(takeSingle == null && takePair == null) { "Every block can only have at most one take{Single,Pair} block" }
+ fun takePair(
+ block: Pair<FormField, FormField>.(alreadyMatched: List<FormField>) -> Boolean = { true }
+ ) {
+ check(takeSingle == null && takePair == null) {
+ "Every block can only have at most one take{Single,Pair} block"
+ }
takePair = block
}
- fun breakTieOnPair(block: Pair<FormField, FormField>.(alreadyMatched: List<FormField>) -> Boolean) {
+ fun breakTieOnPair(
+ block: Pair<FormField, FormField>.(alreadyMatched: List<FormField>) -> Boolean
+ ) {
check(takePair != null) { "Every block needs a takePair block before a breakTieOnPair block" }
check(takeSingle == null) { "takeSingle cannot be mixed with breakTieOnPair" }
tieBreakersPair.add(block)
@@ -69,7 +82,8 @@ internal class SingleFieldMatcher(
class Builder {
private var takeSingle: (FormField.(List<FormField>) -> Boolean)? = null
- private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> = mutableListOf()
+ private val tieBreakersSingle: MutableList<FormField.(List<FormField>) -> Boolean> =
+ mutableListOf()
fun takeSingle(block: FormField.(alreadyMatched: List<FormField>) -> Boolean = { true }) {
check(takeSingle == null) { "Every block can only have at most one takeSingle block" }
@@ -77,7 +91,9 @@ internal class SingleFieldMatcher(
}
fun breakTieOnSingle(block: FormField.(alreadyMatched: List<FormField>) -> Boolean) {
- check(takeSingle != null) { "Every block needs a takeSingle block before a breakTieOnSingle block" }
+ check(takeSingle != null) {
+ "Every block needs a takeSingle block before a breakTieOnSingle block"
+ }
tieBreakersSingle.add(block)
}
@@ -180,7 +196,10 @@ private constructor(
}
@AutofillDsl
- class Builder(private val applyInSingleOriginMode: Boolean, private val applyOnManualRequestOnly: Boolean) {
+ class Builder(
+ private val applyInSingleOriginMode: Boolean,
+ private val applyOnManualRequestOnly: Boolean
+ ) {
companion object {
@@ -286,9 +305,13 @@ private constructor(
"Rules with applyInSingleOriginMode set to true must not fill into hidden fields"
}
}
- return AutofillRule(matchers, applyInSingleOriginMode, applyOnManualRequestOnly, name ?: "Rule #$ruleId").also {
- ruleId++
- }
+ return AutofillRule(
+ matchers,
+ applyInSingleOriginMode,
+ applyOnManualRequestOnly,
+ name ?: "Rule #$ruleId"
+ )
+ .also { ruleId++ }
}
}
@@ -409,4 +432,5 @@ internal class AutofillStrategy private constructor(private val rules: List<Auto
}
}
-internal fun strategy(block: AutofillStrategy.Builder.() -> Unit) = AutofillStrategy.Builder().apply(block).build()
+internal fun strategy(block: AutofillStrategy.Builder.() -> Unit) =
+ AutofillStrategy.Builder().apply(block).build()
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt
index c418df79..6e3e129a 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FeatureAndTrustDetection.kt
@@ -63,7 +63,10 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH =
"com.chrome.canary" to arrayOf("IBnfofsj779wxbzRRDxb6rBPPy/0Nm6aweNFdjmiTPw="),
"com.chrome.dev" to arrayOf("kETuX+5LvF4h3URmVDHE6x8fcaMnFqC8knvLs5Izyr8="),
"com.duckduckgo.mobile.android" to
- arrayOf("u3uzHFc8RqHaf8XFKKas9DIQhFb+7FCBDH8zaU6z0tQ=", "8HB9AhwL8+b43MEbo/VwBCXVl9yjAaMeIQVWk067Gwo="),
+ arrayOf(
+ "u3uzHFc8RqHaf8XFKKas9DIQhFb+7FCBDH8zaU6z0tQ=",
+ "8HB9AhwL8+b43MEbo/VwBCXVl9yjAaMeIQVWk067Gwo="
+ ),
"com.microsoft.emmx" to arrayOf("AeGZlxCoLCdJtNUMRF3IXWcLYTYInQp2anOCfIKh6sk="),
"com.opera.mini.native" to arrayOf("V6y8Ul8bLr0ZGWzW8BQ5fMkQ/RiEHgroUP68Ph5ZP/I="),
"com.opera.mini.native.beta" to arrayOf("V6y8Ul8bLr0ZGWzW8BQ5fMkQ/RiEHgroUP68Ph5ZP/I="),
@@ -80,7 +83,8 @@ private val TRUSTED_BROWSER_CERTIFICATE_HASH =
"org.mozilla.klar" to arrayOf("YgOkc7421k7jf4f6UA7bx56rkwYQq5ufpMp9XB8bT/w="),
"org.torproject.torbrowser" to arrayOf("IAYfBF5zfGc3XBd5TP7bQ2oDzsa6y3y5+WZCIFyizsg="),
"org.ungoogled.chromium.stable" to arrayOf("29UOO5cXoxO/e/hH3hOu6bbtg1My4tK6Eik2Ym5Krtk="),
- "org.ungoogled.chromium.extensions.stable" to arrayOf("29UOO5cXoxO/e/hH3hOu6bbtg1My4tK6Eik2Ym5Krtk="),
+ "org.ungoogled.chromium.extensions.stable" to
+ arrayOf("29UOO5cXoxO/e/hH3hOu6bbtg1My4tK6Eik2Ym5Krtk="),
"com.kiwibrowser.browser" to arrayOf("wGnqlmMy6R4KDDzFd+b1Cf49ndr3AVrQxcXvj9o/hig="),
)
@@ -162,19 +166,30 @@ private val BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY =
private fun isNoAccessibilityServiceEnabled(context: Context): Boolean {
// See https://chromium.googlesource.com/chromium/src/+/447a31e977a65e2eb78804e4a09633699b4ede33
- return Settings.Secure.getString(context.contentResolver, Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES)
+ return Settings.Secure.getString(
+ context.contentResolver,
+ Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES
+ )
.isNullOrEmpty()
}
@RequiresApi(Build.VERSION_CODES.O)
private fun getBrowserSaveFlag(context: Context, appPackage: String): Int? =
BROWSER_SAVE_FLAG[appPackage]
- ?: BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY[appPackage]?.takeIf { isNoAccessibilityServiceEnabled(context) }
+ ?: BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY[appPackage]?.takeIf {
+ isNoAccessibilityServiceEnabled(context)
+ }
-internal data class BrowserAutofillSupportInfo(val multiOriginMethod: BrowserMultiOriginMethod, val saveFlags: Int?)
+internal data class BrowserAutofillSupportInfo(
+ val multiOriginMethod: BrowserMultiOriginMethod,
+ val saveFlags: Int?
+)
@RequiresApi(Build.VERSION_CODES.O)
-internal fun getBrowserAutofillSupportInfoIfTrusted(context: Context, appPackage: String): BrowserAutofillSupportInfo? {
+internal fun getBrowserAutofillSupportInfoIfTrusted(
+ context: Context,
+ appPackage: String
+): BrowserAutofillSupportInfo? {
if (!isTrustedBrowser(context, appPackage)) return null
return BrowserAutofillSupportInfo(
multiOriginMethod = getBrowserMultiOriginMethod(appPackage),
@@ -197,14 +212,18 @@ public enum class BrowserAutofillSupportLevel {
}
@RequiresApi(Build.VERSION_CODES.O)
-private fun getBrowserAutofillSupportLevel(context: Context, appPackage: String): BrowserAutofillSupportLevel {
+private fun getBrowserAutofillSupportLevel(
+ context: Context,
+ appPackage: String
+): BrowserAutofillSupportLevel {
val browserInfo = getBrowserAutofillSupportInfoIfTrusted(context, appPackage)
return when {
browserInfo == null -> BrowserAutofillSupportLevel.None
appPackage in FLAKY_BROWSERS -> BrowserAutofillSupportLevel.FlakyFill
appPackage in BROWSER_SAVE_FLAG_IF_NO_ACCESSIBILITY ->
BrowserAutofillSupportLevel.PasswordFillAndSaveIfNoAccessibility
- browserInfo.multiOriginMethod == BrowserMultiOriginMethod.None -> BrowserAutofillSupportLevel.PasswordFill
+ browserInfo.multiOriginMethod == BrowserMultiOriginMethod.None ->
+ BrowserAutofillSupportLevel.PasswordFill
browserInfo.saveFlags == null -> BrowserAutofillSupportLevel.GeneralFill
else -> BrowserAutofillSupportLevel.GeneralFillAndSave
}.takeUnless { supportLevel ->
@@ -212,7 +231,8 @@ private fun getBrowserAutofillSupportLevel(context: Context, appPackage: String)
// (compatibility mode is only available on Android Pie and higher). Since all known browsers
// with native Autofill support offer full save support as well, we reuse the list of those
// browsers here.
- supportLevel != BrowserAutofillSupportLevel.GeneralFillAndSave && Build.VERSION.SDK_INT < Build.VERSION_CODES.P
+ supportLevel != BrowserAutofillSupportLevel.GeneralFillAndSave &&
+ Build.VERSION.SDK_INT < Build.VERSION_CODES.P
}
?: BrowserAutofillSupportLevel.None
}
@@ -222,9 +242,15 @@ public fun getInstalledBrowsersWithAutofillSupportLevel(
context: Context
): List<Pair<String, BrowserAutofillSupportLevel>> {
val testWebIntent = Intent(Intent.ACTION_VIEW).apply { data = Uri.parse("http://example.org") }
- val installedBrowsers = context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL)
+ val installedBrowsers =
+ context.packageManager.queryIntentActivities(testWebIntent, PackageManager.MATCH_ALL)
return installedBrowsers
.map { it to getBrowserAutofillSupportLevel(context, it.activityInfo.packageName) }
.filter { it.first.isDefault || it.second != BrowserAutofillSupportLevel.None }
- .map { context.packageManager.getApplicationLabel(it.first.activityInfo.applicationInfo).toString() to it.second }
+ .map {
+ context
+ .packageManager
+ .getApplicationLabel(it.first.activityInfo.applicationInfo)
+ .toString() to it.second
+ }
}
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
index 0bd3d404..719af425 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/FormField.kt
@@ -108,9 +108,14 @@ internal class FormField(
"text",
)
private val HTML_INPUT_FIELD_TYPES_FILLABLE =
- (HTML_INPUT_FIELD_TYPES_USERNAME + HTML_INPUT_FIELD_TYPES_PASSWORD + HTML_INPUT_FIELD_TYPES_OTP).toSet().toList()
-
- @RequiresApi(Build.VERSION_CODES.O) private fun isSupportedHint(hint: String) = hint in HINTS_FILLABLE
+ (HTML_INPUT_FIELD_TYPES_USERNAME +
+ HTML_INPUT_FIELD_TYPES_PASSWORD +
+ HTML_INPUT_FIELD_TYPES_OTP)
+ .toSet()
+ .toList()
+
+ @RequiresApi(Build.VERSION_CODES.O)
+ private fun isSupportedHint(hint: String) = hint in HINTS_FILLABLE
private val EXCLUDED_TERMS =
listOf(
"url_bar", // Chrome/Edge/Firefox address bar
@@ -214,7 +219,8 @@ internal class FormField(
private val hasAutocompleteHintUsername = htmlAutocomplete == "username"
val hasAutocompleteHintCurrentPassword = htmlAutocomplete == "current-password"
private val hasAutocompleteHintNewPassword = htmlAutocomplete == "new-password"
- private val hasAutocompleteHintPassword = hasAutocompleteHintCurrentPassword || hasAutocompleteHintNewPassword
+ private val hasAutocompleteHintPassword =
+ hasAutocompleteHintCurrentPassword || hasAutocompleteHintNewPassword
private val hasAutocompleteHintOtp = htmlAutocomplete == "one-time-code"
// Results of hint-based field type detection
@@ -238,7 +244,9 @@ internal class FormField(
// fields to the fill rules and only exclude those fields that have incompatible autocomplete
// hint.
val couldBeTwoStepHiddenPassword =
- !isVisible && isHtmlPasswordField && (hasAutocompleteHintCurrentPassword || htmlAutocomplete == null)
+ !isVisible &&
+ isHtmlPasswordField &&
+ (hasAutocompleteHintCurrentPassword || htmlAutocomplete == null)
// Since many site put autocomplete=off on login forms for compliance reasons or since they are
// worried of the user's browser automatically (i.e., without any user interaction) filling
@@ -247,7 +255,8 @@ internal class FormField(
private val excludedByHints = excludedByAutofillHints
// Only offer to fill into custom views if they explicitly opted into Autofill.
- val relevantField = hasAutofillTypeText && (isTextField || autofillHints.isNotEmpty()) && !excludedByHints
+ val relevantField =
+ hasAutofillTypeText && (isTextField || autofillHints.isNotEmpty()) && !excludedByHints
// Exclude fields based on hint, resource ID or HTML name.
// Note: We still report excluded fields as relevant since they count for adjacency heuristics,
@@ -260,7 +269,8 @@ internal class FormField(
notExcluded && (isAndroidPasswordField || isHtmlPasswordField || hasHintPassword)
private val isCertainPasswordField = isPossiblePasswordField && hasHintPassword
private val isLikelyPasswordField =
- isPossiblePasswordField && (isCertainPasswordField || PASSWORD_HEURISTIC_TERMS.anyMatchesFieldInfo)
+ isPossiblePasswordField &&
+ (isCertainPasswordField || PASSWORD_HEURISTIC_TERMS.anyMatchesFieldInfo)
val passwordCertainty =
if (isCertainPasswordField) CertaintyLevel.Certain
else if (isLikelyPasswordField) CertaintyLevel.Likely
@@ -273,17 +283,20 @@ internal class FormField(
isPossibleOtpField &&
(isCertainOtpField ||
OTP_HEURISTIC_TERMS.anyMatchesFieldInfo ||
- ((htmlMaxLength == null || htmlMaxLength in 6..8) && OTP_WEAK_HEURISTIC_TERMS.anyMatchesFieldInfo))
+ ((htmlMaxLength == null || htmlMaxLength in 6..8) &&
+ OTP_WEAK_HEURISTIC_TERMS.anyMatchesFieldInfo))
val otpCertainty =
if (isCertainOtpField) CertaintyLevel.Certain
else if (isLikelyOtpField) CertaintyLevel.Likely
else if (isPossibleOtpField) CertaintyLevel.Possible else CertaintyLevel.Impossible
// Username field heuristics (based only on the current field)
- private val isPossibleUsernameField = notExcluded && !isPossiblePasswordField && !isCertainOtpField
+ private val isPossibleUsernameField =
+ notExcluded && !isPossiblePasswordField && !isCertainOtpField
private val isCertainUsernameField = isPossibleUsernameField && hasHintUsername
private val isLikelyUsernameField =
- isPossibleUsernameField && (isCertainUsernameField || (USERNAME_HEURISTIC_TERMS.anyMatchesFieldInfo))
+ isPossibleUsernameField &&
+ (isCertainUsernameField || (USERNAME_HEURISTIC_TERMS.anyMatchesFieldInfo))
val usernameCertainty =
if (isCertainUsernameField) CertaintyLevel.Certain
else if (isLikelyUsernameField) CertaintyLevel.Likely
diff --git a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt
index c62e74ab..be3cbe66 100644
--- a/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt
+++ b/autofill-parser/src/main/java/com/github/androidpasswordstore/autofillparser/PublicSuffixListCache.kt
@@ -34,12 +34,18 @@ public fun cachePublicSuffixList(context: Context) {
* Note: Invalid domains, such as IP addresses, are returned unchanged and thus never collide with
* the return value for valid domains.
*/
-internal fun getPublicSuffixPlusOne(context: Context, domain: String, customSuffixes: Sequence<String>) = runBlocking {
+internal fun getPublicSuffixPlusOne(
+ context: Context,
+ domain: String,
+ customSuffixes: Sequence<String>
+) = runBlocking {
// We only feed valid domain names which are not IP addresses into getPublicSuffixPlusOne.
// We do not check whether the domain actually exists (actually, not even whether its TLD
// exists). As long as we restrict ourselves to syntactically valid domain names,
// getPublicSuffixPlusOne will return non-colliding results.
- if (!Patterns.DOMAIN_NAME.matcher(domain).matches() || Patterns.IP_ADDRESS.matcher(domain).matches()) {
+ if (!Patterns.DOMAIN_NAME.matcher(domain).matches() ||
+ Patterns.IP_ADDRESS.matcher(domain).matches()
+ ) {
domain
} else {
getCanonicalSuffix(context, domain, customSuffixes)
@@ -60,7 +66,11 @@ private fun getSuffixPlusUpToOne(domain: String, suffix: String): String? {
return "$lastPrefixPart.$suffix"
}
-private suspend fun getCanonicalSuffix(context: Context, domain: String, customSuffixes: Sequence<String>): String {
+private suspend fun getCanonicalSuffix(
+ context: Context,
+ domain: String,
+ customSuffixes: Sequence<String>
+): String {
val publicSuffixList = PublicSuffixListCache.getOrCachePublicSuffixList(context)
val publicSuffixPlusOne = publicSuffixList.getPublicSuffixPlusOne(domain).await() ?: return domain
var longestSuffix = publicSuffixPlusOne
diff --git a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt
index 8976242e..6f8c6d80 100644
--- a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt
+++ b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixList.kt
@@ -58,7 +58,8 @@ internal class PublicSuffixList(
fun getPublicSuffixPlusOne(domain: String): Deferred<String?> =
scope.async {
when (val offset = data.getPublicSuffixOffset(domain)) {
- is PublicSuffixOffset.Offset -> domain.split('.').drop(offset.value).joinToString(separator = ".")
+ is PublicSuffixOffset.Offset ->
+ domain.split('.').drop(offset.value).joinToString(separator = ".")
else -> null
}
}
diff --git a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListData.kt b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListData.kt
index 7a17a80f..2bdf5f70 100644
--- a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListData.kt
+++ b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListData.kt
@@ -12,7 +12,10 @@ import java.net.IDN
import mozilla.components.lib.publicsuffixlist.ext.binarySearch
/** Class wrapping the public suffix list data and offering methods for accessing rules in it. */
-internal class PublicSuffixListData(private val rules: ByteArray, private val exceptions: ByteArray) {
+internal class PublicSuffixListData(
+ private val rules: ByteArray,
+ private val exceptions: ByteArray
+) {
private fun binarySearchRules(labels: List<ByteArray>, labelIndex: Int): String? {
return rules.binarySearch(labels, labelIndex)
diff --git a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListLoader.kt b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListLoader.kt
index 0cf4c918..5f3fc296 100644
--- a/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListLoader.kt
+++ b/autofill-parser/src/main/java/mozilla/components/lib/publicsuffixlist/PublicSuffixListLoader.kt
@@ -30,7 +30,12 @@ internal object PublicSuffixListLoader {
@Suppress("MagicNumber")
private fun BufferedInputStream.readInt(): Int {
- return (read() and 0xff shl 24 or (read() and 0xff shl 16) or (read() and 0xff shl 8) or (read() and 0xff))
+ return (read() and
+ 0xff shl
+ 24 or
+ (read() and 0xff shl 16) or
+ (read() and 0xff shl 8) or
+ (read() and 0xff))
}
private fun BufferedInputStream.readFully(size: Int): ByteArray {