diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java index bd8f7b9893..56a5ee5df7 100644 --- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java +++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java @@ -75,34 +75,31 @@ class CertificateTransparencyDownloader extends BroadcastReceiver { } } - void startPublicKeyDownload(String publicKeyUrl) { - long downloadId = download(publicKeyUrl); - if (downloadId == -1) { - Log.e(TAG, "Metadata download request failed for " + publicKeyUrl); - return; + long startPublicKeyDownload() { + long downloadId = download(mDataStore.getProperty(Config.PUBLIC_KEY_URL)); + if (downloadId != -1) { + mDataStore.setPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, downloadId); + mDataStore.store(); } - mDataStore.setPropertyLong(Config.PUBLIC_KEY_URL_KEY, downloadId); - mDataStore.store(); + return downloadId; } - void startMetadataDownload(String metadataUrl) { - long downloadId = download(metadataUrl); - if (downloadId == -1) { - Log.e(TAG, "Metadata download request failed for " + metadataUrl); - return; + long startMetadataDownload() { + long downloadId = download(mDataStore.getProperty(Config.METADATA_URL)); + if (downloadId != -1) { + mDataStore.setPropertyLong(Config.METADATA_DOWNLOAD_ID, downloadId); + mDataStore.store(); } - mDataStore.setPropertyLong(Config.METADATA_URL_KEY, downloadId); - mDataStore.store(); + return downloadId; } - void startContentDownload(String contentUrl) { - long downloadId = download(contentUrl); - if (downloadId == -1) { - Log.e(TAG, "Content download request failed for " + contentUrl); - return; + long startContentDownload() { + long downloadId = download(mDataStore.getProperty(Config.CONTENT_URL)); + if (downloadId != -1) { + mDataStore.setPropertyLong(Config.CONTENT_DOWNLOAD_ID, downloadId); + mDataStore.store(); } - mDataStore.setPropertyLong(Config.CONTENT_URL_KEY, downloadId); - mDataStore.store(); + return downloadId; } @Override @@ -157,7 +154,11 @@ class CertificateTransparencyDownloader extends BroadcastReceiver { return; } - startMetadataDownload(mDataStore.getProperty(Config.METADATA_URL_PENDING)); + if (startMetadataDownload() == -1) { + Log.e(TAG, "Metadata download not started."); + } else if (Config.DEBUG) { + Log.d(TAG, "Metadata download started successfully."); + } } private void handleMetadataDownloadCompleted(long downloadId) { @@ -166,7 +167,11 @@ class CertificateTransparencyDownloader extends BroadcastReceiver { handleDownloadFailed(status); return; } - startContentDownload(mDataStore.getProperty(Config.CONTENT_URL_PENDING)); + if (startContentDownload() == -1) { + Log.e(TAG, "Content download not started."); + } else if (Config.DEBUG) { + Log.d(TAG, "Content download started successfully."); + } } private void handleContentDownloadCompleted(long downloadId) { @@ -204,8 +209,6 @@ class CertificateTransparencyDownloader extends BroadcastReceiver { return; } - String contentUrl = mDataStore.getProperty(Config.CONTENT_URL_PENDING); - String metadataUrl = mDataStore.getProperty(Config.METADATA_URL_PENDING); try (InputStream inputStream = mContext.getContentResolver().openInputStream(contentUri)) { success = mInstaller.install(Config.COMPATIBILITY_VERSION, inputStream, version); } catch (IOException e) { @@ -216,8 +219,6 @@ class CertificateTransparencyDownloader extends BroadcastReceiver { if (success) { // Update information about the stored version on successful install. mDataStore.setProperty(Config.VERSION, version); - mDataStore.setProperty(Config.CONTENT_URL, contentUrl); - mDataStore.setProperty(Config.METADATA_URL, metadataUrl); mDataStore.store(); } } @@ -236,30 +237,60 @@ class CertificateTransparencyDownloader extends BroadcastReceiver { } } + @VisibleForTesting + long getPublicKeyDownloadId() { + return mDataStore.getPropertyLong(Config.PUBLIC_KEY_DOWNLOAD_ID, -1); + } + + @VisibleForTesting + long getMetadataDownloadId() { + return mDataStore.getPropertyLong(Config.METADATA_DOWNLOAD_ID, -1); + } + + @VisibleForTesting + long getContentDownloadId() { + return mDataStore.getPropertyLong(Config.CONTENT_DOWNLOAD_ID, -1); + } + + @VisibleForTesting + boolean hasPublicKeyDownloadId() { + return getPublicKeyDownloadId() != -1; + } + + @VisibleForTesting + boolean hasMetadataDownloadId() { + return getMetadataDownloadId() != -1; + } + + @VisibleForTesting + boolean hasContentDownloadId() { + return getContentDownloadId() != -1; + } + @VisibleForTesting boolean isPublicKeyDownloadId(long downloadId) { - return mDataStore.getPropertyLong(Config.PUBLIC_KEY_URL_KEY, -1) == downloadId; + return getPublicKeyDownloadId() == downloadId; } @VisibleForTesting boolean isMetadataDownloadId(long downloadId) { - return mDataStore.getPropertyLong(Config.METADATA_URL_KEY, -1) == downloadId; + return getMetadataDownloadId() == downloadId; } @VisibleForTesting boolean isContentDownloadId(long downloadId) { - return mDataStore.getPropertyLong(Config.CONTENT_URL_KEY, -1) == downloadId; + return getContentDownloadId() == downloadId; } private Uri getPublicKeyDownloadUri() { - return mDownloadHelper.getUri(mDataStore.getPropertyLong(Config.PUBLIC_KEY_URL_KEY, -1)); + return mDownloadHelper.getUri(getPublicKeyDownloadId()); } private Uri getMetadataDownloadUri() { - return mDownloadHelper.getUri(mDataStore.getPropertyLong(Config.METADATA_URL_KEY, -1)); + return mDownloadHelper.getUri(getMetadataDownloadId()); } private Uri getContentDownloadUri() { - return mDownloadHelper.getUri(mDataStore.getPropertyLong(Config.CONTENT_URL_KEY, -1)); + return mDownloadHelper.getUri(getContentDownloadId()); } } diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java index f359a2aff4..3138ea7a83 100644 --- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java +++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java @@ -115,11 +115,14 @@ class CertificateTransparencyFlagsListener implements DeviceConfig.OnPropertiesC // TODO: handle the case where there is already a pending download. - mDataStore.setProperty(Config.VERSION_PENDING, newVersion); - mDataStore.setProperty(Config.CONTENT_URL_PENDING, newContentUrl); - mDataStore.setProperty(Config.METADATA_URL_PENDING, newMetadataUrl); + mDataStore.setProperty(Config.CONTENT_URL, newContentUrl); + mDataStore.setProperty(Config.METADATA_URL, newMetadataUrl); mDataStore.store(); - mCertificateTransparencyDownloader.startMetadataDownload(newMetadataUrl); + if (mCertificateTransparencyDownloader.startMetadataDownload() == -1) { + Log.e(TAG, "Metadata download not started."); + } else if (Config.DEBUG) { + Log.d(TAG, "Metadata download started successfully."); + } } } diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java index c5d0413791..bf23cb09d4 100644 --- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java +++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyJob.java @@ -78,11 +78,15 @@ public class CertificateTransparencyJob extends BroadcastReceiver { Log.d(TAG, "Starting CT daily job."); } - mDataStore.setProperty(Config.CONTENT_URL_PENDING, Config.URL_LOG_LIST); - mDataStore.setProperty(Config.METADATA_URL_PENDING, Config.URL_SIGNATURE); - mDataStore.setProperty(Config.PUBLIC_KEY_URL_PENDING, Config.URL_PUBLIC_KEY); + mDataStore.setProperty(Config.CONTENT_URL, Config.URL_LOG_LIST); + mDataStore.setProperty(Config.METADATA_URL, Config.URL_SIGNATURE); + mDataStore.setProperty(Config.PUBLIC_KEY_URL, Config.URL_PUBLIC_KEY); mDataStore.store(); - mCertificateTransparencyDownloader.startPublicKeyDownload(Config.URL_PUBLIC_KEY); + if (mCertificateTransparencyDownloader.startPublicKeyDownload() == -1) { + Log.e(TAG, "Public key download not started."); + } else if (Config.DEBUG) { + Log.d(TAG, "Public key download started successfully."); + } } } diff --git a/networksecurity/service/src/com/android/server/net/ct/Config.java b/networksecurity/service/src/com/android/server/net/ct/Config.java index ae30f3a421..70d8e42280 100644 --- a/networksecurity/service/src/com/android/server/net/ct/Config.java +++ b/networksecurity/service/src/com/android/server/net/ct/Config.java @@ -47,21 +47,17 @@ final class Config { static final String FLAG_PUBLIC_KEY = FLAGS_PREFIX + "public_key"; // properties - static final String VERSION_PENDING = "version_pending"; static final String VERSION = "version"; - static final String CONTENT_URL_PENDING = "content_url_pending"; static final String CONTENT_URL = "content_url"; - static final String CONTENT_URL_KEY = "content_url_key"; - static final String METADATA_URL_PENDING = "metadata_url_pending"; + static final String CONTENT_DOWNLOAD_ID = "content_download_id"; static final String METADATA_URL = "metadata_url"; - static final String METADATA_URL_KEY = "metadata_url_key"; - static final String PUBLIC_KEY_URL_PENDING = "public_key_url_pending"; + static final String METADATA_DOWNLOAD_ID = "metadata_download_id"; static final String PUBLIC_KEY_URL = "public_key_url"; - static final String PUBLIC_KEY_URL_KEY = "public_key_url_key"; + static final String PUBLIC_KEY_DOWNLOAD_ID = "public_key_download_id"; // URLs - static final String URL_BASE = "https://www.gstatic.com/android/certificate_transparency/"; - static final String URL_LOG_LIST = URL_BASE + "log_list.json"; - static final String URL_SIGNATURE = URL_BASE + "log_list.sig"; - static final String URL_PUBLIC_KEY = URL_BASE + "log_list.pub"; + static final String URL_PREFIX = "https://www.gstatic.com/android/certificate_transparency/"; + static final String URL_LOG_LIST = URL_PREFIX + "log_list.json"; + static final String URL_SIGNATURE = URL_PREFIX + "log_list.sig"; + static final String URL_PUBLIC_KEY = URL_PREFIX + "log_list.pub"; } diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java index 87d75e6cc7..ffa12838c9 100644 --- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java +++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java @@ -27,14 +27,16 @@ import static org.mockito.Mockito.when; import static java.nio.charset.StandardCharsets.UTF_8; import android.app.DownloadManager; +import android.app.DownloadManager.Query; +import android.app.DownloadManager.Request; import android.content.Context; import android.content.Intent; +import android.database.Cursor; +import android.database.MatrixCursor; import android.net.Uri; import androidx.test.platform.app.InstrumentationRegistry; -import com.android.server.net.ct.DownloadHelper.DownloadStatus; - import org.json.JSONException; import org.json.JSONObject; import org.junit.After; @@ -63,7 +65,7 @@ import java.util.Base64; @RunWith(JUnit4.class) public class CertificateTransparencyDownloaderTest { - @Mock private DownloadHelper mDownloadHelper; + @Mock private DownloadManager mDownloadManager; @Mock private CertificateTransparencyInstaller mCertificateTransparencyInstaller; private PrivateKey mPrivateKey; @@ -79,7 +81,6 @@ public class CertificateTransparencyDownloaderTest { @Before public void setUp() throws IOException, GeneralSecurityException { MockitoAnnotations.initMocks(this); - KeyPairGenerator instance = KeyPairGenerator.getInstance("RSA"); KeyPair keyPair = instance.generateKeyPair(); mPrivateKey = keyPair.getPrivate(); @@ -88,16 +89,17 @@ public class CertificateTransparencyDownloaderTest { mContext = InstrumentationRegistry.getInstrumentation().getContext(); mTempFile = File.createTempFile("datastore-test", ".properties"); mDataStore = new DataStore(mTempFile); - mDataStore.load(); mSignatureVerifier = new SignatureVerifier(mContext); - mCertificateTransparencyDownloader = new CertificateTransparencyDownloader( mContext, mDataStore, - mDownloadHelper, + new DownloadHelper(mDownloadManager), mSignatureVerifier, mCertificateTransparencyInstaller); + + prepareDataStore(); + prepareDownloadManager(); } @After @@ -108,116 +110,108 @@ public class CertificateTransparencyDownloaderTest { @Test public void testDownloader_startPublicKeyDownload() { - String publicKeyUrl = "http://test-public-key.org"; - long downloadId = preparePublicKeyDownload(publicKeyUrl); + assertThat(mCertificateTransparencyDownloader.hasPublicKeyDownloadId()).isFalse(); + long downloadId = mCertificateTransparencyDownloader.startPublicKeyDownload(); - assertThat(mCertificateTransparencyDownloader.isPublicKeyDownloadId(downloadId)).isFalse(); - mCertificateTransparencyDownloader.startPublicKeyDownload(publicKeyUrl); + assertThat(mCertificateTransparencyDownloader.hasPublicKeyDownloadId()).isTrue(); assertThat(mCertificateTransparencyDownloader.isPublicKeyDownloadId(downloadId)).isTrue(); } @Test public void testDownloader_startMetadataDownload() { - String metadataUrl = "http://test-metadata.org"; - long downloadId = prepareMetadataDownload(metadataUrl); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse(); + long downloadId = mCertificateTransparencyDownloader.startMetadataDownload(); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(downloadId)).isFalse(); - mCertificateTransparencyDownloader.startMetadataDownload(metadataUrl); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isTrue(); assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(downloadId)).isTrue(); } @Test public void testDownloader_startContentDownload() { - String contentUrl = "http://test-content.org"; - long downloadId = prepareContentDownload(contentUrl); + assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse(); + long downloadId = mCertificateTransparencyDownloader.startContentDownload(); - assertThat(mCertificateTransparencyDownloader.isContentDownloadId(downloadId)).isFalse(); - mCertificateTransparencyDownloader.startContentDownload(contentUrl); + assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isTrue(); assertThat(mCertificateTransparencyDownloader.isContentDownloadId(downloadId)).isTrue(); } @Test public void testDownloader_publicKeyDownloadSuccess_updatePublicKey_startMetadataDownload() throws Exception { - long publicKeyId = prepareSuccessfulPublicKeyDownload(writePublicKeyToFile(mPublicKey)); - long metadataId = prepareMetadataDownload("http://test-metadata.org"); + long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload(); + setSuccessfulDownload(publicKeyId, writePublicKeyToFile(mPublicKey)); assertThat(mSignatureVerifier.getPublicKey()).isEmpty(); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse(); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse(); mCertificateTransparencyDownloader.onReceive( mContext, makeDownloadCompleteIntent(publicKeyId)); assertThat(mSignatureVerifier.getPublicKey()).hasValue(mPublicKey); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isTrue(); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isTrue(); } @Test public void testDownloader_publicKeyDownloadSuccess_updatePublicKeyFail_doNotStartMetadataDownload() throws Exception { - long publicKeyId = - prepareSuccessfulPublicKeyDownload( - writeToFile("i_am_not_a_base64_encoded_public_key".getBytes())); - long metadataId = prepareMetadataDownload("http://test-metadata.org"); + long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload(); + setSuccessfulDownload( + publicKeyId, writeToFile("i_am_not_a_base64_encoded_public_key".getBytes())); assertThat(mSignatureVerifier.getPublicKey()).isEmpty(); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse(); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse(); mCertificateTransparencyDownloader.onReceive( mContext, makeDownloadCompleteIntent(publicKeyId)); assertThat(mSignatureVerifier.getPublicKey()).isEmpty(); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse(); - verify(mDownloadHelper, never()).startDownload(anyString()); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse(); } @Test public void testDownloader_publicKeyDownloadFail_doNotUpdatePublicKey() throws Exception { - long publicKeyId = - prepareFailedPublicKeyDownload( - // Failure cases where we give up on the download. - DownloadManager.ERROR_INSUFFICIENT_SPACE, - DownloadManager.ERROR_HTTP_DATA_ERROR); + long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload(); + setFailedDownload( + publicKeyId, // Failure cases where we give up on the download. + DownloadManager.ERROR_INSUFFICIENT_SPACE, + DownloadManager.ERROR_HTTP_DATA_ERROR); Intent downloadCompleteIntent = makeDownloadCompleteIntent(publicKeyId); - long metadataId = prepareMetadataDownload("http://test-metadata.org"); assertThat(mSignatureVerifier.getPublicKey()).isEmpty(); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse(); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse(); mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent); mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent); assertThat(mSignatureVerifier.getPublicKey()).isEmpty(); - assertThat(mCertificateTransparencyDownloader.isMetadataDownloadId(metadataId)).isFalse(); - verify(mDownloadHelper, never()).startDownload(anyString()); + assertThat(mCertificateTransparencyDownloader.hasMetadataDownloadId()).isFalse(); } @Test public void testDownloader_metadataDownloadSuccess_startContentDownload() { - long metadataId = prepareSuccessfulMetadataDownload(new File("log_list.sig")); - long contentId = prepareContentDownload("http://test-content.org"); + long metadataId = mCertificateTransparencyDownloader.startMetadataDownload(); + setSuccessfulDownload(metadataId, new File("log_list.sig")); - assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isFalse(); + assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse(); mCertificateTransparencyDownloader.onReceive( mContext, makeDownloadCompleteIntent(metadataId)); - assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isTrue(); + assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isTrue(); } @Test public void testDownloader_metadataDownloadFail_doNotStartContentDownload() { - long metadataId = - prepareFailedMetadataDownload( - // Failure cases where we give up on the download. - DownloadManager.ERROR_INSUFFICIENT_SPACE, - DownloadManager.ERROR_HTTP_DATA_ERROR); + long metadataId = mCertificateTransparencyDownloader.startMetadataDownload(); + setFailedDownload( + metadataId, + // Failure cases where we give up on the download. + DownloadManager.ERROR_INSUFFICIENT_SPACE, + DownloadManager.ERROR_HTTP_DATA_ERROR); Intent downloadCompleteIntent = makeDownloadCompleteIntent(metadataId); - long contentId = prepareContentDownload("http://test-content.org"); - assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isFalse(); + assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse(); mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent); mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent); - assertThat(mCertificateTransparencyDownloader.isContentDownloadId(contentId)).isFalse(); - verify(mDownloadHelper, never()).startDownload(anyString()); + assertThat(mCertificateTransparencyDownloader.hasContentDownloadId()).isFalse(); } @Test @@ -227,8 +221,10 @@ public class CertificateTransparencyDownloaderTest { File logListFile = makeLogListFile(newVersion); File metadataFile = sign(logListFile); mSignatureVerifier.setPublicKey(mPublicKey); - prepareSuccessfulMetadataDownload(metadataFile); - long contentId = prepareSuccessfulContentDownload(logListFile); + long metadataId = mCertificateTransparencyDownloader.startMetadataDownload(); + setSuccessfulDownload(metadataId, metadataFile); + long contentId = mCertificateTransparencyDownloader.startContentDownload(); + setSuccessfulDownload(contentId, logListFile); when(mCertificateTransparencyInstaller.install( eq(Config.COMPATIBILITY_VERSION), any(), anyString())) .thenReturn(true); @@ -242,11 +238,12 @@ public class CertificateTransparencyDownloaderTest { @Test public void testDownloader_contentDownloadFail_doNotInstall() throws Exception { - long contentId = - prepareFailedContentDownload( - // Failure cases where we give up on the download. - DownloadManager.ERROR_INSUFFICIENT_SPACE, - DownloadManager.ERROR_HTTP_DATA_ERROR); + long contentId = mCertificateTransparencyDownloader.startContentDownload(); + setFailedDownload( + contentId, + // Failure cases where we give up on the download. + DownloadManager.ERROR_INSUFFICIENT_SPACE, + DownloadManager.ERROR_HTTP_DATA_ERROR); Intent downloadCompleteIntent = makeDownloadCompleteIntent(contentId); mCertificateTransparencyDownloader.onReceive(mContext, downloadCompleteIntent); @@ -262,8 +259,10 @@ public class CertificateTransparencyDownloaderTest { File logListFile = makeLogListFile("456"); File metadataFile = sign(logListFile); mSignatureVerifier.setPublicKey(mPublicKey); - prepareSuccessfulMetadataDownload(metadataFile); - long contentId = prepareSuccessfulContentDownload(logListFile); + long metadataId = mCertificateTransparencyDownloader.startMetadataDownload(); + setSuccessfulDownload(metadataId, metadataFile); + long contentId = mCertificateTransparencyDownloader.startContentDownload(); + setSuccessfulDownload(contentId, logListFile); when(mCertificateTransparencyInstaller.install( eq(Config.COMPATIBILITY_VERSION), any(), anyString())) .thenReturn(false); @@ -281,8 +280,10 @@ public class CertificateTransparencyDownloaderTest { File logListFile = makeLogListFile("456"); File metadataFile = File.createTempFile("log_list-wrong_metadata", "sig"); mSignatureVerifier.setPublicKey(mPublicKey); - prepareSuccessfulMetadataDownload(metadataFile); - long contentId = prepareSuccessfulContentDownload(logListFile); + long metadataId = mCertificateTransparencyDownloader.startMetadataDownload(); + setSuccessfulDownload(metadataId, metadataFile); + long contentId = mCertificateTransparencyDownloader.startContentDownload(); + setSuccessfulDownload(contentId, logListFile); assertNoVersionIsInstalled(); mCertificateTransparencyDownloader.onReceive( @@ -299,8 +300,10 @@ public class CertificateTransparencyDownloaderTest { File logListFile = makeLogListFile("456"); File metadataFile = sign(logListFile); mSignatureVerifier.resetPublicKey(); - prepareSuccessfulMetadataDownload(metadataFile); - long contentId = prepareSuccessfulContentDownload(logListFile); + long metadataId = mCertificateTransparencyDownloader.startMetadataDownload(); + setSuccessfulDownload(metadataId, metadataFile); + long contentId = mCertificateTransparencyDownloader.startContentDownload(); + setSuccessfulDownload(contentId, logListFile); assertNoVersionIsInstalled(); mCertificateTransparencyDownloader.onReceive( @@ -321,26 +324,23 @@ public class CertificateTransparencyDownloaderTest { assertNoVersionIsInstalled(); // 1. Start download of public key. - String publicKeyUrl = "http://test-public-key.org"; - long publicKeyId = preparePublicKeyDownload(publicKeyUrl); - - mCertificateTransparencyDownloader.startPublicKeyDownload(publicKeyUrl); + long publicKeyId = mCertificateTransparencyDownloader.startPublicKeyDownload(); // 2. On successful public key download, set the key and start the metatadata download. setSuccessfulDownload(publicKeyId, publicKeyFile); - long metadataId = prepareMetadataDownload("http://test-metadata.org"); mCertificateTransparencyDownloader.onReceive( mContext, makeDownloadCompleteIntent(publicKeyId)); // 3. On successful metadata download, start the content download. + long metadataId = mCertificateTransparencyDownloader.getMetadataDownloadId(); setSuccessfulDownload(metadataId, metadataFile); - long contentId = prepareContentDownload("http://test-content.org"); mCertificateTransparencyDownloader.onReceive( mContext, makeDownloadCompleteIntent(metadataId)); // 4. On successful content download, verify the signature and install the new version. + long contentId = mCertificateTransparencyDownloader.getContentDownloadId(); setSuccessfulDownload(contentId, logListFile); when(mCertificateTransparencyInstaller.install( eq(Config.COMPATIBILITY_VERSION), any(), anyString())) @@ -354,16 +354,10 @@ public class CertificateTransparencyDownloaderTest { private void assertNoVersionIsInstalled() { assertThat(mDataStore.getProperty(Config.VERSION)).isNull(); - assertThat(mDataStore.getProperty(Config.CONTENT_URL)).isNull(); - assertThat(mDataStore.getProperty(Config.METADATA_URL)).isNull(); } private void assertInstallSuccessful(String version) { assertThat(mDataStore.getProperty(Config.VERSION)).isEqualTo(version); - assertThat(mDataStore.getProperty(Config.CONTENT_URL)) - .isEqualTo(mDataStore.getProperty(Config.CONTENT_URL_PENDING)); - assertThat(mDataStore.getProperty(Config.METADATA_URL)) - .isEqualTo(mDataStore.getProperty(Config.METADATA_URL_PENDING)); } private Intent makeDownloadCompleteIntent(long downloadId) { @@ -371,110 +365,51 @@ public class CertificateTransparencyDownloaderTest { .putExtra(DownloadManager.EXTRA_DOWNLOAD_ID, downloadId); } - private long prepareDownloadId(String url) { - long downloadId = mNextDownloadId++; - when(mDownloadHelper.startDownload(url)).thenReturn(downloadId); - return downloadId; + private void prepareDataStore() { + mDataStore.load(); + mDataStore.setProperty(Config.CONTENT_URL, Config.URL_LOG_LIST); + mDataStore.setProperty(Config.METADATA_URL, Config.URL_SIGNATURE); + mDataStore.setProperty(Config.PUBLIC_KEY_URL, Config.URL_PUBLIC_KEY); } - private long preparePublicKeyDownload(String url) { - long downloadId = prepareDownloadId(url); - mDataStore.setProperty(Config.PUBLIC_KEY_URL_PENDING, url); - return downloadId; + private void prepareDownloadManager() { + when(mDownloadManager.enqueue(any(Request.class))) + .thenAnswer(invocation -> mNextDownloadId++); } - private long prepareMetadataDownload(String url) { - long downloadId = prepareDownloadId(url); - mDataStore.setProperty(Config.METADATA_URL_PENDING, url); - return downloadId; - } - - private long prepareContentDownload(String url) { - long downloadId = prepareDownloadId(url); - mDataStore.setProperty(Config.CONTENT_URL_PENDING, url); - return downloadId; - } - - private long prepareSuccessfulDownload(String propertyKey) { - long downloadId = mNextDownloadId++; - mDataStore.setPropertyLong(propertyKey, downloadId); - when(mDownloadHelper.getDownloadStatus(downloadId)) - .thenReturn(makeSuccessfulDownloadStatus(downloadId)); - return downloadId; - } - - private long prepareSuccessfulDownload(String propertyKey, File file) { - long downloadId = prepareSuccessfulDownload(propertyKey); - when(mDownloadHelper.getUri(downloadId)).thenReturn(Uri.fromFile(file)); - return downloadId; - } - - private long prepareSuccessfulPublicKeyDownload(File file) { - long downloadId = prepareSuccessfulDownload(Config.PUBLIC_KEY_URL_KEY, file); - mDataStore.setProperty( - Config.METADATA_URL_PENDING, "http://public-key-was-downloaded-here.org"); - return downloadId; - } - - private long prepareSuccessfulMetadataDownload(File file) { - long downloadId = prepareSuccessfulDownload(Config.METADATA_URL_KEY, file); - mDataStore.setProperty( - Config.METADATA_URL_PENDING, "http://metadata-was-downloaded-here.org"); - return downloadId; - } - - private long prepareSuccessfulContentDownload(File file) { - long downloadId = prepareSuccessfulDownload(Config.CONTENT_URL_KEY, file); - mDataStore.setProperty( - Config.CONTENT_URL_PENDING, "http://content-was-downloaded-here.org"); - return downloadId; + private Cursor makeSuccessfulDownloadCursor() { + MatrixCursor cursor = + new MatrixCursor( + new String[] { + DownloadManager.COLUMN_STATUS, DownloadManager.COLUMN_REASON + }); + cursor.addRow(new Object[] {DownloadManager.STATUS_SUCCESSFUL, -1}); + return cursor; } private void setSuccessfulDownload(long downloadId, File file) { - when(mDownloadHelper.getDownloadStatus(downloadId)) - .thenReturn(makeSuccessfulDownloadStatus(downloadId)); - when(mDownloadHelper.getUri(downloadId)).thenReturn(Uri.fromFile(file)); + when(mDownloadManager.query(any(Query.class))).thenReturn(makeSuccessfulDownloadCursor()); + when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(Uri.fromFile(file)); } - private long prepareFailedDownload(String propertyKey, int... downloadManagerErrors) { - long downloadId = mNextDownloadId++; - mDataStore.setPropertyLong(propertyKey, downloadId); - DownloadStatus firstError = - DownloadStatus.builder() - .setDownloadId(downloadId) - .setStatus(DownloadManager.STATUS_FAILED) - .setReason(downloadManagerErrors[0]) - .build(); - DownloadStatus[] otherErrors = new DownloadStatus[downloadManagerErrors.length - 1]; + private Cursor makeFailedDownloadCursor(int error) { + MatrixCursor cursor = + new MatrixCursor( + new String[] { + DownloadManager.COLUMN_STATUS, DownloadManager.COLUMN_REASON + }); + cursor.addRow(new Object[] {DownloadManager.STATUS_FAILED, error}); + return cursor; + } + + private void setFailedDownload(long downloadId, int... downloadManagerErrors) { + Cursor first = makeFailedDownloadCursor(downloadManagerErrors[0]); + Cursor[] others = new Cursor[downloadManagerErrors.length - 1]; for (int i = 1; i < downloadManagerErrors.length; i++) { - otherErrors[i - 1] = - DownloadStatus.builder() - .setDownloadId(downloadId) - .setStatus(DownloadManager.STATUS_FAILED) - .setReason(downloadManagerErrors[i]) - .build(); + others[i - 1] = makeFailedDownloadCursor(downloadManagerErrors[i]); } - when(mDownloadHelper.getDownloadStatus(downloadId)).thenReturn(firstError, otherErrors); - return downloadId; - } - - private long prepareFailedPublicKeyDownload(int... downloadManagerErrors) { - return prepareFailedDownload(Config.PUBLIC_KEY_URL_KEY, downloadManagerErrors); - } - - private long prepareFailedMetadataDownload(int... downloadManagerErrors) { - return prepareFailedDownload(Config.METADATA_URL_KEY, downloadManagerErrors); - } - - private long prepareFailedContentDownload(int... downloadManagerErrors) { - return prepareFailedDownload(Config.CONTENT_URL_KEY, downloadManagerErrors); - } - - private DownloadStatus makeSuccessfulDownloadStatus(long downloadId) { - return DownloadStatus.builder() - .setDownloadId(downloadId) - .setStatus(DownloadManager.STATUS_SUCCESSFUL) - .build(); + when(mDownloadManager.query(any())).thenReturn(first, others); + when(mDownloadManager.getUriForDownloadedFile(downloadId)).thenReturn(null); } private File writePublicKeyToFile(PublicKey publicKey)