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