Simplify the Android CT properties
Since we are moving away from runtime flags, the CT URLs for the log list, signature, and public key will be hardcoded. I took the occasion to simplify the logic for handling the Android CT properties and removed the various "_PENDING" properties. They were making everything much harder to follow. Flag: com.android.net.ct.flags.certificate_transparency_job Bug: 319829948 Test: NetworkSecurityUnitTests Change-Id: I74bb946eccb5f376ee161ace2f151bf6ea1bdcff
This commit is contained in:
parent
dd87fb0d06
commit
9190aed0f8
5 changed files with 190 additions and 221 deletions
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
Loading…
Reference in a new issue