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&#39;); DROP TABLE Students; --</id><added>2014-09-27</added><lastupdated>2014-09-27</lastupdated><name>Firefox</name><summary>(installed by null)</summary><desc>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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>&lt;p&gt;(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)&lt;/p&gt;</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