From 1deec1c9b3e72bfc0fe3b9f3651291b6850f8fdb Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner <hans@eds.org> Date: Wed, 2 Jan 2019 17:14:34 +0100 Subject: [PATCH] sanitize all packageNames from the index This is insurance to make sure that packageNames are not abused for exploiting F-Droid. The database queries already use SQL Prepared Statements, but who know what else might be exploitable. fdroid/fdroidclient#1588 --- .../main/java/org/fdroid/fdroid/data/Apk.java | 14 ++++++ .../main/java/org/fdroid/fdroid/data/App.java | 13 ++++++ .../fdroid/fdroid/data/RepoXMLHandler.java | 11 +++-- .../fdroid/data/RepoXMLHandlerTest.java | 40 ++++++++++++++++-- .../fdroid/updater/IndexV1UpdaterTest.java | 21 +++++++++ .../simpleIndexWithCorruptedPackageName.xml | 4 ++ ...r.at_corrupt_app_package_name_index-v1.jar | Bin 0 -> 4326 bytes ...at.or.at_corrupt_package_name_index-v1.jar | Bin 0 -> 4325 bytes 8 files changed, 96 insertions(+), 7 deletions(-) create mode 100644 app/src/test/resources/simpleIndexWithCorruptedPackageName.xml create mode 100644 app/src/test/resources/testy.at.or.at_corrupt_app_package_name_index-v1.jar create mode 100644 app/src/test/resources/testy.at.or.at_corrupt_package_name_index-v1.jar diff --git a/app/src/main/java/org/fdroid/fdroid/data/Apk.java b/app/src/main/java/org/fdroid/fdroid/data/Apk.java index 78b9e1872..66a815fff 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -460,6 +460,20 @@ public class Apk extends ValueObject implements Comparable<Apk>, Parcelable { return null; } + /** + * Set the Package Name property while ensuring it is sanitized. + */ + @JsonProperty("packageName") + @SuppressWarnings("unused") + void setPackageName(String packageName) { + if (Utils.isSafePackageName(packageName)) { + this.packageName = packageName; + } else { + throw new IllegalArgumentException("Repo index package entry includes unsafe packageName: '" + + packageName + "'"); + } + } + @JsonProperty("uses-permission") @SuppressWarnings("unused") private void setUsesPermission(Object[][] permissions) { diff --git a/app/src/main/java/org/fdroid/fdroid/data/App.java b/app/src/main/java/org/fdroid/fdroid/data/App.java index 16d56d278..b2ea39190 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -406,6 +406,19 @@ public class App extends ValueObject implements Comparable<App>, Parcelable { this.description = formatDescription(description); } + /** + * Set the Package Name property while ensuring it is sanitized. + */ + @JsonProperty("packageName") + void setPackageName(String packageName) { + if (Utils.isSafePackageName(packageName)) { + this.packageName = packageName; + } else { + throw new IllegalArgumentException("Repo index app entry includes unsafe packageName: '" + + packageName + "'"); + } + } + /** * Parses the {@code localized} block in the incoming index metadata, * choosing the best match in terms of locale/language while filling as diff --git a/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java b/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java index 1971da4fc..1da274f63 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java +++ b/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java @@ -22,7 +22,6 @@ package org.fdroid.fdroid.data; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import org.fdroid.fdroid.IndexUpdater; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Schema.ApkTable; import org.xml.sax.Attributes; @@ -330,8 +329,8 @@ public class RepoXMLHandler extends DefaultHandler { } @Override - public void startElement(String uri, String localName, String qName, - Attributes attributes) throws SAXException { + public void startElement(String uri, String localName, String qName, Attributes attributes) + throws SAXException { super.startElement(uri, localName, qName, attributes); if ("repo".equals(localName)) { @@ -353,7 +352,11 @@ public class RepoXMLHandler extends DefaultHandler { } else if ("application".equals(localName) && curapp == null) { curapp = new App(); curapp.repoId = repo.getId(); - curapp.packageName = attributes.getValue("", "id"); + try { + curapp.setPackageName(attributes.getValue("", "id")); + } catch (IllegalArgumentException e) { + throw new SAXException(e); + } // To appease the NON NULL constraint in the DB. Usually there is a description, and it // is quite difficult to get an app to _not_ have a description when using fdroidserver. diff --git a/app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java b/app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java index fa568a5a5..e77b53bfd 100644 --- a/app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java @@ -27,12 +27,18 @@ import android.text.TextUtils; import android.util.Log; import org.apache.commons.io.FileUtils; import org.fdroid.fdroid.BuildConfig; +import org.fdroid.fdroid.mock.MockRepo; import org.fdroid.fdroid.mock.RepoDetails; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; import org.robolectric.annotation.Config; +import org.xml.sax.InputSource; +import org.xml.sax.XMLReader; +import javax.xml.parsers.SAXParser; +import javax.xml.parsers.SAXParserFactory; +import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -48,6 +54,7 @@ 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 static org.junit.Assert.fail; @Config(constants = BuildConfig.class) @RunWith(RobolectricTestRunner.class) @@ -124,6 +131,33 @@ public class RepoXMLHandlerTest { }); } + @Test(expected = IllegalArgumentException.class) + public void testSimpleIndexWithCorruptedPackageName() throws Throwable { + Repo expectedRepo = new Repo(); + expectedRepo.name = "F-Droid"; + expectedRepo.signingCertificate = "308201ee30820157a0030201020204300d845b300d06092a864886f70d01010b0500302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e301e170d3134303432373030303633315a170d3431303931323030303633315a302a3110300e060355040b1307462d44726f6964311630140603550403130d70616c6174736368696e6b656e30819f300d06092a864886f70d010101050003818d0030818902818100a439472e4b6d01141bfc94ecfe131c7c728fdda670bb14c57ca60bd1c38a8b8bc0879d22a0a2d0bc0d6fdd4cb98d1d607c2caefbe250a0bd0322aedeb365caf9b236992fac13e6675d3184a6c7c6f07f73410209e399a9da8d5d7512bbd870508eebacff8b57c3852457419434d34701ccbf692267cbc3f42f1c5d1e23762d790203010001a321301f301d0603551d0e041604140b1840691dab909746fde4bfe28207d1cae15786300d06092a864886f70d01010b05000381810062424c928ffd1b6fd419b44daafef01ca982e09341f7077fb865905087aeac882534b3bd679b51fdfb98892cef38b63131c567ed26c9d5d9163afc775ac98ad88c405d211d6187bde0b0d236381cc574ba06ef9080721a92ae5a103a7301b2c397eecc141cc850dd3e123813ebc41c59d31ddbcb6e984168280c53272f6a442b"; // NOCHECKSTYLE LineLength + expectedRepo.description = "The official repository of the F-Droid client. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitorious.org/f-droid."; // NOCHECKSTYLE LineLength + expectedRepo.timestamp = 1398733213; + + InputStream inputStream = getClass().getClassLoader() + .getResourceAsStream("simpleIndexWithCorruptedPackageName.xml"); + SAXParserFactory factory = SAXParserFactory.newInstance(); + factory.setNamespaceAware(true); + SAXParser parser = factory.newSAXParser(); + XMLReader reader = parser.getXMLReader(); + RepoDetails repoDetails = new RepoDetails(); + MockRepo mockRepo = new MockRepo(100, Repo.PUSH_REQUEST_IGNORE); + RepoXMLHandler handler = new RepoXMLHandler(mockRepo, repoDetails); + reader.setContentHandler(handler); + InputSource is = new InputSource(new BufferedInputStream(inputStream)); + try { + reader.parse(is); + } catch (org.xml.sax.SAXException e) { + throw e.getCause(); + } + fail(); + } + @Test public void testPushRequestsRepoIgnore() { Repo expectedRepo = new Repo(); @@ -188,17 +222,17 @@ public class RepoXMLHandlerTest { repoPushRequest = new RepoPushRequest("install", "--", "123"); assertEquals(repoPushRequest.request, "install"); assertEquals(repoPushRequest.packageName, null); - assertEquals(repoPushRequest.versionCode, new Integer(123)); + assertEquals(repoPushRequest.versionCode, Integer.valueOf(123)); repoPushRequest = new RepoPushRequest("uninstall", "Robert'); DROP TABLE Students; --", "123"); assertEquals(repoPushRequest.request, "uninstall"); assertEquals(repoPushRequest.packageName, null); - assertEquals(repoPushRequest.versionCode, new Integer(123)); + assertEquals(repoPushRequest.versionCode, Integer.valueOf(123)); repoPushRequest = new RepoPushRequest("badrquest", "asdfasdfasdf", "123"); assertEquals(repoPushRequest.request, null); assertEquals(repoPushRequest.packageName, "asdfasdfasdf"); - assertEquals(repoPushRequest.versionCode, new Integer(123)); + assertEquals(repoPushRequest.versionCode, Integer.valueOf(123)); } @Test 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 c7319b3c0..cc9d6394d 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java @@ -8,6 +8,7 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.JsonMappingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.ObjectReader; import org.apache.commons.io.IOUtils; @@ -159,6 +160,26 @@ public class IndexV1UpdaterTest extends FDroidProviderTest { getClass().getResourceAsStream("foo"); } + @Test(expected = IllegalArgumentException.class) + public void testIndexV1WithCorruptAppPackageName() throws Throwable { + try { + testBadTestyJar("testy.at.or.at_corrupt_app_package_name_index-v1.jar"); + } catch (JsonMappingException e) { + throw e.getCause(); + } + fail(); + } + + @Test(expected = IllegalArgumentException.class) + public void testIndexV1WithCorruptPackageName() throws Throwable { + try { + testBadTestyJar("testy.at.or.at_corrupt_package_name_index-v1.jar"); + } catch (JsonMappingException e) { + throw e.getCause(); + } + fail(); + } + @Test(expected = IndexUpdater.SigningException.class) public void testIndexV1WithBadTestyJarNoManifest() throws IOException, IndexUpdater.UpdateException { testBadTestyJar("testy.at.or.at_no-MANIFEST.MF_index-v1.jar"); diff --git a/app/src/test/resources/simpleIndexWithCorruptedPackageName.xml b/app/src/test/resources/simpleIndexWithCorruptedPackageName.xml new file mode 100644 index 000000000..7cd26d89f --- /dev/null +++ b/app/src/test/resources/simpleIndexWithCorruptedPackageName.xml @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?><fdroid><repo icon="blah.png" maxage="14" name="Android-Nexus-7-20139453 on UNSET" pubkey="308202da308201c2a00302010202080eb08c796fec91aa300d06092a864886f70d0101050500302d3111300f060355040a0c084b6572706c61707031183016060355040b0c0f477561726469616e50726f6a656374301e170d3134313030333135303631325a170d3135313030333135303631325a302d3111300f060355040a0c084b6572706c61707031183016060355040b0c0f477561726469616e50726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a0282010100c7ab44b130be5c00eedcc3625462f6f6ac26e502641cd641f3e30cbb0ff1ba325158611e7fc2448a35b6a6df30dc6e23602cf6909448befcf11e2fe486b580f1e76fe5887d159050d00afd2c4079f6538896bb200627f4b3e874f011ce5df0fef5d150fcb0b377b531254e436eaf4083ea72fe3b8c3ef450789fa858f2be8f6c5335bb326aff3dda689fbc7b5ba98dea53651dbea7452c38d294985ac5dd8a9e491a695de92c706d682d6911411fcaef3b0a08a030fe8a84e47acaab0b7edcda9d190ce39e810b79b1d8732eca22b15f0d048c8d6f00503a7ee81ab6e08919ff465883432304d95238b95e95c5f74e0a421809e2a6a85825aed680e0d6939e8f0203010001300d06092a864886f70d010105050003820101006d17aad3271b8b2c299dbdb7b1182849b0d5ddb9f1016dcb3487ae0db02b6be503344c7d066e2050bcd01d411b5ee78c7ed450f0ff9da5ce228f774cbf41240361df53d9c6078159d16f4d34379ab7dedf6186489397c83b44b964251a2ebb42b7c4689a521271b1056d3b5a5fa8f28ba64fb8ce5e2226c33c45d27ba3f632dc266c12abf582b8438c2abcf3eae9de9f31152b4158ace0ef33435c20eb809f1b3988131db6e5a1442f2617c3491d9565fedb3e320e8df4236200d3bd265e47934aa578f84d0d1a5efeb49b39907e876452c46996d0feff9404b41aa5631b4482175d843d5512ded45e12a514690646492191e7add434afce63dbff8f0b03ec0c" timestamp="1412696461"><description>A local FDroid repo generated from apps installed on Android-Nexus-7-20139453</description></repo><application id="Robert'); DROP TABLE Students; --"><id>Robert'); DROP TABLE Students; --</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>Firefox</name><summary>(installed by null)</summary><desc><p>(installed by null, first installed on Sat Sep 27 23:47:05 EDT 2014, last updated on Sat Sep 27 23:47:05 EDT 2014)</p></desc><icon>org.mozilla.firefox_2014092317.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>32.0.3</marketversion><marketvercode>2014092317</marketvercode><package><version>32.0.3</version><versioncode>2014092317</versioncode><apkname>org.mozilla.firefox_2014092317.apk</apkname><hash type="sha256">4b4e642b71acfe217758bb12ae7dec7fe46027ee732f4a9775ef7a4107deb5fb</hash><sig>20e61aee1b748061ec3b0ab1bbe5bac4</sig><size>30831633</size><sdkver>9</sdkver><added>2014-09-27</added><features/><permissions>RECEIVE_BOOT_COMPLETED,org.mozilla.firefox.permission.PER_ANDROID_PACKAGE,GET_ACCOUNTS,ACCESS_NETWORK_STATE,MANAGE_ACCOUNTS,USE_CREDENTIALS,AUTHENTICATE_ACCOUNTS,WRITE_SYNC_SETTINGS,WRITE_SETTINGS,READ_SYNC_STATS,READ_SYNC_SETTINGS,org.mozilla.firefox_fxaccount.permission.PER_ACCOUNT_TYPE,org.mozilla.firefox_sync.permission.PER_ACCOUNT_TYPE,ACCESS_FINE_LOCATION,INTERNET,WRITE_EXTERNAL_STORAGE,com.android.launcher.permission.INSTALL_SHORTCUT,com.android.launcher.permission.UNINSTALL_SHORTCUT,com.android.browser.permission.READ_HISTORY_BOOKMARKS,WAKE_LOCK,VIBRATE,org.mozilla.firefox.permissions.PASSWORD_PROVIDER,org.mozilla.firefox.permissions.BROWSER_PROVIDER,org.mozilla.firefox.permissions.FORMHISTORY_PROVIDER,NFC,RECORD_AUDIO,CAMERA,READ_EXTERNAL_STORAGE</permissions></package></application><application id="com.koushikdutta.superuser"><id>com.koushikdutta.superuser</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>Superuser</name><summary>(installed by null)</summary><desc><p>(installed by null, first installed on Sat Sep 27 23:23:22 EDT 2014, last updated on Sat Sep 27 23:23:22 EDT 2014)</p></desc><icon>com.koushikdutta.superuser_1030.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>1.0.3.0</marketversion><marketvercode>1030</marketvercode><package><version>1.0.3.0</version><versioncode>1030</versioncode><apkname>com.koushikdutta.superuser_1030.apk</apkname><hash type="sha256">8bbe1c0aa307a0c689d0b97ea5123f6d74d42bb9f91cbeaac2583b23de3a77ab</hash><sig>9af2c721bb87900f7e386d7a3716a7a6</sig><size>2944602</size><sdkver>8</sdkver><added>2014-09-27</added><features/><permissions>ACCESS_SUPERUSER,RECEIVE_BOOT_COMPLETED</permissions></package></application><application id="info.guardianproject.courier"><id>info.guardianproject.courier</id><added>2014-10-03</added><lastupdated>2014-10-03</lastupdated><name>Courier</name><summary>Courier is a mobile RSS news reader with</summary><desc><p>Courier is a mobile RSS news reader with enhanced security features, offline reading and sharing capability. +(installed by F-Droid, first installed on Fri Oct 03 09:12:04 EDT 2014, last updated on Fri Oct 03 09:12:04 EDT 2014)</p></desc><icon>info.guardianproject.courier_15.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>0.1.9</marketversion><marketvercode>15</marketvercode><package><version>0.1.9</version><versioncode>15</versioncode><apkname>info.guardianproject.courier_15.apk</apkname><hash type="sha256">bf6566da1f90831887f5bf5605f8d816b1f7f694969459dec599b8bc01a827d3</hash><sig>d70ac6a02b53ebdd1354ea7af7b9ceee</sig><size>16484753</size><sdkver>9</sdkver><added>2014-10-03</added><features/><permissions>INTERNET,ACCESS_NETWORK_STATE,WRITE_EXTERNAL_STORAGE,ACCESS_WIFI_STATE,BLUETOOTH,BLUETOOTH_ADMIN,VIBRATE,READ_EXTERNAL_STORAGE</permissions></package></application><application id="org.adaway"><id>org.adaway</id><added>2014-09-29</added><lastupdated>2014-09-29</lastupdated><name>AdAway</name><summary>(installed by F-Droid)</summary><desc><p>(installed by F-Droid, first installed on Mon Sep 29 08:31:13 EDT 2014, last updated on Mon Sep 29 08:31:13 EDT 2014)</p></desc><icon>org.adaway_50.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>2.9.1</marketversion><marketvercode>50</marketvercode><package><version>2.9.1</version><versioncode>50</versioncode><apkname>org.adaway_50.apk</apkname><hash type="sha256">c9f4fcdca5e47abecfe8bc529ba6299f242fce1d5c87e50b8a36ace82d4fc259</hash><sig>5292cd7cf993d06d6f6741117b8400fc</sig><size>2816877</size><sdkver>7</sdkver><added>2014-09-29</added><features/><permissions>INTERNET,ACCESS_NETWORK_STATE,RECEIVE_BOOT_COMPLETED,WRITE_EXTERNAL_STORAGE,WAKE_LOCK,ACCESS_SUPERUSER,READ_EXTERNAL_STORAGE</permissions></package></application><application id="info.guardianproject.gilga"><id>info.guardianproject.gilga</id><added>2014-10-04</added><lastupdated>2014-10-07</lastupdated><name>Gilgamesh</name><summary>(installed by F-Droid)</summary><desc><p>(installed by F-Droid, first installed on Sat Oct 04 14:59:10 EDT 2014, last updated on Tue Oct 07 09:49:14 EDT 2014)</p></desc><icon>info.guardianproject.gilga_2.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>0.0.2</marketversion><marketvercode>2</marketvercode><package><versioncode>2</versioncode><apkname>info.guardianproject.gilga_2.apk</apkname><hash type="sha256">1eac2e0043977dc8f31947f19852803207205887a5f01a1cbb8a5e477b3d82a9</hash><sig>6de574cd61a684bda38ba8e895dece7c</sig><size>30761</size><sdkver>14</sdkver><added>2014-10-04</added><features/><permissions>BLUETOOTH_ADMIN,BLUETOOTH,ACCESS_WIFI_STATE,CHANGE_WIFI_STATE,INTERNET</permissions></package></application><application id="com.google.zxing.client.android"><id>com.google.zxing.client.android</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>Barcode Scanner</name><summary>(installed by null)</summary><desc><p>(installed by null, first installed on Sat Sep 27 23:36:20 EDT 2014, last updated on Sat Sep 27 23:36:20 EDT 2014)</p></desc><icon>com.google.zxing.client.android_100.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>4.7.0</marketversion><marketvercode>100</marketvercode><package><version>4.7.0</version><versioncode>100</versioncode><apkname>com.google.zxing.client.android_100.apk</apkname><hash type="sha256">62dea7cf201d2e36725ad76b1525decb58b05dd9e4a032ed084c7a6c6d38da2c</hash><sig>c3bb49636af03e7c23a63724eb529ea9</sig><size>735678</size><sdkver>15</sdkver><added>2014-09-27</added><features/><permissions>CAMERA,INTERNET,VIBRATE,FLASHLIGHT,READ_CONTACTS,com.android.browser.permission.READ_HISTORY_BOOKMARKS,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,READ_EXTERNAL_STORAGE</permissions></package></application><application id="info.guardianproject.lildebi"><id>info.guardianproject.lildebi</id><added>2014-09-28</added><lastupdated>2014-09-28</lastupdated><name>Lil' Debi</name><summary>Want an easy Debian chroot running that </summary><desc><p>Want an easy Debian chroot running that you can trust? Install Lil’ Debi, and you can have a Debian install running with a single click of a button. It builds up a whole Debian chroot on your phone entirely using debootstrap. You choose the release, mirror, and size of the disk image, and away it goes. It could take up to an hour on a slow device, then its done. The entire package is built from source using publicly available, repeatable builds. It even validates every package using the official Debian repository keys, which are included in the app. +(installed by null, first installed on Sun Sep 28 00:39:09 EDT 2014, last updated on Sun Sep 28 00:39:09 EDT 2014)</p></desc><icon>info.guardianproject.lildebi_5100.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>0.5.1</marketversion><marketvercode>5100</marketvercode><package><version>0.5.1</version><versioncode>5100</versioncode><apkname>info.guardianproject.lildebi_5100.apk</apkname><hash type="sha256">7af667881af6107f3fe60d6973712506dbaf83710d383eb1c312fc75dae2e46a</hash><sig>b4964fd759edaa54e65bb476d0276880</sig><size>1569480</size><sdkver>8</sdkver><added>2014-09-28</added><features/><permissions>INTERNET,ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE,WAKE_LOCK,jackpal.androidterm.permission.RUN_SCRIPT</permissions></package></application><application id="de.danoeh.antennapod"><id>de.danoeh.antennapod</id><added>2014-10-03</added><lastupdated>2014-10-03</lastupdated><name>AntennaPod</name><summary>(installed by F-Droid)</summary><desc><p>(installed by F-Droid, first installed on Fri Oct 03 09:08:31 EDT 2014, last updated on Fri Oct 03 09:08:31 EDT 2014)</p></desc><icon>de.danoeh.antennapod_40.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>0.9.9.3</marketversion><marketvercode>40</marketvercode><package><version>0.9.9.3</version><versioncode>40</versioncode><apkname>de.danoeh.antennapod_40.apk</apkname><hash type="sha256">ea83cb81c03bc8b6c1fb6e61e7d0915abef8ca175789a5ac5add45c12f633ebd</hash><sig>3870fa89bfb5e13509ce5888800bc643</sig><size>2815685</size><sdkver>10</sdkver><added>2014-10-03</added><features/><permissions>INTERNET,WRITE_EXTERNAL_STORAGE,WAKE_LOCK,ACCESS_NETWORK_STATE,ACCESS_WIFI_STATE,RECEIVE_BOOT_COMPLETED,READ_EXTERNAL_STORAGE</permissions></package></application><application id="info.guardianproject.otr.app.im"><id>info.guardianproject.otr.app.im</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>ChatSecure</name><summary>(installed by F-Droid)</summary><desc><p>(installed by F-Droid, first installed on Sat Sep 27 23:42:00 EDT 2014, last updated on Sat Sep 27 23:42:00 EDT 2014)</p></desc><icon>info.guardianproject.otr.app.im_1403000.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>14.0.3</marketversion><marketvercode>1403000</marketvercode><package><version>14.0.3</version><versioncode>1403000</versioncode><apkname>info.guardianproject.otr.app.im_1403000.apk</apkname><hash type="sha256">46b0b26e2122a8bf937be259d6219ffe5bace7b2eda692b43a5f55fff2322e13</hash><sig>a0eeebb161f946e3516945fae8a92a3e</sig><size>11235852</size><sdkver>9</sdkver><added>2014-09-27</added><features/><permissions>info.guardianproject.otr.app.providers.imps.permission.READ_ONLY,info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY,WAKE_LOCK,VIBRATE,INTERNET,CHANGE_WIFI_MULTICAST_STATE,ACCESS_WIFI_STATE,ACCESS_NETWORK_STATE,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE,RECEIVE_BOOT_COMPLETED,info.guardianproject.otr.app.im.permission.IM_SERVICE,UPDATE_APP_OPS_STATS,GET_ACCOUNTS,MANAGE_ACCOUNTS,USE_CREDENTIALS,com.google.android.googleapps.permission.GOOGLE_AUTH</permissions></package></application><application id="org.torproject.android"><id>org.torproject.android</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>Orbot</name><summary>Orbot is a free proxy app that empowers </summary><desc><p>Orbot is a free proxy app that empowers other apps to use the internet more securely. Orbot uses Tor to encrypt your Internet traffic and then hides it by bouncing through a series of computers around the world. Tor is free software and an open network that helps you defend against a form of network surveillance that threatens personal freedom and privacy, confidential business activities and relationships, and state security known as traffic analysis. +(installed by null, first installed on Sat Sep 27 23:39:38 EDT 2014, last updated on Sat Sep 27 23:39:38 EDT 2014)</p></desc><icon>org.torproject.android_124.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>14.0.8.1</marketversion><marketvercode>124</marketvercode><package><version>14.0.8.1</version><versioncode>124</versioncode><apkname>org.torproject.android_124.apk</apkname><hash type="sha256">74daa523cd9e85722a9190dd95f3b839d69b7457ffcb9647ca6745824f6ef66d</hash><sig>8bd7e51b479aeba908ff46ada3305a29</sig><size>5548347</size><sdkver>9</sdkver><added>2014-09-27</added><features/><permissions>INTERNET,RECEIVE_BOOT_COMPLETED,ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,org.torproject.android.MANAGE_TOR</permissions></package></application><application id="org.gege.caldavsyncadapter"><id>org.gege.caldavsyncadapter</id><added>2014-10-03</added><lastupdated>2014-10-03</lastupdated><name>CalDAV Sync Adapter</name><summary>(installed by F-Droid)</summary><desc><p>(installed by F-Droid, first installed on Fri Oct 03 09:07:38 EDT 2014, last updated on Fri Oct 03 09:07:38 EDT 2014)</p></desc><icon>org.gege.caldavsyncadapter_18.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>1.8.1</marketversion><marketvercode>18</marketvercode><package><version>1.8.1</version><versioncode>18</versioncode><apkname>org.gege.caldavsyncadapter_18.apk</apkname><hash type="sha256">3fba34579260dd8f4290a0f68c7526e12385901d52d81267751336e81e2f654a</hash><sig>9767040018038872ff3f651a32969d77</sig><size>796278</size><sdkver>14</sdkver><added>2014-10-03</added><features/><permissions>AUTHENTICATE_ACCOUNTS,READ_CALENDAR,WRITE_CALENDAR,INTERNET</permissions></package></application><application id="info.guardianproject.checkey"><id>info.guardianproject.checkey</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>Checkey</name><summary>(installed by F-Droid)</summary><desc><p>(installed by F-Droid, first installed on Sat Sep 27 23:44:13 EDT 2014, last updated on Sat Sep 27 23:44:21 EDT 2014)</p></desc><icon>info.guardianproject.checkey_1.png</icon><license>Unknown</license><categories>LocalRepo,Android-Nexus-7-20139453</categories><category>LocalRepo,Android-Nexus-7-20139453</category><web/><source/><tracker/><marketversion>0.1</marketversion><marketvercode>1</marketvercode><package><version>0.1</version><versioncode>1</versioncode><apkname>info.guardianproject.checkey_1.apk</apkname><hash type="sha256">a8e3c102d5279a3029d0eebdeda2ffdbe1f8a3493ea7dbdc31a11affc708ee57</hash><sig>d70ac6a02b53ebdd1354ea7af7b9ceee</sig><size>878679</size><sdkver>8</sdkver><added>2014-09-27</added><features/><permissions>INTERNET</permissions></package></application></fdroid> diff --git a/app/src/test/resources/testy.at.or.at_corrupt_app_package_name_index-v1.jar b/app/src/test/resources/testy.at.or.at_corrupt_app_package_name_index-v1.jar new file mode 100644 index 0000000000000000000000000000000000000000..44611cedefb8988a56fde734826a4ebfe0ed7881 GIT binary patch literal 4326 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 literal 0 HcmV?d00001 diff --git a/app/src/test/resources/testy.at.or.at_corrupt_package_name_index-v1.jar b/app/src/test/resources/testy.at.or.at_corrupt_package_name_index-v1.jar new file mode 100644 index 0000000000000000000000000000000000000000..a087e839774fd60cd08d1c707e8c0a0e6d3c6673 GIT binary patch literal 4325 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 literal 0 HcmV?d00001