diff --git a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java index 97b82c773..5e702d957 100644 --- a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java +++ b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java @@ -167,20 +167,19 @@ public class IndexV1Updater extends RepoUpdater { return; } - /* TODO - if (timestamp < repo.timestamp) { - throw new RepoUpdater.UpdateException(repo, "index.jar is older that current index! " - + timestamp + " < " + repo.timestamp); - } - */ - // TODO handle maxage, convert to "expiration" Date instance + long timestamp = (Long) repoMap.get("timestamp") / 1000; + + if (repo.timestamp > timestamp) { + throw new RepoUpdater.UpdateException(repo, "index.jar is older that current index! " + + timestamp + " < " + repo.timestamp); + } X509Certificate certificate = getSigningCertFromJar(indexEntry); verifySigningCertificate(certificate); Utils.debugLog(TAG, "Repo signature verified, saving app metadata to database."); // timestamp is absolutely required - repo.timestamp = (Long) repoMap.get("timestamp"); + repo.timestamp = timestamp; // below are optional, can be null repo.name = getStringRepoValue(repoMap, "name"); repo.icon = getStringRepoValue(repoMap, "icon"); diff --git a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java index 9967a3113..1bc261142 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java @@ -27,7 +27,11 @@ import java.util.jar.JarFile; import static org.hamcrest.CoreMatchers.containsString; import static org.hamcrest.core.IsNot.not; -import static org.junit.Assert.*; +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.fail; @Config(constants = BuildConfig.class, sdk = 24) @RunWith(RobolectricTestRunner.class) @@ -41,6 +45,7 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { public void testIndexV1Processing() throws IOException, RepoUpdater.UpdateException { Preferences.setup(context); Repo repo = MultiRepoUpdaterTest.createRepo("Testy", TESTY_JAR, context, TESTY_CERT); + repo.timestamp = 1481222110; IndexV1Updater updater = new IndexV1Updater(context, repo); JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true); Log.i(TAG, "jarFile " + jarFile); @@ -63,6 +68,19 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { getClass().getResourceAsStream("foo"); } + @Test(expected = RepoUpdater.UpdateException.class) + public void testIndexV1WithOldTimestamp() throws IOException, RepoUpdater.UpdateException { + Repo repo = MultiRepoUpdaterTest.createRepo("Testy", TESTY_JAR, context, TESTY_CERT); + repo.timestamp = System.currentTimeMillis() / 1000; + IndexV1Updater updater = new IndexV1Updater(context, repo); + JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true); + JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexV1Updater.DATA_FILE_NAME); + InputStream indexInputStream = jarFile.getInputStream(indexEntry); + updater.processIndexV1(indexInputStream, indexEntry, "fakeEtag"); + fail(); // it should never reach here, it should throw a SigningException + getClass().getResourceAsStream("foo"); + } + @Test(expected = RepoUpdater.SigningException.class) public void testIndexV1WithBadTestyJarNoManifest() throws IOException, RepoUpdater.UpdateException { testBadTestyJar("testy.at.or.at_no-MANIFEST.MF_index-v1.jar");