1 /*
2  * Copyright (C) 2019 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.cts.usespermissiondiffcertapp;
18 
19 import static org.junit.Assert.assertEquals;
20 import static org.junit.Assert.assertNotNull;
21 import static org.junit.Assert.assertTrue;
22 import static org.junit.Assert.fail;
23 
24 import android.content.ClipData;
25 import android.content.ContentResolver;
26 import android.content.ContentValues;
27 import android.content.Context;
28 import android.content.Intent;
29 import android.content.UriPermission;
30 import android.database.Cursor;
31 import android.net.Uri;
32 
33 import androidx.test.InstrumentationRegistry;
34 
35 import java.io.IOException;
36 import java.util.List;
37 
38 public class Asserts {
getContext()39     private static Context getContext() {
40         return InstrumentationRegistry.getTargetContext();
41     }
42 
assertAccess(ClipData clip, int mode)43     static void assertAccess(ClipData clip, int mode) {
44         for (int i = 0; i < clip.getItemCount(); i++) {
45             ClipData.Item item = clip.getItemAt(i);
46             Uri uri = item.getUri();
47             if (uri != null) {
48                 assertAccess(uri, mode);
49             } else {
50                 Intent intent = item.getIntent();
51                 uri = intent.getData();
52                 if (uri != null) {
53                     assertAccess(uri, mode);
54                 }
55                 ClipData intentClip = intent.getClipData();
56                 if (intentClip != null) {
57                     assertAccess(intentClip, mode);
58                 }
59             }
60         }
61     }
62 
assertAccess(Uri uri, int mode)63     static void assertAccess(Uri uri, int mode) {
64         if ((mode & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0) {
65             assertReadingContentUriAllowed(uri);
66         } else {
67             assertReadingContentUriNotAllowed(uri, null);
68         }
69         if ((mode & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0) {
70             assertWritingContentUriAllowed(uri);
71         } else {
72             assertWritingContentUriNotAllowed(uri, null);
73         }
74     }
75 
assertReadingContentUriNotAllowed(Uri uri, String msg)76     static void assertReadingContentUriNotAllowed(Uri uri, String msg) {
77         try {
78             getContext().getContentResolver().query(uri, null, null, null, null);
79             fail("expected SecurityException reading " + uri + ": " + msg);
80         } catch (SecurityException expected) {
81             assertNotNull("security exception's error message.", expected.getMessage());
82         }
83     }
84 
assertReadingContentUriAllowed(Uri uri)85     static void assertReadingContentUriAllowed(Uri uri) {
86         try {
87             getContext().getContentResolver().query(uri, null, null, null, null);
88         } catch (SecurityException e) {
89             fail("unexpected SecurityException reading " + uri + ": " + e.getMessage());
90         }
91     }
92 
assertReadingClipNotAllowed(ClipData clip)93     static void assertReadingClipNotAllowed(ClipData clip) {
94         assertReadingClipNotAllowed(clip, null);
95     }
96 
assertReadingClipNotAllowed(ClipData clip, String msg)97     static void assertReadingClipNotAllowed(ClipData clip, String msg) {
98         for (int i=0; i<clip.getItemCount(); i++) {
99             ClipData.Item item = clip.getItemAt(i);
100             Uri uri = item.getUri();
101             if (uri != null) {
102                 assertReadingContentUriNotAllowed(uri, msg);
103             } else {
104                 Intent intent = item.getIntent();
105                 uri = intent.getData();
106                 if (uri != null) {
107                     assertReadingContentUriNotAllowed(uri, msg);
108                 }
109                 ClipData intentClip = intent.getClipData();
110                 if (intentClip != null) {
111                     assertReadingClipNotAllowed(intentClip, msg);
112                 }
113             }
114         }
115     }
116 
assertOpenFileDescriptorModeNotAllowed(Uri uri, String msg, String mode)117     static void assertOpenFileDescriptorModeNotAllowed(Uri uri, String msg, String mode) {
118         try {
119             getContext().getContentResolver().openFileDescriptor(uri, mode).close();
120             fail("expected SecurityException writing " + uri + ": " + msg);
121         } catch (IOException e) {
122             throw new IllegalStateException(e);
123         } catch (SecurityException expected) {
124             assertNotNull("security exception's error message.", expected.getMessage());
125         }
126     }
127 
assertContentUriAllowed(Uri uri)128     static void assertContentUriAllowed(Uri uri) {
129         assertReadingContentUriAllowed(uri);
130         assertWritingContentUriAllowed(uri);
131     }
132 
assertContentUriNotAllowed(Uri uri, String msg)133     static void assertContentUriNotAllowed(Uri uri, String msg) {
134         assertReadingContentUriNotAllowed(uri, msg);
135         assertWritingContentUriNotAllowed(uri, msg);
136     }
137 
assertWritingContentUriNotAllowed(Uri uri, String msg)138     static void assertWritingContentUriNotAllowed(Uri uri, String msg) {
139         final ContentResolver resolver = getContext().getContentResolver();
140         try {
141             resolver.insert(uri, new ContentValues());
142             fail("expected SecurityException inserting " + uri + ": " + msg);
143         } catch (SecurityException expected) {
144             assertNotNull("security exception's error message.", expected.getMessage());
145         }
146 
147         try {
148             resolver.update(uri, new ContentValues(), null, null);
149             fail("expected SecurityException updating " + uri + ": " + msg);
150         } catch (SecurityException expected) {
151             assertNotNull("security exception's error message.", expected.getMessage());
152         }
153 
154         try {
155             resolver.delete(uri, null, null);
156             fail("expected SecurityException deleting " + uri + ": " + msg);
157         } catch (SecurityException expected) {
158             assertNotNull("security exception's error message.", expected.getMessage());
159         }
160 
161         try {
162             getContext().getContentResolver().openOutputStream(uri).close();
163             fail("expected SecurityException writing " + uri + ": " + msg);
164         } catch (IOException e) {
165             throw new IllegalStateException(e);
166         } catch (SecurityException expected) {
167             assertNotNull("security exception's error message.", expected.getMessage());
168         }
169 
170         assertOpenFileDescriptorModeNotAllowed(uri, msg, "w");
171         assertOpenFileDescriptorModeNotAllowed(uri, msg, "wt");
172         assertOpenFileDescriptorModeNotAllowed(uri, msg, "wa");
173         assertOpenFileDescriptorModeNotAllowed(uri, msg, "rw");
174         assertOpenFileDescriptorModeNotAllowed(uri, msg, "rwt");
175     }
176 
assertWritingContentUriAllowed(Uri uri)177     static void assertWritingContentUriAllowed(Uri uri) {
178         final ContentResolver resolver = getContext().getContentResolver();
179         try {
180             resolver.insert(uri, new ContentValues());
181             resolver.update(uri, new ContentValues(), null, null);
182             resolver.delete(uri, null, null);
183 
184             resolver.openOutputStream(uri).close();
185             resolver.openFileDescriptor(uri, "w").close();
186             resolver.openFileDescriptor(uri, "wt").close();
187             resolver.openFileDescriptor(uri, "wa").close();
188             resolver.openFileDescriptor(uri, "rw").close();
189             resolver.openFileDescriptor(uri, "rwt").close();
190         } catch (IOException e) {
191             fail("unexpected IOException writing " + uri + ": " + e.getMessage());
192         } catch (SecurityException e) {
193             fail("unexpected SecurityException writing " + uri + ": " + e.getMessage());
194         }
195     }
196 
assertWritingClipNotAllowed(ClipData clip)197     static void assertWritingClipNotAllowed(ClipData clip) {
198         assertWritingClipNotAllowed(clip, null);
199     }
200 
assertWritingClipNotAllowed(ClipData clip, String msg)201     static void assertWritingClipNotAllowed(ClipData clip, String msg) {
202         for (int i=0; i<clip.getItemCount(); i++) {
203             ClipData.Item item = clip.getItemAt(i);
204             Uri uri = item.getUri();
205             if (uri != null) {
206                 assertWritingContentUriNotAllowed(uri, msg);
207             } else {
208                 Intent intent = item.getIntent();
209                 uri = intent.getData();
210                 if (uri != null) {
211                     assertWritingContentUriNotAllowed(uri, msg);
212                 }
213                 ClipData intentClip = intent.getClipData();
214                 if (intentClip != null) {
215                     assertWritingClipNotAllowed(intentClip, msg);
216                 }
217             }
218         }
219     }
220 
assertReadingClipAllowed(ClipData clip)221     static void assertReadingClipAllowed(ClipData clip) {
222         for (int i=0; i<clip.getItemCount(); i++) {
223             ClipData.Item item = clip.getItemAt(i);
224             Uri uri = item.getUri();
225             if (uri != null) {
226                 Cursor c = getContext().getContentResolver().query(uri,
227                         null, null, null, null);
228                 if (c != null) {
229                     c.close();
230                 }
231             } else {
232                 Intent intent = item.getIntent();
233                 uri = intent.getData();
234                 if (uri != null) {
235                     Cursor c = getContext().getContentResolver().query(uri,
236                             null, null, null, null);
237                     if (c != null) {
238                         c.close();
239                     }
240                 }
241                 ClipData intentClip = intent.getClipData();
242                 if (intentClip != null) {
243                     assertReadingClipAllowed(intentClip);
244                 }
245             }
246         }
247     }
248 
assertWritingClipAllowed(ClipData clip)249     static void assertWritingClipAllowed(ClipData clip) {
250         for (int i=0; i<clip.getItemCount(); i++) {
251             ClipData.Item item = clip.getItemAt(i);
252             Uri uri = item.getUri();
253             if (uri != null) {
254                 getContext().getContentResolver().insert(uri, new ContentValues());
255             } else {
256                 Intent intent = item.getIntent();
257                 uri = intent.getData();
258                 if (uri != null) {
259                     getContext().getContentResolver().insert(uri, new ContentValues());
260                 }
261                 ClipData intentClip = intent.getClipData();
262                 if (intentClip != null) {
263                     assertWritingClipAllowed(intentClip);
264                 }
265             }
266         }
267     }
268 
269 
assertClipDataEquals(ClipData expected, ClipData actual)270     static void assertClipDataEquals(ClipData expected, ClipData actual) {
271         assertEquals(expected.getItemCount(), actual.getItemCount());
272         for (int i = 0; i < expected.getItemCount(); i++) {
273             final ClipData.Item expectedItem = expected.getItemAt(i);
274             final ClipData.Item actualItem = actual.getItemAt(i);
275             assertEquals(expectedItem.getText(), actualItem.getText());
276             assertEquals(expectedItem.getHtmlText(), actualItem.getHtmlText());
277             assertEquals(expectedItem.getIntent(), actualItem.getIntent());
278             assertEquals(expectedItem.getUri(), actualItem.getUri());
279         }
280     }
281 
assertNoPersistedUriPermission()282     static void assertNoPersistedUriPermission() {
283         assertPersistedUriPermission(null, 0, -1, -1);
284     }
285 
assertPersistedUriPermission(Uri uri, int flags, long before, long after)286     static void assertPersistedUriPermission(Uri uri, int flags, long before, long after) {
287         // Assert local
288         final List<UriPermission> perms = getContext()
289                 .getContentResolver().getPersistedUriPermissions();
290         if (uri != null) {
291             assertEquals("expected exactly one permission", 1, perms.size());
292 
293             final UriPermission perm = perms.get(0);
294             assertEquals("unexpected uri", uri, perm.getUri());
295 
296             final long actual = perm.getPersistedTime();
297             if (before != -1) {
298                 assertTrue("found " + actual + " before " + before, actual >= before);
299             }
300             if (after != -1) {
301                 assertTrue("found " + actual + " after " + after, actual <= after);
302             }
303 
304             final boolean expectedRead = (flags & Intent.FLAG_GRANT_READ_URI_PERMISSION) != 0;
305             final boolean expectedWrite = (flags & Intent.FLAG_GRANT_WRITE_URI_PERMISSION) != 0;
306             assertEquals("unexpected read status", expectedRead, perm.isReadPermission());
307             assertEquals("unexpected write status", expectedWrite, perm.isWritePermission());
308 
309         } else {
310             assertEquals("expected zero permissions", 0, perms.size());
311         }
312 
313         Utils.verifyOutgoingPersisted(uri);
314     }
315 }
316