1 /*
2  * Copyright (C) 2024 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.adservices.service.common;
18 
19 import android.net.Uri;
20 
21 import com.android.internal.annotations.VisibleForTesting;
22 
23 import java.util.List;
24 import java.util.Objects;
25 
26 /**
27  * Validates whether a coordinator origin URI is valid.
28  *
29  * <p>The origin must contain only scheme and hostname and must belong to the allowlist.
30  */
31 public interface CoordinatorOriginUriValidator extends Validator<Uri> {
32     @VisibleForTesting
33     String URI_SHOULD_HAVE_PRESENT_HOST = "The coordinator origin uri should have present host.";
34 
35     @VisibleForTesting String URI_SHOULD_USE_HTTPS = "The coordinator origin uri should use HTTPS.";
36 
37     @VisibleForTesting
38     String URI_SHOULD_NOT_HAVE_PATH = "The coordinator origin uri should not have a path.";
39 
40     @VisibleForTesting
41     String URI_SHOULD_BELONG_TO_ALLOWLIST =
42             "The coordinator origin uri should belong to the allowlist.";
43 
44     CoordinatorOriginUriValidator VALIDATOR_NO_OP = (object, violations) -> {};
45 
46     /** Creates an instance of the disabled validator */
createDisabledInstance()47     static CoordinatorOriginUriValidator createDisabledInstance() {
48         return VALIDATOR_NO_OP;
49     }
50 
51     /** Creates an instance of an enabled validator */
createEnabledInstance(String allowlist)52     static CoordinatorOriginUriValidator createEnabledInstance(String allowlist) {
53         return (uri, violations) -> {
54             if (!Objects.isNull(uri)) {
55                 if (ValidatorUtil.isStringNullOrEmpty(uri.getHost())) {
56                     violations.add(URI_SHOULD_HAVE_PRESENT_HOST);
57                 } else if (!ValidatorUtil.HTTPS_SCHEME.equalsIgnoreCase(uri.getScheme())) {
58                     violations.add(URI_SHOULD_USE_HTTPS);
59                 } else if (!ValidatorUtil.isStringNullOrEmpty(uri.getPath())) {
60                     violations.add(URI_SHOULD_NOT_HAVE_PATH);
61                 } else if (!isUrlAllowListed(allowlist, uri)) {
62                     violations.add(URI_SHOULD_BELONG_TO_ALLOWLIST);
63                 }
64             }
65         };
66     }
67 
68     private static boolean isUrlAllowListed(String allowlist, Uri uri) {
69         List<String> allowedUrls = AllowLists.splitAllowList(allowlist);
70 
71         for (String url : allowedUrls) {
72             Uri allowedUri = Uri.parse(url);
73             if (uri.getHost().equals(allowedUri.getHost())) {
74                 return true;
75             }
76         }
77 
78         return false;
79     }
80 }
81