<?xml version='1.0' encoding='UTF-8'?> <SmellBaseline> <ManuallySuppressedIssues/> <CurrentIssues> <ID>ComplexMethod:AutofillStrategyDsl.kt$AutofillRule$fun match( allPassword: List<FormField>, allUsername: List<FormField>, allOtp: List<FormField>, singleOriginMode: Boolean, isManualRequest: Boolean ): AutofillScenario<FormField>?</ID> <ID>DestructuringDeclarationWithTooManyEntries:AutofillStrategyDsl.kt$AutofillRule$(type, matcher, optional, matchHidden)</ID> <ID>ForbiddenComment:AutofillFormParser.kt$AutofillFormParser$// TODO: Support WebViews in apps via Digital Asset Links</ID> <ID>ForbiddenComment:AutofillStrategy.kt$// TODO: Introduce a custom fill/generate/update flow for this scenario</ID> <ID>ForbiddenComment:FormField.kt$FormField$// TODO: Revisit this decision in the future</ID> <ID>LongMethod:ByteArray.kt$@Suppress("ComplexMethod", "NestedBlockDepth") internal fun ByteArray.binarySearch(labels: List<ByteArray>, labelIndex: Int): String?</ID> <ID>LoopWithTooManyJumpStatements:AutofillStrategyDsl.kt$PairOfFieldsMatcher$for ((i, tieBreaker) in tieBreakers.withIndex()) { val new = current.filter { tieBreaker(it, alreadyMatched) } if (new.isEmpty()) { logcat { "Tie breaker #${i + 1}: Didn't match any pair of fields; skipping" } continue } // and return if the available options have been narrowed to a single field. if (new.size == 1) { logcat { "Tie breaker #${i + 1}: Success" } current = new break } logcat { "Tie breaker #${i + 1}: Matched ${new.size} pairs of fields; continuing" } current = new }</ID> <ID>LoopWithTooManyJumpStatements:AutofillStrategyDsl.kt$SingleFieldMatcher$for ((i, tieBreaker) in tieBreakers.withIndex()) { // Successively filter matched fields via tie breakers... val new = current.filter { tieBreaker(it, alreadyMatched) } // skipping those tie breakers that are not satisfied for any remaining field... if (new.isEmpty()) { logcat { "Tie breaker #${i + 1}: Didn't match any field; skipping" } continue } // and return if the available options have been narrowed to a single field. if (new.size == 1) { logcat { "Tie breaker #${i + 1}: Success" } current = new break } logcat { "Tie breaker #${i + 1}: Matched ${new.size} fields; continuing" } current = new }</ID> <ID>LoopWithTooManyJumpStatements:ByteArray.kt$while (true) { val byte0 = if (expectDot) { expectDot = false '.'.code.toByte() } else { labels[currentLabelIndex][currentLabelByteIndex] and BITMASK } val byte1 = this[start + publicSuffixByteIndex] and BITMASK // Compare the bytes. Note that the file stores UTF-8 encoded bytes, so we must compare // the // unsigned bytes. compareResult = (byte0.toUByte() - byte1.toUByte()).toInt() if (compareResult != 0) { break } publicSuffixByteIndex++ currentLabelByteIndex++ if (publicSuffixByteIndex == publicSuffixLength) { break } if (labels[currentLabelIndex].size == currentLabelByteIndex) { // We've exhausted our current label. Either there are more labels to compare, in // which // case we expect a dot as the next character. Otherwise, we've checked all our // labels. if (currentLabelIndex == labels.size - 1) { break } else { currentLabelIndex++ currentLabelByteIndex = -1 expectDot = true } } }</ID> <ID>MagicNumber:AutofillFormParser.kt$AutofillFormParser$26</ID> <ID>MagicNumber:AutofillFormParser.kt$FillableForm$26</ID> <ID>MagicNumber:AutofillHelper.kt$26</ID> <ID>MagicNumber:AutofillHelper.kt$28</ID> <ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$26</ID> <ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$28</ID> <ID>MagicNumber:AutofillHelper.kt$FixedSaveCallback$29</ID> <ID>MagicNumber:AutofillScenario.kt$26</ID> <ID>MagicNumber:AutofillScenario.kt$4</ID> <ID>MagicNumber:AutofillScenario.kt$5</ID> <ID>MagicNumber:AutofillScenario.kt$AutofillScenario$26</ID> <ID>MagicNumber:AutofillScenario.kt$ClassifiedAutofillScenario$26</ID> <ID>MagicNumber:AutofillScenario.kt$GenericAutofillScenario$26</ID> <ID>MagicNumber:AutofillStrategy.kt$26</ID> <ID>MagicNumber:AutofillStrategyDsl.kt$26</ID> <ID>MagicNumber:AutofillStrategyDsl.kt$AutofillRule$26</ID> <ID>MagicNumber:AutofillStrategyDsl.kt$AutofillStrategy$26</ID> <ID>MagicNumber:AutofillStrategyDsl.kt$FieldMatcher$26</ID> <ID>MagicNumber:AutofillStrategyDsl.kt$PairOfFieldsMatcher$26</ID> <ID>MagicNumber:AutofillStrategyDsl.kt$SingleFieldMatcher$26</ID> <ID>MagicNumber:FeatureAndTrustDetection.kt$26</ID> <ID>MagicNumber:FeatureAndTrustDetection.kt$28</ID> <ID>MagicNumber:FormField.kt$FormField$26</ID> <ID>MagicNumber:FormField.kt$FormField$6</ID> <ID>MagicNumber:FormField.kt$FormField$8</ID> <ID>MagicNumber:FormField.kt$FormField.Companion$26</ID> <ID>MagicNumber:PublicSuffixListCache.kt$29</ID> <ID>MaxLineLength:FeatureAndTrustDetection.kt$/* In order to add a new browser, do the following: 1. Obtain the .apk from a trusted source. For example, download it from the Play Store on your phone and use adb pull to get it onto your computer. We will assume that it is called browser.apk. 2. Run aapt dump badging browser.apk | grep package: | grep -Eo " name='[a-zA-Z0-9_\.]*" | cut -c8- to obtain the package name (actually, the application ID) of the app in the .apk. 3. Run apksigner verify --print-certs browser.apk | grep "#1 certificate SHA-256" | grep -Eo "[a-f0-9]{64}" | tr -d '\n' | xxd -r -p | base64 to calculate the hash of browser.apk's first signing certificate. Note: This will only work if the apk has a single signing certificate. Apps with multiple signers are very rare, so there is probably no need to add them. Refer to computeCertificatesHash to learn how the hash would be computed in this case. 4. Verify the package name and the hash, for example by asking other people to repeat the steps above. 5. Add an entry with the browser apps's package name and the hash to TRUSTED_BROWSER_CERTIFICATE_HASH. 6. Optionally, try adding the browser's package name to BROWSERS_WITH_SAVE_SUPPORT and check whether a save request to Password Store is triggered when you submit a registration form. 7. Optionally, try adding the browser's package name to BROWSERS_WITH_MULTI_ORIGIN_SUPPORT and check whether it correctly distinguishes web origins even if iframes are present on the page. You can use https://fabianhenneke.github.io/Android-Password-Store/ as a test form. */</ID> <ID>MaxLineLength:FormField.kt$FormField$"\"$hint\", \"$fieldId\"${if (isFocused) ", focused" else ""}${if (isVisible) ", visible" else ""}, $webOrigin, $htmlAttributesDebug, $autofillHints"</ID> <ID>ReturnCount:AutofillFormParser.kt$AutofillFormParser$private fun determineFormOrigin(context: Context): FormOrigin?</ID> <ID>ReturnCount:AutofillFormParser.kt$AutofillFormParser$private fun webOriginToFormOrigin(context: Context, origin: String): FormOrigin?</ID> <ID>ReturnCount:AutofillFormParser.kt$FormOrigin.Companion$public fun fromBundle(bundle: Bundle): FormOrigin?</ID> <ID>ReturnCount:AutofillStrategyDsl.kt$AutofillRule$fun match( allPassword: List<FormField>, allUsername: List<FormField>, allOtp: List<FormField>, singleOriginMode: Boolean, isManualRequest: Boolean ): AutofillScenario<FormField>?</ID> <ID>ReturnCount:PublicSuffixListCache.kt$private fun getSuffixPlusUpToOne(domain: String, suffix: String): String?</ID> <ID>ReturnCount:PublicSuffixListData.kt$PublicSuffixListData$private fun findExceptionMatch(labels: List<ByteArray>, wildcardMatch: String?): String?</ID> <ID>ReturnCount:PublicSuffixListData.kt$PublicSuffixListData$private fun findMatchingRule(domainLabels: List<String>): List<String></ID> <ID>TooGenericExceptionCaught:AutofillScenario.kt$AutofillScenario.Companion$e: Throwable</ID> <ID>UnusedPrivateMember:AutofillStrategy.kt$private inline fun <T> Pair<T, T>.none(predicate: T.() -> Boolean)</ID> <ID>UnusedPrivateMember:FormField.kt$FormField$// Ignored for now, see excludedByHints private val excludedByAutocompleteHint = htmlAutocomplete == "off"</ID> </CurrentIssues> </SmellBaseline>