diff --git a/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java b/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java index fabd5649b..9ee53fcdf 100644 --- a/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java +++ b/app/src/androidTest/java/org/fdroid/fdroid/installer/ApkVerifierTest.java @@ -28,7 +28,7 @@ import android.support.test.runner.AndroidJUnit4; import android.util.Log; import org.fdroid.fdroid.AssetUtils; -import org.fdroid.fdroid.RepoXMLHandler; +import org.fdroid.fdroid.data.RepoXMLHandler; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.compat.FileCompatTest; import org.fdroid.fdroid.data.Apk; diff --git a/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java b/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java index b67b3e908..2b70965b4 100644 --- a/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java +++ b/app/src/main/java/org/fdroid/fdroid/IndexUpdater.java @@ -38,6 +38,7 @@ import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoPersister; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.RepoPushRequest; +import org.fdroid.fdroid.data.RepoXMLHandler; import org.fdroid.fdroid.data.Schema.RepoTable; import org.fdroid.fdroid.installer.InstallManagerService; import org.fdroid.fdroid.installer.InstallerService; diff --git a/app/src/main/java/org/fdroid/fdroid/Utils.java b/app/src/main/java/org/fdroid/fdroid/Utils.java index e99b9cab4..110838af2 100644 --- a/app/src/main/java/org/fdroid/fdroid/Utils.java +++ b/app/src/main/java/org/fdroid/fdroid/Utils.java @@ -76,6 +76,7 @@ import java.util.List; import java.util.Locale; import java.util.Map; import java.util.concurrent.TimeUnit; +import java.util.regex.Pattern; public final class Utils { @@ -98,6 +99,8 @@ public final class Utils { private static DisplayImageOptions.Builder defaultDisplayImageOptionsBuilder; private static DisplayImageOptions repoAppDisplayImageOptions; + private static Pattern safePackageNamePattern; + public static final String FALLBACK_ICONS_DIR = "/icons/"; /* @@ -621,6 +624,21 @@ public final class Utils { return sb; } + /** + * This is not strict validation of the package name, this is just to make + * sure that the package name is not used as an attack vector, e.g. SQL + * Injection. + */ + public static boolean isSafePackageName(@Nullable String packageName) { + if (TextUtils.isEmpty(packageName)) { + return false; + } + if (safePackageNamePattern == null) { + safePackageNamePattern = Pattern.compile("[a-zA-Z0-9._]+"); + } + return safePackageNamePattern.matcher(packageName).matches(); + } + /** * Calculate the number of days since the given date. */ 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 a4aac393b..66a815fff 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -16,7 +16,6 @@ import android.webkit.MimeTypeMap; import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; -import org.fdroid.fdroid.RepoXMLHandler; import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Schema.ApkTable.Cols; @@ -461,6 +460,20 @@ public class Apk extends ValueObject implements Comparable, 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/ApkProvider.java b/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java index d89eb0a68..00e6645fe 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/ApkProvider.java @@ -533,7 +533,7 @@ public class ApkProvider extends FDroidProvider { queryBuilder.addSelection(query); queryBuilder.addOrderBy(sortOrder); - Cursor cursor = LoggingQuery.query(db(), queryBuilder.toString(), queryBuilder.getArgs()); + Cursor cursor = LoggingQuery.rawQuery(db(), queryBuilder.toString(), queryBuilder.getArgs()); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } 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, 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/AppPrefsProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppPrefsProvider.java index c4734d889..6e5c752f2 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/AppPrefsProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/AppPrefsProvider.java @@ -131,7 +131,7 @@ public class AppPrefsProvider extends FDroidProvider { query.addFields(projection); query.addOrderBy(sortOrder); - Cursor cursor = LoggingQuery.query(db(), query.toString(), query.getArgs()); + Cursor cursor = LoggingQuery.rawQuery(db(), query.toString(), query.getArgs()); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java index 6283ca3d2..d7188b48e 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java @@ -892,7 +892,7 @@ public class AppProvider extends FDroidProvider { query.addOrderBy(sortOrder); query.addLimit(limit); - Cursor cursor = LoggingQuery.query(db(), query.toString(), query.getArgs()); + Cursor cursor = LoggingQuery.rawQuery(db(), query.toString(), query.getArgs()); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } diff --git a/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java b/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java index a78f53b1e..db45311e0 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/CategoryProvider.java @@ -211,7 +211,7 @@ public class CategoryProvider extends FDroidProvider { query.setOnlyCategoriesWithApps(); } - Cursor cursor = LoggingQuery.query(db(), query.toString(), query.getArgs()); + Cursor cursor = LoggingQuery.rawQuery(db(), query.toString(), query.getArgs()); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } diff --git a/app/src/main/java/org/fdroid/fdroid/data/LoggingQuery.java b/app/src/main/java/org/fdroid/fdroid/data/LoggingQuery.java index aaa1c06ab..881d1c707 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/LoggingQuery.java +++ b/app/src/main/java/org/fdroid/fdroid/data/LoggingQuery.java @@ -161,7 +161,7 @@ final class LoggingQuery { return plan; } - public static Cursor query(SQLiteDatabase db, String query, String[] queryBuilderArgs) { + public static Cursor rawQuery(SQLiteDatabase db, String query, String[] queryBuilderArgs) { return new LoggingQuery(db, query, queryBuilderArgs).rawQuery(); } diff --git a/app/src/main/java/org/fdroid/fdroid/data/PackageProvider.java b/app/src/main/java/org/fdroid/fdroid/data/PackageProvider.java index 3b4daee34..bd70850de 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/PackageProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/PackageProvider.java @@ -138,7 +138,7 @@ public class PackageProvider extends FDroidProvider { query.addFields(projection); query.addOrderBy(sortOrder); - Cursor cursor = LoggingQuery.query(db(), query.toString(), query.getArgs()); + Cursor cursor = LoggingQuery.rawQuery(db(), query.toString(), query.getArgs()); cursor.setNotificationUri(getContext().getContentResolver(), uri); return cursor; } diff --git a/app/src/main/java/org/fdroid/fdroid/data/RepoPushRequest.java b/app/src/main/java/org/fdroid/fdroid/data/RepoPushRequest.java index 49082c873..7ac81ae95 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/RepoPushRequest.java +++ b/app/src/main/java/org/fdroid/fdroid/data/RepoPushRequest.java @@ -20,6 +20,10 @@ package org.fdroid.fdroid.data; import android.support.annotation.Nullable; +import org.fdroid.fdroid.Utils; + +import java.util.Arrays; +import java.util.List; /** * Represents action requests embedded in the index XML received from a repo. @@ -32,15 +36,33 @@ public class RepoPushRequest { public static final String INSTALL = "install"; public static final String UNINSTALL = "uninstall"; + public static final List VALID_REQUESTS = Arrays.asList(INSTALL, UNINSTALL); public final String request; public final String packageName; @Nullable public final Integer versionCode; + /** + * Create a new instance. {@code request} is validated against the list of + * valid install requests. {@code packageName} has a safety validation to + * make sure that only valid Android/Java Package Name characters are included. + * If validation fails, the the values are set to {@code null}, which are + * handled in {@link org.fdroid.fdroid.IndexV1Updater#processRepoPushRequests(List)} + * or {@link org.fdroid.fdroid.IndexUpdater#processRepoPushRequests(List)} + */ public RepoPushRequest(String request, String packageName, @Nullable String versionCode) { - this.request = request; - this.packageName = packageName; + if (VALID_REQUESTS.contains(request)) { + this.request = request; + } else { + this.request = null; + } + + if (Utils.isSafePackageName(packageName)) { + this.packageName = packageName; + } else { + this.packageName = null; + } Integer i; try { diff --git a/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java b/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java similarity index 97% rename from app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java rename to app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java index 5aef95ac7..1da274f63 100644 --- a/app/src/main/java/org/fdroid/fdroid/RepoXMLHandler.java +++ b/app/src/main/java/org/fdroid/fdroid/data/RepoXMLHandler.java @@ -17,15 +17,12 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -package org.fdroid.fdroid; +package org.fdroid.fdroid.data; import android.os.Build; import android.support.annotation.NonNull; import android.support.annotation.Nullable; -import org.fdroid.fdroid.data.Apk; -import org.fdroid.fdroid.data.App; -import org.fdroid.fdroid.data.Repo; -import org.fdroid.fdroid.data.RepoPushRequest; +import org.fdroid.fdroid.Utils; import org.fdroid.fdroid.data.Schema.ApkTable; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -332,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)) { @@ -344,8 +341,7 @@ public class RepoXMLHandler extends DefaultHandler { repoDescription = cleanWhiteSpace(attributes.getValue("", "description")); repoTimestamp = parseLong(attributes.getValue("", "timestamp"), 0); repoIcon = attributes.getValue("", "icon"); - } else if (RepoPushRequest.INSTALL.equals(localName) - || RepoPushRequest.UNINSTALL.equals(localName)) { + } else if (RepoPushRequest.VALID_REQUESTS.contains(localName)) { if (repo.pushRequests == Repo.PUSH_REQUEST_ACCEPT_ALWAYS) { RepoPushRequest r = new RepoPushRequest( localName, @@ -356,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/updater/RepoXMLHandlerTest.java b/app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java similarity index 93% rename from app/src/test/java/org/fdroid/fdroid/updater/RepoXMLHandlerTest.java rename to app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java index 7b568c579..e77b53bfd 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/RepoXMLHandlerTest.java +++ b/app/src/test/java/org/fdroid/fdroid/data/RepoXMLHandlerTest.java @@ -20,23 +20,25 @@ * MA 02110-1301, USA. */ -package org.fdroid.fdroid.updater; +package org.fdroid.fdroid.data; import android.support.annotation.NonNull; import android.text.TextUtils; import android.util.Log; import org.apache.commons.io.FileUtils; import org.fdroid.fdroid.BuildConfig; -import org.fdroid.fdroid.data.Apk; -import org.fdroid.fdroid.data.App; -import org.fdroid.fdroid.data.Repo; -import org.fdroid.fdroid.data.RepoPushRequest; +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; @@ -52,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) @@ -128,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(); @@ -160,6 +190,51 @@ public class RepoXMLHandlerTest { assertEquals(6, repoPushRequests.size()); } + @Test + public void testPushRequestsRepoCorruption() { + RepoPushRequest repoPushRequest; + repoPushRequest = new RepoPushRequest(null, null, null); // request with no data + assertEquals(repoPushRequest.request, null); + assertEquals(repoPushRequest.packageName, null); + assertEquals(repoPushRequest.versionCode, null); + + repoPushRequest = new RepoPushRequest("install", "org.fdroid.fdroid", "999999999999"); + assertEquals(repoPushRequest.versionCode, null); + + repoPushRequest = new RepoPushRequest("install", "org.fdroid.fdroid", + String.valueOf(((long) Integer.MAX_VALUE) + 1)); + assertEquals(repoPushRequest.versionCode, null); + + repoPushRequest = new RepoPushRequest("install", "org.fdroid.fdroid", + String.valueOf(((long) Integer.MIN_VALUE) - 1)); + assertEquals(repoPushRequest.versionCode, null); + + repoPushRequest = new RepoPushRequest("Robert'); DROP TABLE Students; --", "org.fdroid.fdroid", null); + assertEquals(repoPushRequest.request, null); + assertEquals(repoPushRequest.packageName, "org.fdroid.fdroid"); + assertEquals(repoPushRequest.versionCode, null); + + repoPushRequest = new RepoPushRequest("install", "Robert'); DROP TABLE Students; --", "123.1.1"); + assertEquals(repoPushRequest.request, "install"); + assertEquals(repoPushRequest.packageName, null); + assertEquals(repoPushRequest.versionCode, null); + + repoPushRequest = new RepoPushRequest("install", "--", "123"); + assertEquals(repoPushRequest.request, "install"); + assertEquals(repoPushRequest.packageName, null); + 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, Integer.valueOf(123)); + + repoPushRequest = new RepoPushRequest("badrquest", "asdfasdfasdf", "123"); + assertEquals(repoPushRequest.request, null); + assertEquals(repoPushRequest.packageName, "asdfasdfasdf"); + assertEquals(repoPushRequest.versionCode, Integer.valueOf(123)); + } + @Test public void testMediumRepo() { Repo expectedRepo = new Repo(); @@ -839,7 +914,7 @@ public class RepoXMLHandlerTest { } @NonNull - static RepoDetails getFromFile(ClassLoader classLoader, String indexFilename, int pushRequests) { + public static RepoDetails getFromFile(ClassLoader classLoader, String indexFilename, int pushRequests) { Log.i(TAG, "test file: " + classLoader.getResource(indexFilename)); InputStream inputStream = classLoader.getResourceAsStream(indexFilename); return RepoDetails.getFromFile(inputStream, pushRequests); 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 3ea37db40..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; @@ -25,6 +26,7 @@ import org.fdroid.fdroid.data.InstalledAppTestUtils; import org.fdroid.fdroid.data.Repo; import org.fdroid.fdroid.data.RepoProvider; import org.fdroid.fdroid.data.RepoPushRequest; +import org.fdroid.fdroid.data.RepoXMLHandlerTest; import org.fdroid.fdroid.mock.RepoDetails; import org.junit.Before; import org.junit.Test; @@ -158,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 @@ +A local FDroid repo generated from apps installed on Android-Nexus-7-20139453Robert'); DROP TABLE Students; --2014-09-272014-09-27Firefox(installed by null)<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>org.mozilla.firefox_2014092317.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-2013945332.0.3201409231732.0.32014092317org.mozilla.firefox_2014092317.apk4b4e642b71acfe217758bb12ae7dec7fe46027ee732f4a9775ef7a4107deb5fb20e61aee1b748061ec3b0ab1bbe5bac43083163392014-09-27RECEIVE_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_STORAGEcom.koushikdutta.superuser2014-09-272014-09-27Superuser(installed by null)<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>com.koushikdutta.superuser_1030.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394531.0.3.010301.0.3.01030com.koushikdutta.superuser_1030.apk8bbe1c0aa307a0c689d0b97ea5123f6d74d42bb9f91cbeaac2583b23de3a77ab9af2c721bb87900f7e386d7a3716a7a6294460282014-09-27ACCESS_SUPERUSER,RECEIVE_BOOT_COMPLETEDinfo.guardianproject.courier2014-10-032014-10-03CourierCourier is a mobile RSS news reader with<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>info.guardianproject.courier_15.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394530.1.9150.1.915info.guardianproject.courier_15.apkbf6566da1f90831887f5bf5605f8d816b1f7f694969459dec599b8bc01a827d3d70ac6a02b53ebdd1354ea7af7b9ceee1648475392014-10-03INTERNET,ACCESS_NETWORK_STATE,WRITE_EXTERNAL_STORAGE,ACCESS_WIFI_STATE,BLUETOOTH,BLUETOOTH_ADMIN,VIBRATE,READ_EXTERNAL_STORAGEorg.adaway2014-09-292014-09-29AdAway(installed by F-Droid)<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>org.adaway_50.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394532.9.1502.9.150org.adaway_50.apkc9f4fcdca5e47abecfe8bc529ba6299f242fce1d5c87e50b8a36ace82d4fc2595292cd7cf993d06d6f6741117b8400fc281687772014-09-29INTERNET,ACCESS_NETWORK_STATE,RECEIVE_BOOT_COMPLETED,WRITE_EXTERNAL_STORAGE,WAKE_LOCK,ACCESS_SUPERUSER,READ_EXTERNAL_STORAGEinfo.guardianproject.gilga2014-10-042014-10-07Gilgamesh(installed by F-Droid)<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>info.guardianproject.gilga_2.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394530.0.222info.guardianproject.gilga_2.apk1eac2e0043977dc8f31947f19852803207205887a5f01a1cbb8a5e477b3d82a96de574cd61a684bda38ba8e895dece7c30761142014-10-04BLUETOOTH_ADMIN,BLUETOOTH,ACCESS_WIFI_STATE,CHANGE_WIFI_STATE,INTERNETcom.google.zxing.client.android2014-09-272014-09-27Barcode Scanner(installed by null)<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>com.google.zxing.client.android_100.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394534.7.01004.7.0100com.google.zxing.client.android_100.apk62dea7cf201d2e36725ad76b1525decb58b05dd9e4a032ed084c7a6c6d38da2cc3bb49636af03e7c23a63724eb529ea9735678152014-09-27CAMERA,INTERNET,VIBRATE,FLASHLIGHT,READ_CONTACTS,com.android.browser.permission.READ_HISTORY_BOOKMARKS,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,READ_EXTERNAL_STORAGEinfo.guardianproject.lildebi2014-09-282014-09-28Lil' DebiWant an easy Debian chroot running that <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>info.guardianproject.lildebi_5100.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394530.5.151000.5.15100info.guardianproject.lildebi_5100.apk7af667881af6107f3fe60d6973712506dbaf83710d383eb1c312fc75dae2e46ab4964fd759edaa54e65bb476d0276880156948082014-09-28INTERNET,ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE,WAKE_LOCK,jackpal.androidterm.permission.RUN_SCRIPTde.danoeh.antennapod2014-10-032014-10-03AntennaPod(installed by F-Droid)<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>de.danoeh.antennapod_40.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394530.9.9.3400.9.9.340de.danoeh.antennapod_40.apkea83cb81c03bc8b6c1fb6e61e7d0915abef8ca175789a5ac5add45c12f633ebd3870fa89bfb5e13509ce5888800bc6432815685102014-10-03INTERNET,WRITE_EXTERNAL_STORAGE,WAKE_LOCK,ACCESS_NETWORK_STATE,ACCESS_WIFI_STATE,RECEIVE_BOOT_COMPLETED,READ_EXTERNAL_STORAGEinfo.guardianproject.otr.app.im2014-09-272014-09-27ChatSecure(installed by F-Droid)<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>info.guardianproject.otr.app.im_1403000.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-2013945314.0.3140300014.0.31403000info.guardianproject.otr.app.im_1403000.apk46b0b26e2122a8bf937be259d6219ffe5bace7b2eda692b43a5f55fff2322e13a0eeebb161f946e3516945fae8a92a3e1123585292014-09-27info.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_AUTHorg.torproject.android2014-09-272014-09-27OrbotOrbot is a free proxy app that empowers <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>org.torproject.android_124.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-2013945314.0.8.112414.0.8.1124org.torproject.android_124.apk74daa523cd9e85722a9190dd95f3b839d69b7457ffcb9647ca6745824f6ef66d8bd7e51b479aeba908ff46ada3305a29554834792014-09-27INTERNET,RECEIVE_BOOT_COMPLETED,ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,org.torproject.android.MANAGE_TORorg.gege.caldavsyncadapter2014-10-032014-10-03CalDAV Sync Adapter(installed by F-Droid)<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>org.gege.caldavsyncadapter_18.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394531.8.1181.8.118org.gege.caldavsyncadapter_18.apk3fba34579260dd8f4290a0f68c7526e12385901d52d81267751336e81e2f654a9767040018038872ff3f651a32969d77796278142014-10-03AUTHENTICATE_ACCOUNTS,READ_CALENDAR,WRITE_CALENDAR,INTERNETinfo.guardianproject.checkey2014-09-272014-09-27Checkey(installed by F-Droid)<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>info.guardianproject.checkey_1.pngUnknownLocalRepo,Android-Nexus-7-20139453LocalRepo,Android-Nexus-7-201394530.110.11info.guardianproject.checkey_1.apka8e3c102d5279a3029d0eebdeda2ffdbe1f8a3493ea7dbdc31a11affc708ee57d70ac6a02b53ebdd1354ea7af7b9ceee87867982014-09-27INTERNET 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 000000000..44611cede Binary files /dev/null and b/app/src/test/resources/testy.at.or.at_corrupt_app_package_name_index-v1.jar differ 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 000000000..a087e8397 Binary files /dev/null and b/app/src/test/resources/testy.at.or.at_corrupt_package_name_index-v1.jar differ diff --git a/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java b/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java index 5778f482c..e17411a41 100644 --- a/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java +++ b/app/src/testShared/java/org/fdroid/fdroid/mock/RepoDetails.java @@ -2,7 +2,7 @@ package org.fdroid.fdroid.mock; import android.support.annotation.NonNull; -import org.fdroid.fdroid.RepoXMLHandler; +import org.fdroid.fdroid.data.RepoXMLHandler; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; import org.fdroid.fdroid.data.RepoPushRequest;