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.ondevicepersonalization.services.util;
18 
19 import android.annotation.NonNull;
20 
21 import java.util.Arrays;
22 
23 /** A utility class to check entity against allow list */
24 public class AllowListUtils {
25     private static final String ALLOW_ALL = "*";
26     private static final String SPLITTER = ",";
27     private static final String PAIR_SPLITTER = ";";
28     private static final String CERT_SPLITTER = ":";
29 
30     /** check if an entity is in the allow list based on name and certificate(optional)*/
isAllowListed(final String entityName, final String packageCertificate, @NonNull final String allowList)31     public static boolean isAllowListed(final String entityName,
32                                         final String packageCertificate,
33                                         @NonNull final String allowList) {
34         if (ALLOW_ALL.equals(allowList)) {
35             return true;
36         }
37 
38         if (entityName == null || entityName.trim().isEmpty()) {
39             return false;
40         }
41 
42         return Arrays.stream(allowList.split(SPLITTER))
43                 .map(String::trim)
44                 .anyMatch(entityInAllowList -> isMatch(
45                         entityInAllowList, entityName, packageCertificate));
46     }
47 
48     /** check if a pair of entities are in an allow list */
isPairAllowListed( final String first, final String firstCertDigest, final String second, final String secondCertDigest, @NonNull final String pairAllowList)49     public static boolean isPairAllowListed(
50             final String first, final String firstCertDigest,
51             final String second, final String secondCertDigest,
52             @NonNull final String pairAllowList) {
53         if (first == null || first.isBlank()
54                 || second == null || second.isBlank()
55                 || firstCertDigest == null || firstCertDigest.isBlank()
56                 || secondCertDigest == null || secondCertDigest.isBlank()
57                 || pairAllowList == null || pairAllowList.isBlank()) {
58             return false;
59         }
60 
61         return Arrays.stream(pairAllowList.split(SPLITTER))
62                 .map(String::trim)
63                 .anyMatch(entityInAllowList -> isPairMatch(
64                         entityInAllowList, first, firstCertDigest, second, secondCertDigest));
65     }
66 
isPairMatch( String entityPairInAllowList, String first, String firstCertDigest, String second, String secondCertDigest)67     private static boolean isPairMatch(
68             String entityPairInAllowList,
69             String first, String firstCertDigest,
70             String second, String secondCertDigest) {
71         String[] pair = entityPairInAllowList.split(PAIR_SPLITTER);
72         if (pair == null || pair.length != 2 || pair[0] == null || pair[1] == null
73                 || pair[0].isBlank() || pair[1].isBlank()) {
74             return false;
75         }
76         return isMatch(pair[0], first, firstCertDigest)
77                 && isMatch(pair[1], second, secondCertDigest);
78     }
79 
isMatch( String entityInAllowList, String entityName, String certDigest)80     private static boolean isMatch(
81             String entityInAllowList, String entityName, String certDigest) {
82         String[] entityAndCert = entityInAllowList.split(CERT_SPLITTER);
83         if (entityAndCert == null) {
84             return false;
85         } else if (entityAndCert.length == 1 && entityAndCert[0] != null
86                 && !entityAndCert[0].isBlank()) {
87             return entityAndCert[0].equals(entityName);
88         } else if (entityAndCert.length == 2 && entityAndCert[0] != null
89                 && !entityAndCert[0].isBlank() && entityAndCert[1] != null
90                 && !entityAndCert[1].isBlank()) {
91             return entityAndCert[0].equals(entityName) && entityAndCert[1].equals(certDigest);
92         }
93         return false;
94     }
95 }
96