Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d7889c02 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Skip domain approval logic if host is invalid" into sc-dev

parents 24f078ee 9357d80e
Loading
Loading
Loading
Loading
+5 −1
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@ import android.content.IntentFilter;
import android.content.pm.parsing.component.ParsedActivity;
import android.content.pm.parsing.component.ParsedIntentInfo;
import android.os.Build;
import android.text.TextUtils;
import android.util.ArraySet;
import android.util.Patterns;

@@ -32,7 +33,6 @@ import com.android.server.compat.PlatformCompat;
import com.android.server.pm.parsing.pkg.AndroidPackage;

import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@@ -251,6 +251,10 @@ public class DomainVerificationCollector {
     * improve the reliability of any legacy verifiers.
     */
    private boolean isValidHost(String host) {
        if (TextUtils.isEmpty(host)) {
            return false;
        }

        mDomainMatcher.reset(host);
        return mDomainMatcher.matches();
    }
+15 −0
Original line number Diff line number Diff line
@@ -22,6 +22,8 @@ import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.text.TextUtils;
import android.util.Patterns;

import com.android.internal.util.CollectionUtils;
import com.android.server.compat.PlatformCompat;
@@ -29,9 +31,13 @@ import com.android.server.pm.PackageManagerService;
import com.android.server.pm.parsing.pkg.AndroidPackage;

import java.util.Set;
import java.util.regex.Matcher;

public final class DomainVerificationUtils {

    private static final ThreadLocal<Matcher> sCachedMatcher = ThreadLocal.withInitial(
            () -> Patterns.DOMAIN_NAME.matcher(""));

    /**
     * Consolidates package exception messages. A generic unavailable message is included since the
     * caller doesn't bother to check why the package isn't available.
@@ -48,6 +54,15 @@ public final class DomainVerificationUtils {
            return false;
        }

        String host = intent.getData().getHost();
        if (TextUtils.isEmpty(host)) {
            return false;
        }

        if (!sCachedMatcher.get().reset(host).matches()) {
            return false;
        }

        Set<String> categories = intent.getCategories();
        int categoriesSize = CollectionUtils.size(categories);
        if (categoriesSize > 2) {
+41 −3
Original line number Diff line number Diff line
@@ -235,9 +235,23 @@ class DomainVerificationCollectorTest {
                    <category android:name="android.intent.category.BROWSABLE"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <data android:scheme="https"/>
                    <data android:path="/sub5"/>
                    <data android:host="example5.com"/>
                    <data android:host="invalid5"/>
                    <data android:path="/sub6"/>
                    <data android:host="example6.com"/>
                    <data android:host="invalid6"/>
                </intent-filter>
                <intent-filter android:autoVerify="$autoVerify">
                    <category android:name="android.intent.category.BROWSABLE"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <data android:scheme="example7.com"/>
                <intent-filter android:autoVerify="$autoVerify">
                    <category android:name="android.intent.category.BROWSABLE"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <data android:scheme="https"/>
                </intent-filter>
                <intent-filter android:autoVerify="$autoVerify">
                    <category android:name="android.intent.category.BROWSABLE"/>
                    <category android:name="android.intent.category.DEFAULT"/>
                    <data android:path="/sub7"/>
                </intent-filter>
            </xml>
        """.trimIndent()
@@ -324,6 +338,30 @@ class DomainVerificationCollectorTest {
                                    addDataAuthority("invalid6", null)
                                }
                        )
                        addIntent(
                                ParsedIntentInfo().apply {
                                    setAutoVerify(autoVerify)
                                    addCategory(Intent.CATEGORY_BROWSABLE)
                                    addCategory(Intent.CATEGORY_DEFAULT)
                                    addDataAuthority("example7.com", null)
                                }
                        )
                        addIntent(
                                ParsedIntentInfo().apply {
                                    setAutoVerify(autoVerify)
                                    addCategory(Intent.CATEGORY_BROWSABLE)
                                    addCategory(Intent.CATEGORY_DEFAULT)
                                    addDataScheme("https")
                                }
                        )
                        addIntent(
                                ParsedIntentInfo().apply {
                                    setAutoVerify(autoVerify)
                                    addCategory(Intent.CATEGORY_BROWSABLE)
                                    addCategory(Intent.CATEGORY_DEFAULT)
                                    addDataPath("/sub7", PatternMatcher.PATTERN_LITERAL)
                                }
                        )
                    },
            )

+126 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm.test.verify.domain

import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import com.android.server.pm.verify.domain.DomainVerificationUtils
import com.google.common.truth.Truth.assertThat
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized

@RunWith(Parameterized::class)
class DomainVerificationValidIntentTest {

    companion object {

        @Parameterized.Parameters(name = "{0}")
        @JvmStatic
        fun parameters(): Array<Params> {
            val succeeding = mutableListOf<Params>()
            val failing = mutableListOf<Params>()

            // Start with the base intent
            val base = Params(categorySet = emptySet()).also { succeeding += it }

            // Add all explicit supported categorySet
            succeeding += base.copy(
                categorySet = setOf(Intent.CATEGORY_BROWSABLE),
                matchDefaultOnly = true
            )

            failing += base.copy(
                categorySet = setOf(Intent.CATEGORY_BROWSABLE),
                matchDefaultOnly = false
            )

            succeeding += listOf(true, false).map {
                base.copy(
                    categorySet = setOf(Intent.CATEGORY_DEFAULT),
                    matchDefaultOnly = it
                )
            }

            succeeding += listOf(true, false).map {
                base.copy(
                    categorySet = setOf(Intent.CATEGORY_BROWSABLE, Intent.CATEGORY_DEFAULT),
                    matchDefaultOnly = it
                )
            }

            // Fail on unsupported category
            failing += listOf(
                emptySet(),
                setOf(Intent.CATEGORY_BROWSABLE),
                setOf(Intent.CATEGORY_DEFAULT),
                setOf(Intent.CATEGORY_BROWSABLE, Intent.CATEGORY_DEFAULT)
            ).map { base.copy(categorySet = it + "invalid.CATEGORY") }

            // Fail on unsupported action
            failing += base.copy(action = Intent.ACTION_SEND)

            // Fail on unsupported domain
            failing += base.copy(domain = "invalid")

            // Fail on empty domains
            failing += base.copy(domain = "")

            // Fail on missing scheme
            failing += base.copy(
                uriFunction = { Uri.Builder().authority("test.com").build() }
            )

            // Fail on missing host
            failing += base.copy(
                domain = "",
                uriFunction = { Uri.Builder().scheme("https").build() }
            )

            succeeding.forEach { it.expected = true }
            failing.forEach { it.expected = false }
            return (succeeding + failing).toTypedArray()
        }

        data class Params(
            val action: String = Intent.ACTION_VIEW,
            val categorySet: Set<String> = mutableSetOf(),
            val domain: String = "test.com",
            val matchDefaultOnly: Boolean = true,
            var expected: Boolean? = null,
            val uriFunction: (domain: String) -> Uri = { Uri.parse("https://$it") }
        ) {
            val intent = Intent(action, uriFunction(domain)).apply {
                categorySet.forEach(::addCategory)
            }

            override fun toString() = intent.toShortString(false, false, false, false) +
                    ", matchDefaultOnly = $matchDefaultOnly, expected = $expected"
        }
    }

    @Parameterized.Parameter(0)
    lateinit var params: Params

    @Test
    fun verify() {
        val flags = if (params.matchDefaultOnly) PackageManager.MATCH_DEFAULT_ONLY else 0
        assertThat(DomainVerificationUtils.isDomainVerificationIntent(params.intent, flags))
            .isEqualTo(params.expected)
    }
}