diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index b871a4239..e8febd20c 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -37,7 +37,7 @@ -keep class org.codehaus.** { *; } -keepclassmembers public final enum org.codehaus.jackson.annotate.JsonAutoDetect$Visibility { public static final org.codehaus.jackson.annotate.JsonAutoDetect$Visibility *; } --keep public class your.class.** { +-keep public class org.fdroid.** { *; } diff --git a/app/src/androidTest/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java b/app/src/androidTest/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java index e007f0cd7..1bf8a4c68 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/updater/SwapRepoEmulatorTest.java @@ -4,12 +4,15 @@ import android.content.Context; import android.content.Intent; import android.content.pm.ApplicationInfo; import android.content.pm.ResolveInfo; +import android.net.Uri; import android.os.Looper; import androidx.test.platform.app.InstrumentationRegistry; import androidx.test.filters.LargeTest; import android.text.TextUtils; import android.util.Log; +import org.fdroid.download.Downloader; +import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.FDroidApp; import org.fdroid.fdroid.Hasher; import org.fdroid.fdroid.Preferences; @@ -18,6 +21,14 @@ import org.fdroid.fdroid.nearby.LocalHTTPD; import org.fdroid.fdroid.nearby.LocalRepoKeyStore; import org.fdroid.fdroid.nearby.LocalRepoManager; import org.fdroid.fdroid.nearby.LocalRepoService; +import org.fdroid.fdroid.net.DownloaderFactory; +import org.fdroid.index.IndexParser; +import org.fdroid.index.IndexParserKt; +import org.fdroid.index.v1.IndexV1; +import org.fdroid.index.v1.IndexV1UpdaterKt; +import org.fdroid.index.v1.IndexV1Verifier; +import org.fdroid.index.v1.PackageV1; +import org.fdroid.index.v2.FileV2; import org.junit.Ignore; import org.junit.Test; @@ -27,14 +38,18 @@ import java.net.Socket; import java.security.cert.Certificate; import java.util.HashSet; import java.util.List; +import java.util.Locale; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import kotlin.Pair; + @LargeTest public class SwapRepoEmulatorTest { public static final String TAG = "SwapRepoEmulatorTest"; @@ -44,8 +59,7 @@ public class SwapRepoEmulatorTest { */ @Ignore @Test - public void testSwap() - throws IOException, LocalRepoKeyStore.InitException, InterruptedException { + public void testSwap() throws Exception { Looper.prepare(); LocalHTTPD localHttpd = null; try { @@ -54,15 +68,16 @@ public class SwapRepoEmulatorTest { Preferences.setupForTests(context); FDroidApp.initWifiSettings(); - assertNull(FDroidApp.repo.getAddress()); + assertNull(FDroidApp.repo); final CountDownLatch latch = new CountDownLatch(1); new Thread() { @Override public void run() { - while (FDroidApp.repo.getAddress() == null) { + while (FDroidApp.repo == null) { try { - Log.i(TAG, "Waiting for IP address... " + FDroidApp.repo.getAddress()); + String address = FDroidApp.repo == null ? null : FDroidApp.repo.getAddress(); + Log.i(TAG, "Waiting for IP address... " + address); Thread.sleep(1000); } catch (InterruptedException e) { // ignored @@ -91,54 +106,45 @@ public class SwapRepoEmulatorTest { LocalRepoKeyStore localRepoKeyStore = LocalRepoKeyStore.get(context); Certificate localCert = localRepoKeyStore.getCertificate(); + String fingerprint = Utils.calcFingerprint(localCert).toLowerCase(Locale.ROOT); String signingCert = Hasher.hex(localCert); assertFalse(TextUtils.isEmpty(signingCert)); - assertFalse(TextUtils.isEmpty(Utils.calcFingerprint(localCert))); + assertFalse(TextUtils.isEmpty(fingerprint)); - //Repo repoToDelete = RepoProvider.Helper.findByAddress(context, FDroidApp.repo.getAddress()); - //while (repoToDelete != null) { - // Log.d(TAG, "Removing old test swap repo matching this one: " + repoToDelete.address); - // RepoProvider.Helper.remove(context, repoToDelete.getId()); - // repoToDelete = RepoProvider.Helper.findByAddress(context, FDroidApp.repo.getAddress()); - //} - // - //ContentValues values = new ContentValues(4); - //values.put(Schema.RepoTable.Cols.SIGNING_CERT, signingCert); - //values.put(Schema.RepoTable.Cols.ADDRESS, FDroidApp.repo.getAddress()); - //values.put(Schema.RepoTable.Cols.NAME, ""); - //values.put(Schema.RepoTable.Cols.IS_SWAP, true); - //final String lastEtag = UUID.randomUUID().toString(); - //values.put(Schema.RepoTable.Cols.LAST_ETAG, lastEtag); - //RepoProvider.Helper.insert(context, values); - //Repo repo = RepoProvider.Helper.findByAddress(context, FDroidApp.repo.getAddress()); - //assertTrue(repo.isSwap); - //assertNotEquals(-1, repo.getId()); - //assertEquals(lastEtag, repo.lastetag); - //assertNull(repo.lastUpdated); - // assertTrue(isPortInUse(FDroidApp.ipAddressString, FDroidApp.port)); - //Thread.sleep(100); - //IndexUpdater updater = new IndexUpdater(context, repo); - //updater.update(); - //assertTrue(updater.hasChanged()); - // - //repo = RepoProvider.Helper.findByAddress(context, FDroidApp.repo.getAddress()); - //final Date lastUpdated = repo.lastUpdated; - //assertTrue("repo lastUpdated should be updated", new Date(2019, 5, 13).compareTo(repo.lastUpdated) > 0); - // - //App app = AppProvider.Helper.findSpecificApp(context.getContentResolver(), - // context.getPackageName(), repo.getId()); - //assertEquals(context.getPackageName(), app.packageName); - // - //List apks = ApkProvider.Helper.findByRepo(context, repo, Schema.ApkTable.Cols.ALL); - //assertEquals(1, apks.size()); - //for (Apk apk : apks) { - // Log.i(TAG, "Apk: " + apk); - // assertEquals(context.getPackageName(), apk.packageName); - // assertEquals(BuildConfig.VERSION_NAME, apk.versionName); - // assertEquals(BuildConfig.VERSION_CODE, apk.versionCode); - // assertEquals(app.repoId, apk.repoId); - //} + Thread.sleep(100); + + Uri uri = Uri.parse(FDroidApp.repo.getAddress()) + .buildUpon() + .appendPath(IndexV1UpdaterKt.SIGNED_FILE_NAME) + .build(); + FileV2 indexFile = FileV2.fromPath("/" + IndexV1UpdaterKt.SIGNED_FILE_NAME); + File swapJarFile = File.createTempFile("swap", "", context.getCacheDir()); + Downloader downloader = + DownloaderFactory.INSTANCE.createWithTryFirstMirror(FDroidApp.repo, uri, indexFile, swapJarFile); + downloader.download(); + IndexV1Verifier verifier = new IndexV1Verifier(swapJarFile, null, fingerprint); + Pair pair = verifier.getStreamAndVerify(inputStream -> + IndexParserKt.parseV1(IndexParser.INSTANCE, inputStream) + ); + assertEquals(signingCert, pair.getFirst()); + IndexV1 indexV1 = pair.getSecond(); + assertEquals(1, indexV1.getApps().size()); + assertEquals(context.getPackageName(), indexV1.getApps().get(0).getPackageName()); + long firstTimestamp = indexV1.getRepo().getTimestamp(); + + assertEquals(1, indexV1.getPackages().size()); + List apks = indexV1.getPackages().get(context.getPackageName()); + assertNotNull(apks); + assertEquals(1, apks.size()); + for (PackageV1 apk : apks) { + Log.i(TAG, "Apk: " + apk); + assertNotNull(apk.getVersionCode()); + long versionCode = apk.getVersionCode(); + assertEquals(context.getPackageName(), apk.getPackageName()); + assertEquals(BuildConfig.VERSION_NAME, apk.getVersionName()); + assertEquals(BuildConfig.VERSION_CODE, versionCode); + } Intent mainIntent = new Intent(Intent.ACTION_MAIN, null); mainIntent.addCategory(Intent.CATEGORY_LAUNCHER); @@ -152,22 +158,25 @@ public class SwapRepoEmulatorTest { } LocalRepoService.runProcess(context, packageNames.toArray(new String[0])); - //updater = new IndexUpdater(context, repo); - //updater.update(); - //assertTrue(updater.hasChanged()); - //assertTrue("repo lastUpdated should be updated", lastUpdated.compareTo(repo.lastUpdated) < 0); - // - //for (String packageName : packageNames) { - // assertNotNull(ApkProvider.Helper.findByPackageName(context, packageName)); - //} + swapJarFile = File.createTempFile("swap", "", context.getCacheDir()); + downloader = + DownloaderFactory.INSTANCE.createWithTryFirstMirror(FDroidApp.repo, uri, indexFile, swapJarFile); + downloader.download(); + verifier = new IndexV1Verifier(swapJarFile, null, fingerprint); + pair = verifier.getStreamAndVerify(inputStream -> + IndexParserKt.parseV1(IndexParser.INSTANCE, inputStream) + ); + indexV1 = pair.getSecond(); + assertTrue(firstTimestamp < indexV1.getRepo().getTimestamp()); + for (String packageName : packageNames) { + assertNotNull(indexV1.getPackages().get(packageName)); + } } finally { if (localHttpd != null) { localHttpd.stop(); } } - if (localHttpd != null) { - assertFalse(localHttpd.isAlive()); - } + assertFalse(localHttpd.isAlive()); } private boolean isPortInUse(String host, int port) {