1 /*
<lambda>null2  * Copyright (C) 2022 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.permission.safetylabel
18 
19 import android.os.PersistableBundle
20 
21 import androidx.annotation.VisibleForTesting
22 
23 import com.android.permission.safetylabel.DataCategoryConstants.CATEGORY_LOCATION
24 import com.android.permission.safetylabel.DataCategoryConstants.Category
25 import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_ADVERTISING
26 import com.android.permission.safetylabel.DataPurposeConstants.PURPOSE_APP_FUNCTIONALITY
27 import com.android.permission.safetylabel.DataType.KEY_EPHEMERAL
28 import com.android.permission.safetylabel.DataType.KEY_PURPOSES
29 import com.android.permission.safetylabel.DataType.KEY_IS_COLLECTION_OPTIONAL
30 import com.android.permission.safetylabel.SafetyLabel.KEY_VERSION
31 
32 /** A class that facilitates creating test safety label persistable bundles. */
33 object SafetyLabelTestPersistableBundles {
34   private const val TOP_LEVEL_VERSION = 1L
35   private const val SAFETY_LABELS_VERSION = 1L
36   @VisibleForTesting const val INVALID_TOP_LEVEL_VERSION = -1L
37   @VisibleForTesting const val INVALID_SAFETY_LABELS_VERSION = -2L
38   const val INVALID_KEY = "invalid_key"
39 
40   /**
41    * Returns [PersistableBundle] representation of an empty top level metadata persistable bundle.
42    */
43   fun createNonVersionedEmptyMetadataPersistableBundle(): PersistableBundle {
44     return PersistableBundle()
45   }
46 
47   /**
48    * Returns [PersistableBundle] representation of a top level metadata versioned by the provided
49    * top level version number, or the default value [TOP_LEVEL_VERSION] if not provided.
50    */
51   fun createVersionedEmptyMetadataPersistableBundle(
52     version: Long = TOP_LEVEL_VERSION
53   ): PersistableBundle {
54     return PersistableBundle().apply {
55       putLong(KEY_VERSION, version)
56     }
57   }
58 
59   /**
60    * Returns [PersistableBundle] representation of a top level metadata versioned by the provided
61    * top level version number, or the default value [TOP_LEVEL_VERSION] if not provided.
62    * And the embedded safety labels will be versioned by the provided safety labels version number,
63    * or the default value [SAFETY_LABELS_VERSION] if not provided.
64    */
65   fun createMetadataPersistableBundle(
66     topLevelVersion: Long = TOP_LEVEL_VERSION,
67     safetyLabelsVersion: Long = SAFETY_LABELS_VERSION
68   ): PersistableBundle {
69     return createVersionedEmptyMetadataPersistableBundle(topLevelVersion).apply {
70       putPersistableBundle(SafetyLabel.KEY_SAFETY_LABEL,
71         createSafetyLabelPersistableBundle(safetyLabelsVersion))
72     }
73   }
74 
75   /**
76    * Returns [PersistableBundle] representation of a metadata with invalid safety label key.
77    */
78   fun createInvalidMetadataPersistableBundle(): PersistableBundle {
79     return createVersionedEmptyMetadataPersistableBundle().apply {
80       putPersistableBundle(INVALID_KEY, createSafetyLabelPersistableBundle())
81     }
82   }
83 
84   /**
85    * Returns [PersistableBundle] representation of a metadata with invalid safety label bundle.
86    */
87   fun createMetadataPersistableBundleWithInvalidSafetyLabel(): PersistableBundle {
88     return createVersionedEmptyMetadataPersistableBundle().apply {
89       putPersistableBundle(
90           SafetyLabel.KEY_SAFETY_LABEL, createInvalidSafetyLabelPersistableBundle())
91     }
92   }
93 
94   /**
95    * Returns [PersistableBundle] representation of an invalid metadata without version number.
96    */
97   fun createMetadataPersistableBundleWithoutVersion(): PersistableBundle {
98     return createMetadataPersistableBundle().apply { remove(KEY_VERSION) }
99   }
100 
101   /**
102    * Returns [PersistableBundle] representation of a metadata with invalid top level version number.
103    */
104   fun createMetadataPersistableBundleInvalidVersion(): PersistableBundle {
105     return createMetadataPersistableBundle().apply {
106       putLong(KEY_VERSION, INVALID_TOP_LEVEL_VERSION)
107     }
108   }
109 
110   /**
111    * Returns [PersistableBundle] representation of an empty safety label versioned by the provided
112    * version number, or the default value [SAFETY_LABELS_VERSION] if not provided.
113    */
114   private fun createVersionedEmptySafetyLabelsPersistableBundle(
115     version: Long = SAFETY_LABELS_VERSION
116   ): PersistableBundle {
117     return PersistableBundle().apply {
118       putLong(KEY_VERSION, version)
119     }
120   }
121 
122   /** Returns [PersistableBundle] representation of a valid safety label */
123   fun createSafetyLabelPersistableBundle(
124     version: Long = SAFETY_LABELS_VERSION
125   ): PersistableBundle {
126     return createVersionedEmptySafetyLabelsPersistableBundle(version).apply {
127       putPersistableBundle(DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundle())
128     }
129   }
130 
131   /** Returns [PersistableBundle] representation of a non-versioned invalid safety label */
132   fun createSafetyLabelPersistableBundleWithoutVersion(): PersistableBundle {
133     return createSafetyLabelPersistableBundle().apply {
134      remove(KEY_VERSION)
135     }
136   }
137 
138   /** Returns [PersistableBundle] representation of a safety label with invalid version number */
139   fun createSafetyLabelPersistableBundleWithInvalidVersion(): PersistableBundle {
140     return createSafetyLabelPersistableBundle().apply {
141       putLong(KEY_VERSION, INVALID_SAFETY_LABELS_VERSION)
142     }
143   }
144 
145   /** Returns [PersistableBundle] representation of an invalid safety label */
146   fun createInvalidSafetyLabelPersistableBundle(): PersistableBundle {
147     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
148       putPersistableBundle(INVALID_KEY, createDataLabelPersistableBundle())
149     }
150   }
151 
152   /** Returns [PersistableBundle] representation of an invalid safety label */
153   fun createSafetyLabelPersistableBundleWithNullDataCollected(): PersistableBundle {
154     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
155       putPersistableBundle(
156           DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithNullDataCollected())
157     }
158   }
159 
160   /** Returns [PersistableBundle] representation of an invalid safety label */
161   fun createSafetyLabelPersistableBundleWithNullDataShared(): PersistableBundle {
162     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
163       putPersistableBundle(
164           DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithNullDataShared())
165     }
166   }
167 
168   /** Returns [PersistableBundle] representation of an invalid safety label */
169   fun createSafetyLabelPersistableBundleWithEmptyDataCollected(): PersistableBundle {
170     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
171       putPersistableBundle(
172           DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithEmptyDataCollected())
173     }
174   }
175 
176   /** Returns [PersistableBundle] representation of an invalid safety label */
177   fun createSafetyLabelPersistableBundleWithEmptyDataShared(): PersistableBundle {
178     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
179       putPersistableBundle(
180           DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithEmptyDataShared())
181     }
182   }
183 
184   /** Returns [PersistableBundle] representation of an invalid safety label */
185   fun createSafetyLabelPersistableBundleWithInvalidDataCollected(): PersistableBundle {
186     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
187       putPersistableBundle(
188           DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithInvalidDataCollected())
189     }
190   }
191 
192   /** Returns [PersistableBundle] representation of an invalid safety label */
193   fun createSafetyLabelPersistableBundleWithInvalidDataShared(): PersistableBundle {
194     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
195       putPersistableBundle(
196           DataLabel.KEY_DATA_LABEL, createDataLabelPersistableBundleWithInvalidDataShared())
197     }
198   }
199 
200   /** Returns [PersistableBundle] representation of a data label */
201   fun createDataLabelPersistableBundle(): PersistableBundle {
202     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
203       putPersistableBundle(
204           DataLabelConstants.DATA_USAGE_SHARED, createCategoryMapPersistableBundle())
205       putPersistableBundle(
206           DataLabelConstants.DATA_USAGE_COLLECTED, createCategoryMapPersistableBundle())
207     }
208   }
209 
210   /** Returns [PersistableBundle] representation of an invalid data label */
211   fun createInvalidDataLabelPersistableBundle(): PersistableBundle {
212     return createVersionedEmptySafetyLabelsPersistableBundle().apply {
213       putPersistableBundle(INVALID_KEY, createCategoryMapPersistableBundle())
214     }
215   }
216 
217   /** Returns [PersistableBundle] representation of a null data collected data label */
218   private fun createDataLabelPersistableBundleWithNullDataCollected(): PersistableBundle {
219     return createDataLabelPersistableBundle().apply {
220       remove(DataLabelConstants.DATA_USAGE_COLLECTED)
221     }
222   }
223 
224   /** Returns [PersistableBundle] representation of a null data shared data label */
225   private fun createDataLabelPersistableBundleWithNullDataShared(): PersistableBundle {
226     return createDataLabelPersistableBundle().apply { remove(DataLabelConstants.DATA_USAGE_SHARED) }
227   }
228 
229   /** Returns [PersistableBundle] representation of an empty data collected data label */
230   private fun createDataLabelPersistableBundleWithEmptyDataCollected(): PersistableBundle {
231     return createDataLabelPersistableBundle().apply {
232       remove(DataLabelConstants.DATA_USAGE_COLLECTED)
233       putPersistableBundle(DataLabelConstants.DATA_USAGE_COLLECTED, PersistableBundle.EMPTY)
234     }
235   }
236 
237   /** Returns [PersistableBundle] representation of an empty data shared data label */
238   private fun createDataLabelPersistableBundleWithEmptyDataShared(): PersistableBundle {
239     return createDataLabelPersistableBundle().apply {
240       remove(DataLabelConstants.DATA_USAGE_SHARED)
241       putPersistableBundle(DataLabelConstants.DATA_USAGE_SHARED, PersistableBundle.EMPTY)
242     }
243   }
244 
245   /** Returns [PersistableBundle] representation of an invalid data collected data label */
246   private fun createDataLabelPersistableBundleWithInvalidDataCollected(): PersistableBundle {
247     return createDataLabelPersistableBundle().apply {
248       remove(DataLabelConstants.DATA_USAGE_COLLECTED)
249       putPersistableBundle(
250           DataLabelConstants.DATA_USAGE_COLLECTED, createInvalidCategoryMapPersistableBundle())
251     }
252   }
253 
254   /** Returns [PersistableBundle] representation of an invalid data shared data label */
255   private fun createDataLabelPersistableBundleWithInvalidDataShared(): PersistableBundle {
256     return createDataLabelPersistableBundle().apply {
257       remove(DataLabelConstants.DATA_USAGE_SHARED)
258       putPersistableBundle(
259           DataLabelConstants.DATA_USAGE_SHARED, createInvalidCategoryMapPersistableBundle())
260     }
261   }
262 
263   /** Returns [PersistableBundle] representation of data label with additional invalid categories*/
264   fun createDataLabelPersistableBundleWithAdditonalInvalidCategory(): PersistableBundle {
265     return PersistableBundle().apply {
266       putPersistableBundle(
267           DataLabelConstants.DATA_USAGE_SHARED,
268           createCategoryMapPersistableBundleWithAdditionalInvalidCategory())
269       putPersistableBundle(
270           DataLabelConstants.DATA_USAGE_COLLECTED,
271           createCategoryMapPersistableBundleWithAdditionalInvalidCategory())
272     }
273   }
274 
275   /** Returns [PersistableBundle] representation of a [Map] of valid data categories */
276   fun createCategoryMapPersistableBundle(): PersistableBundle {
277     return PersistableBundle().apply {
278       DataCategoryConstants.VALID_CATEGORIES.forEach { categoryKey ->
279         putPersistableBundle(categoryKey, createTypeMapPersistableBundle(categoryKey))
280       }
281     }
282   }
283 
284   /** Returns [PersistableBundle] representation of a [Map] of valid data categories */
285   fun createCategoryMapPersistableBundleWithAdditionalInvalidCategory(): PersistableBundle {
286     return PersistableBundle().apply {
287       DataCategoryConstants.VALID_CATEGORIES.forEach { categoryKey ->
288         putPersistableBundle(categoryKey, createTypeMapPersistableBundle(categoryKey))
289       }
290       putPersistableBundle(INVALID_KEY, createTypeMapPersistableBundle(CATEGORY_LOCATION))
291     }
292   }
293 
294   /**
295    * Returns [PersistableBundle] representation of a [Map] of valid data categories and invalid
296    * types
297    */
298   fun createCategoryMapPersistableBundleWithInvalidTypes(): PersistableBundle {
299     return PersistableBundle().apply {
300       DataCategoryConstants.VALID_CATEGORIES.forEach { categoryKey ->
301         putPersistableBundle(categoryKey, createInvalidTypeMapPersistableBundle())
302       }
303     }
304   }
305 
306   /** Returns [PersistableBundle] representation of a [Map] of invalid data categories */
307   fun createInvalidCategoryMapPersistableBundle(): PersistableBundle {
308     return PersistableBundle().apply {
309       putPersistableBundle(INVALID_KEY, createTypeMapPersistableBundle(CATEGORY_LOCATION))
310     }
311   }
312 
313   /** Returns [PersistableBundle] representation of a [Map] of valid data type */
314   fun createTypeMapPersistableBundle(@Category category: String): PersistableBundle {
315     return PersistableBundle().apply {
316       DataTypeConstants.getValidDataTypesForCategory(category).forEach { type ->
317         putPersistableBundle(type, createTypePersistableBundle())
318       }
319     }
320   }
321 
322   /** Returns [PersistableBundle] representation of a [Map] of invalid data type */
323   fun createInvalidTypeMapPersistableBundle(): PersistableBundle {
324     return PersistableBundle().apply {
325       putPersistableBundle(INVALID_KEY, createTypePersistableBundle())
326     }
327   }
328 
329   /** Returns [PersistableBundle] representation of a [Map] of valid type, with invalid data */
330   fun createTypeMapWithInvalidTypeDataPersistableBundle(
331       @Category category: String
332   ): PersistableBundle {
333     return PersistableBundle().apply {
334       DataTypeConstants.getValidDataTypesForCategory(category).forEach { type ->
335         putPersistableBundle(type, createInvalidTypePersistableBundle())
336       }
337     }
338   }
339 
340   /** Returns [PersistableBundle] representation of a valid data type */
341   fun createTypePersistableBundle(): PersistableBundle {
342     return PersistableBundle().apply {
343       putIntArray(KEY_PURPOSES, intArrayOf(PURPOSE_APP_FUNCTIONALITY, PURPOSE_ADVERTISING))
344       putBoolean(KEY_IS_COLLECTION_OPTIONAL, true)
345       putBoolean(KEY_EPHEMERAL, true)
346     }
347   }
348 
349   /** Returns [PersistableBundle] representation of an invalid data type */
350   fun createInvalidTypePersistableBundle(): PersistableBundle {
351     return PersistableBundle().apply { putLong(INVALID_KEY, 0) }
352   }
353 }
354