1/*
2 * Copyright (C) 2009 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
17package com.android.providers.downloads.public_api_access_tests;
18
19import android.app.DownloadManager;
20import android.content.ContentResolver;
21import android.content.ContentValues;
22import android.net.Uri;
23import android.provider.Downloads;
24import android.test.AndroidTestCase;
25import android.test.suitebuilder.annotation.MediumTest;
26
27/**
28 * DownloadProvider allows apps without permission ACCESS_DOWNLOAD_MANAGER to access it -- this is
29 * how the public API works.  But such access is subject to strict constraints on what can be
30 * inserted.  This test suite checks those constraints.
31 */
32@MediumTest
33public class PublicApiAccessTest extends AndroidTestCase {
34    private static final String[] DISALLOWED_COLUMNS = new String[] {
35                    Downloads.Impl.COLUMN_COOKIE_DATA,
36                    Downloads.Impl.COLUMN_REFERER,
37                    Downloads.Impl.COLUMN_USER_AGENT,
38                    Downloads.Impl.COLUMN_NO_INTEGRITY,
39                    Downloads.Impl.COLUMN_NOTIFICATION_CLASS,
40                    Downloads.Impl.COLUMN_NOTIFICATION_EXTRAS,
41                    Downloads.Impl.COLUMN_OTHER_UID,
42                    Downloads.Impl.COLUMN_APP_DATA,
43                    Downloads.Impl.COLUMN_CONTROL,
44                    Downloads.Impl.COLUMN_STATUS,
45            };
46
47    private ContentResolver mContentResolver;
48    private DownloadManager mManager;
49
50    @Override
51    protected void setUp() throws Exception {
52        super.setUp();
53        mContentResolver = getContext().getContentResolver();
54        mManager = new DownloadManager(mContentResolver, getContext().getPackageName());
55    }
56
57    @Override
58    protected void tearDown() throws Exception {
59        if (mContentResolver != null) {
60            mContentResolver.delete(Downloads.Impl.CONTENT_URI, null, null);
61        }
62        super.tearDown();
63    }
64
65    public void testMinimalValidWrite() {
66        mContentResolver.insert(Downloads.Impl.CONTENT_URI, buildValidValues());
67    }
68
69    public void testMaximalValidWrite() {
70        ContentValues values = buildValidValues();
71        values.put(Downloads.Impl.COLUMN_TITLE, "foo");
72        values.put(Downloads.Impl.COLUMN_DESCRIPTION, "foo");
73        values.put(Downloads.Impl.COLUMN_MIME_TYPE, "foo");
74        values.put(Downloads.Impl.COLUMN_NOTIFICATION_PACKAGE, "foo");
75        values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, 0);
76        values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, true);
77        values.put(Downloads.Impl.RequestHeaders.INSERT_KEY_PREFIX + "0", "X-Some-Header: value");
78        mContentResolver.insert(Downloads.Impl.CONTENT_URI, values);
79    }
80
81    private ContentValues buildValidValues() {
82        ContentValues values = new ContentValues();
83        values.put(Downloads.Impl.COLUMN_URI, "foo");
84        values.put(Downloads.Impl.COLUMN_DESTINATION,
85                Downloads.Impl.DESTINATION_CACHE_PARTITION_PURGEABLE);
86        values.put(Downloads.Impl.COLUMN_VISIBILITY, Downloads.Impl.VISIBILITY_VISIBLE);
87        values.put(Downloads.Impl.COLUMN_IS_PUBLIC_API, true);
88        return values;
89    }
90
91    public void testNoPublicApi() {
92        ContentValues values = buildValidValues();
93        values.remove(Downloads.Impl.COLUMN_IS_PUBLIC_API);
94        testInvalidValues(values);
95    }
96
97    public void testInvalidDestination() {
98        ContentValues values = buildValidValues();
99        values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_EXTERNAL);
100        testInvalidValues(values);
101        values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_CACHE_PARTITION);
102        testInvalidValues(values);
103    }
104
105    public void testInvalidVisibility() {
106        ContentValues values = buildValidValues();
107        values.put(Downloads.Impl.COLUMN_VISIBILITY,
108                Downloads.Impl.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
109        testInvalidValues(values);
110
111        values.put(Downloads.Impl.COLUMN_VISIBILITY, Downloads.Impl.VISIBILITY_HIDDEN);
112        testInvalidValues(values);
113
114        values.remove(Downloads.Impl.COLUMN_VISIBILITY);
115        testInvalidValues(values);
116    }
117
118    public void testDisallowedColumns() {
119        for (String column : DISALLOWED_COLUMNS) {
120            ContentValues values = buildValidValues();
121            values.put(column, 1);
122            testInvalidValues(values);
123        }
124    }
125
126    public void testFileUriWithoutExternalPermission() {
127        ContentValues values = buildValidValues();
128        values.put(Downloads.Impl.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI);
129        values.put(Downloads.Impl.COLUMN_FILE_NAME_HINT, "file:///sdcard/foo");
130        testInvalidValues(values);
131    }
132
133    private void testInvalidValues(ContentValues values) {
134        try {
135            mContentResolver.insert(Downloads.Impl.CONTENT_URI, values);
136            fail("Didn't get SecurityException as expected");
137        } catch (SecurityException exc) {
138            // expected
139        }
140    }
141
142    public void testDownloadManagerRequest() {
143        // first try a minimal request
144        DownloadManager.Request request = new DownloadManager.Request(Uri.parse("http://localhost/path"));
145        mManager.enqueue(request);
146
147        // now set everything we can, save for external destintion (for which we lack permission)
148        request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_WIFI);
149        request.setAllowedOverRoaming(false);
150        request.setTitle("test");
151        request.setDescription("test");
152        request.setMimeType("text/html");
153        request.addRequestHeader("X-Some-Header", "value");
154        mManager.enqueue(request);
155    }
156}
157