From d769dcfc6076bd22038c082d675f6052f02a44bc Mon Sep 17 00:00:00 2001 From: Hans-Christoph Steiner Date: Wed, 22 Mar 2017 21:38:33 +0100 Subject: [PATCH] support new index-v1 format using Jackson parser This adds support for parsing the new index-v1.json data as defined in fdroidserver!221. This new index metadata format is required to support localization, graphics, screenshots, etc. refs #15 --- app/build.gradle | 10 +- app/proguard-rules.pro | 10 + .../org/fdroid/fdroid/IndexV1Updater.java | 335 +++ .../java/org/fdroid/fdroid/RepoUpdater.java | 38 +- .../java/org/fdroid/fdroid/UpdateService.java | 12 +- .../main/java/org/fdroid/fdroid/data/Apk.java | 32 +- .../main/java/org/fdroid/fdroid/data/App.java | 17 + .../java/org/fdroid/fdroid/data/Repo.java | 10 + .../org/fdroid/fdroid/net/Downloader.java | 8 + .../org/fdroid/fdroid/net/HttpDownloader.java | 23 +- .../fdroid/net/LocalFileDownloader.java | 6 +- .../fdroid/updater/IndexV1UpdaterTest.java | 205 ++ .../fdroid/updater/MultiRepoUpdaterTest.java | 2 +- .../fdroid/updater/RepoXMLHandlerTest.java | 9 +- .../resources/guardianproject_index-v1.json | 1974 +++++++++++++++++ .../test/resources/guardianproject_index.xml | 790 +++++++ .../resources/testy.at.or.at_index-v1.jar | Bin 0 -> 24734 bytes .../testy.at.or.at_no-.RSA_index-v1.jar | Bin 0 -> 22726 bytes .../testy.at.or.at_no-.SF_index-v1.jar | Bin 0 -> 24353 bytes ...testy.at.or.at_no-MANIFEST.MF_index-v1.jar | Bin 0 -> 24423 bytes .../testy.at.or.at_no-signature_index-v1.jar | Bin 0 -> 22162 bytes 21 files changed, 3437 insertions(+), 44 deletions(-) create mode 100644 app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java create mode 100644 app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java create mode 100644 app/src/test/resources/guardianproject_index-v1.json create mode 100644 app/src/test/resources/guardianproject_index.xml create mode 100644 app/src/test/resources/testy.at.or.at_index-v1.jar create mode 100644 app/src/test/resources/testy.at.or.at_no-.RSA_index-v1.jar create mode 100644 app/src/test/resources/testy.at.or.at_no-.SF_index-v1.jar create mode 100644 app/src/test/resources/testy.at.or.at_no-MANIFEST.MF_index-v1.jar create mode 100644 app/src/test/resources/testy.at.or.at_no-signature_index-v1.jar diff --git a/app/build.gradle b/app/build.gradle index 2ee1df806..3d4bcb75e 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -58,13 +58,14 @@ dependencies { exclude module: 'design' } - testCompile 'junit:junit:4.12' + compile 'com.fasterxml.jackson.core:jackson-core:2.8.7' + compile 'com.fasterxml.jackson.core:jackson-annotations:2.8.7' + compile 'com.fasterxml.jackson.core:jackson-databind:2.8.7' testCompile "org.robolectric:robolectric:3.3.1" - + testCompile 'junit:junit:4.12' // As per https://github.com/robolectric/robolectric/issues/1932#issuecomment-219796474 testCompile 'org.khronos:opengl-api:gl1.1-android-2.1_r1' - testCompile "org.mockito:mockito-core:1.10.19" androidTestCompile "com.android.support:support-annotations:${supportLibVersion}" @@ -129,6 +130,9 @@ if (!hasProperty('sourceDeps')) { 'com.android.support:support-v4:cd030f875dc7ee73b58e17598f368a2e12824fb3ceb4ed515ed815a47160228c', 'com.android.support:support-vector-drawable:d79752fd68db5a8f5c18125517dafb9e4d7b593c755d188986010e15edd62454', 'com.android.support:transition:5a4adefb1b410b23ad62b4477bc612edc47d3dfc8efed488deb8223b70b510d7', + 'com.fasterxml.jackson.core:jackson-annotations:6b7802f6c22c09c4a92a2ebeb76e755c3c0a58dfbf419835fae470d89e469b86', + 'com.fasterxml.jackson.core:jackson-core:256ff34118ab292d1b4f3ee4d2c3e5e5f0f609d8e07c57e8ad1f51c46d4fbb46', + 'com.fasterxml.jackson.core:jackson-databind:4f74337b6d18664be0f5b15c6664b17aa3972c9c175092328b139b894ff66f19', 'com.github.pserwylo:BottomNavigation:83d7941a7a8d21ba1a8a708cd683b1bb07c6cf898044dc92eadf18a7a7d54f90', 'com.google.zxing:core:b4d82452e7a6bf6ec2698904b332431717ed8f9a850224f295aec89de80f2259', 'com.hannesdorfmann:adapterdelegates3:1b20d099d6e7afe57aceca13b713b386959d94a247c3c06a7aeb65b866ece02f', diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro index 65c2e1e09..517c234ec 100644 --- a/app/proguard-rules.pro +++ b/app/proguard-rules.pro @@ -44,3 +44,13 @@ # - https://github.com/ReactiveX/RxJava/issues/1415#issuecomment-48390883 # - https://github.com/ReactiveX/RxJava/blob/1.x/src/main/java/rx/internal/util/unsafe/UnsafeAccess.java#L23 -dontwarn rx.internal.util.** + +-keepattributes *Annotation*,EnclosingMethod,Signature +-keepnames class com.fasterxml.jackson.** { *; } +-dontwarn com.fasterxml.jackson.databind.ext.** +-keep class org.codehaus.** { *; } +-keepclassmembers public final enum org.codehaus.jackson.annotate.JsonAutoDetect$Visibility { +public static final org.codehaus.jackson.annotate.JsonAutoDetect$Visibility *; } +-keep public class your.class.** { + *; +} \ No newline at end of file diff --git a/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java new file mode 100644 index 000000000..9b8001d0b --- /dev/null +++ b/app/src/main/java/org/fdroid/fdroid/IndexV1Updater.java @@ -0,0 +1,335 @@ +package org.fdroid.fdroid; + +import android.content.ContentValues; +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.annotation.NonNull; +import android.support.v4.content.LocalBroadcastManager; +import android.text.TextUtils; +import android.util.Log; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.ObjectMapper; + +import org.apache.commons.io.FileUtils; +import org.fdroid.fdroid.data.Apk; +import org.fdroid.fdroid.data.App; +import org.fdroid.fdroid.data.Repo; +import org.fdroid.fdroid.data.RepoPersister; +import org.fdroid.fdroid.data.RepoProvider; +import org.fdroid.fdroid.data.Schema; +import org.fdroid.fdroid.net.Downloader; +import org.fdroid.fdroid.net.DownloaderFactory; + +import java.io.IOException; +import java.io.InputStream; +import java.net.URL; +import java.security.cert.X509Certificate; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +/** + * Receives the index data about all available apps and packages via the V1 + * JSON data {@link #DATA_FILE_NAME}, embedded in a signed jar + * {@link #SIGNED_FILE_NAME}. This uses the Jackson library to parse the JSON, + * with {@link App} and {@link Apk} being instantiated directly from the JSON + * by Jackson. This is possible but not wise to do with {@link Repo} since that + * class has many fields that are related to security components of the + * implementation internal to this app. + */ +public class IndexV1Updater extends RepoUpdater { + public static final String TAG = "IndexV1Updater"; + + private static final String SIGNED_FILE_NAME = "index-v1.jar"; + public static final String DATA_FILE_NAME = "index-v1.json"; + + private final LocalBroadcastManager localBroadcastManager; + + public IndexV1Updater(@NonNull Context context, @NonNull Repo repo) { + super(context, repo); + this.localBroadcastManager = LocalBroadcastManager.getInstance(this.context); + } + + /** + * @return whether this successfully found an index of this version + * @throws RepoUpdater.UpdateException + */ + @Override + public boolean update() throws RepoUpdater.UpdateException { + + if (repo.isSwap) { + // swap repos do not support index-v1 + return false; + } + Downloader downloader = null; + InputStream indexInputStream = null; + try { + // read file name from file + final Uri dataUri = Uri.parse(repo.address).buildUpon().appendPath(SIGNED_FILE_NAME).build(); + downloader = DownloaderFactory.create(context, dataUri.toString()); + downloader.setCacheTag(repo.lastetag); + downloader.setListener(new ProgressListener() { + @Override + public void onProgress(URL sourceUrl, int bytesRead, int totalBytes) { + Intent intent = new Intent(Downloader.ACTION_PROGRESS); + intent.setData(dataUri); + intent.putExtra(Downloader.EXTRA_BYTES_READ, bytesRead); + intent.putExtra(Downloader.EXTRA_TOTAL_BYTES, totalBytes); + localBroadcastManager.sendBroadcast(intent); + } + }); + downloader.download(); + if (downloader.isNotFound()) { + return false; + } + if (downloader.isCached()) { + // The index is unchanged since we last read it. We just mark + // everything that came from this repo as being updated. + Utils.debugLog(TAG, "Repo index for " + dataUri + " is up to date (by etag)"); + } + hasChanged = downloader.hasChanged(); + + if (!hasChanged) { + return true; + } + + JarFile jarFile = new JarFile(downloader.outputFile, true); + JarEntry indexEntry = (JarEntry) jarFile.getEntry(DATA_FILE_NAME); + indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry), + processXmlProgressListener, new URL(repo.address), (int) indexEntry.getSize()); + processIndexV1(indexInputStream, indexEntry, downloader.getCacheTag()); + + } catch (IOException e) { + if (downloader != null) { + FileUtils.deleteQuietly(downloader.outputFile); + } + throw new RepoUpdater.UpdateException(repo, "Error getting index file", e); + } catch (InterruptedException e) { + // ignored if canceled, the local database just won't be updated + } + + return true; + } + + /** + * Parses the index and feeds it to the database via {@link Repo}, {@link App}, + * and {@link Apk} instances. + * + * @param indexInputStream {@link InputStream} to {@code index-v1.json} + * @param cacheTag the {@code etag} value from HTTP headers + * @throws IOException + * @throws UpdateException + */ + public void processIndexV1(InputStream indexInputStream, JarEntry indexEntry, String cacheTag) + throws IOException, UpdateException { + ObjectMapper mapper = new ObjectMapper(); + JsonFactory f = mapper.getFactory(); + JsonParser parser = f.createParser(indexInputStream); + HashMap repoMap = null; + App[] apps = null; + Map requests = null; + Map> packages = null; + + parser.nextToken(); // go into the main object block + while (true) { + String fieldName = parser.nextFieldName(); + if (fieldName == null) { + break; + } + switch (fieldName) { + case "repo": + repoMap = parseRepo(mapper, parser); + break; + case "requests": + requests = parseRequests(mapper, parser); + break; + case "apps": + apps = parseApps(mapper, parser); + break; + case "packages": + packages = parsePackages(mapper, parser); + break; + } + } + parser.close(); // ensure resources get cleaned up timely and properly + + if (repoMap == null) { + return; + } + + /* TODO + if (timestamp < repo.timestamp) { + throw new RepoUpdater.UpdateException(repo, "index.jar is older that current index! " + + timestamp + " < " + repo.timestamp); + } + */ + // TODO handle maxage, convert to "expiration" Date instance + + X509Certificate certificate = getSigningCertFromJar(indexEntry); + verifySigningCertificate(certificate); + Utils.debugLog(TAG, "Repo signature verified, saving app metadata to database."); + + // timestamp is absolutely required + repo.timestamp = (Long) repoMap.get("timestamp"); + // below are optional, can be null + repo.name = getStringRepoValue(repoMap, "name"); + repo.icon = getStringRepoValue(repoMap, "icon"); + repo.description = getStringRepoValue(repoMap, "description"); + repo.mirrors = getStringArrayRepoValue(repoMap, "mirrors"); + // below are optional, can be default value + repo.maxage = getIntRepoValue(repoMap, "maxage"); + repo.version = getIntRepoValue(repoMap, "version"); + + RepoPersister repoPersister = new RepoPersister(context, repo); + if (apps != null && apps.length > 0) { + for (App app : apps) { + app.repoId = repo.getId(); // TODO this should be "injected" i.e. @JacksonInject + List apks = null; + if (packages != null) { + apks = packages.get(app.packageName); + } + if (apks == null) { + Log.i(TAG, "processIndexV1 empty packages"); + apks = new ArrayList(0); + } + repoPersister.saveToDb(app, apks); + } + } + + // TODO send event saying moving on to committing to db + ContentValues values = prepareRepoDetailsForSaving(repo.name, + repo.description, repo.maxage, repo.version, repo.timestamp, repo.icon, + repo.mirrors, cacheTag); + repoPersister.commit(values); + + + // TODO RepoUpdater.processRepoPushRequests(context, repoPushRequestList); + Utils.debugLog(TAG, "Repo Push Requests: " + requests); + } + + private int getIntRepoValue(Map repoMap, String key) { + Object value = repoMap.get(key); + if (value != null && value instanceof Integer) { + return (Integer) value; + } + return Repo.INT_UNSET_VALUE; + } + + private String getStringRepoValue(Map repoMap, String key) { + Object value = repoMap.get(key); + if (value != null && value instanceof String) { + return (String) value; + } + return null; + } + + private String[] getStringArrayRepoValue(Map repoMap, String key) { + Object value = repoMap.get(key); + if (value != null && value instanceof String[]) { + return (String[]) value; + } + return null; + } + + private HashMap parseRepo(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference> typeRef = new TypeReference>() { + }; + parser.nextToken(); + parser.nextToken(); + return mapper.readValue(parser, typeRef); + } + + private Map parseRequests(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference> typeRef = new TypeReference>() { + }; + parser.nextToken(); // START_OBJECT + return mapper.readValue(parser, typeRef); + } + + private App[] parseApps(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference typeRef = new TypeReference() { + }; + parser.nextToken(); // START_ARRAY + return mapper.readValue(parser, typeRef); + } + + private Map> parsePackages(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference>> typeRef = new TypeReference>>() { + }; + parser.nextToken(); // START_OBJECT + return mapper.readValue(parser, typeRef); + } + + /** + * Verify that the signing certificate used to sign {@link #SIGNED_FILE_NAME} + * matches the signing stored in the database for this repo. {@link #repo} and + * {@code repo.signingCertificate} must be pre-loaded from the database before + * running this, if this is an existing repo. If the repo does not exist, + * this will run the TOFU process. + *

+ * Index V1 works with two copies of the signing certificate: + *

  • in the downloaded jar
  • + *
  • stored in the local database
  • + *

    + * A new repo can be added with or without the fingerprint of the signing + * certificate. If no fingerprint is supplied, then do a pure TOFU and just + * store the certificate as valid. If there is a fingerprint, then first + * check that the signing certificate in the jar matches that fingerprint. + *

    + * This is also responsible for adding the {@link Repo} instance to the + * database for the first time. + *

    + * This is the same as {@link RepoUpdater#verifyCerts(String, X509Certificate)}, + * {@link RepoUpdater#verifyAndStoreTOFUCerts(String, X509Certificate)}, and + * {@link RepoUpdater#assertSigningCertFromXmlCorrect()} except there is no + * embedded copy of the signing certificate in the index data. + * + * @param rawCertFromJar the {@link X509Certificate} embedded in the downloaded jar + * @see RepoUpdater#verifyAndStoreTOFUCerts(String, X509Certificate) + * @see RepoUpdater#verifyCerts(String, X509Certificate) + * @see RepoUpdater#assertSigningCertFromXmlCorrect() + */ + private void verifySigningCertificate(X509Certificate rawCertFromJar) throws SigningException { + String certFromJar = Hasher.hex(rawCertFromJar); + + if (TextUtils.isEmpty(certFromJar)) { + throw new SigningException(repo, + SIGNED_FILE_NAME + " must have an included signing certificate!"); + } + + if (repo.signingCertificate == null) { + if (repo.fingerprint != null) { + String fingerprintFromJar = Utils.calcFingerprint(rawCertFromJar); + if (!repo.fingerprint.equalsIgnoreCase(fingerprintFromJar)) { + throw new SigningException(repo, + "Supplied certificate fingerprint does not match!"); + } + } + Utils.debugLog(TAG, "Saving new signing certificate to database for " + repo.address); + ContentValues values = new ContentValues(2); + values.put(Schema.RepoTable.Cols.LAST_UPDATED, Utils.formatDate(new Date(), "")); + values.put(Schema.RepoTable.Cols.SIGNING_CERT, Hasher.hex(rawCertFromJar)); + RepoProvider.Helper.update(context, repo, values); + repo.signingCertificate = certFromJar; + } + + if (TextUtils.isEmpty(repo.signingCertificate)) { + throw new SigningException(repo, "A empty repo signing certificate is invalid!"); + } + + if (repo.signingCertificate.equals(certFromJar)) { + return; // we have a match! + } + + throw new SigningException(repo, "Signing certificate does not match!"); + } + +} diff --git a/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java b/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java index a29899c89..e2abe0df2 100644 --- a/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java +++ b/app/src/main/java/org/fdroid/fdroid/RepoUpdater.java @@ -21,6 +21,8 @@ */ package org.fdroid.fdroid; +// TODO move to org.fdroid.fdroid.updater +// TODO reduce visibility of methods once in .updater package (.e.g tests need it public now) import android.content.ContentResolver; import android.content.ContentValues; @@ -83,21 +85,22 @@ import javax.xml.parsers.SAXParserFactory; * very careful with the changes that you are making! */ public class RepoUpdater { - + //TODO rename RepoUpdater to IndexV0Updater private static final String TAG = "RepoUpdater"; private final String indexUrl; @NonNull - private final Context context; + final Context context; @NonNull - private final Repo repo; - private boolean hasChanged; + final Repo repo; + boolean hasChanged; @Nullable - private ProgressListener downloadProgressListener; - private ProgressListener committingProgressListener; - private ProgressListener processXmlProgressListener; + ProgressListener downloadProgressListener; + ProgressListener committingProgressListener; + ProgressListener processXmlProgressListener; + private String cacheTag; private X509Certificate signingCertFromJar; @@ -174,10 +177,10 @@ public class RepoUpdater { * a single file, {@code index.xml}. This takes the {@code index.jar}, verifies the * signature, then returns the unzipped {@code index.xml}. * + * @return whether this version of the repo index was found and processed * @throws UpdateException All error states will come from here. */ - public void update() throws UpdateException { - + public boolean update() throws UpdateException { final Downloader downloader = downloadIndex(); hasChanged = downloader.hasChanged(); @@ -188,6 +191,7 @@ public class RepoUpdater { processDownloadedFile(downloader.outputFile); processRepoPushRequests(); } + return true; } private ContentValues repoDetailsToSave; @@ -200,7 +204,7 @@ public class RepoUpdater { int version, long timestamp, String icon, String[] mirrors) { signingCertFromIndexXml = signingCert; repoDetailsToSave = prepareRepoDetailsForSaving(name, description, maxAge, version, - timestamp, icon, mirrors); + timestamp, icon, mirrors, cacheTag); } @Override @@ -297,9 +301,9 @@ public class RepoUpdater { * Update tracking data for the repo represented by this instance (index version, etag, * description, human-readable name, etc. */ - private ContentValues prepareRepoDetailsForSaving(String name, String description, int maxAge, - int version, long timestamp, String icon, - String[] mirrors) { + ContentValues prepareRepoDetailsForSaving(String name, String description, int maxAge, + int version, long timestamp, String icon, + String[] mirrors, String cacheTag) { ContentValues values = new ContentValues(); values.put(RepoTable.Cols.LAST_UPDATED, Utils.formatTime(new Date(), "")); @@ -308,12 +312,12 @@ public class RepoUpdater { values.put(RepoTable.Cols.LAST_ETAG, cacheTag); } - if (version != -1 && version != repo.version) { + if (version != Repo.INT_UNSET_VALUE && version != repo.version) { Utils.debugLog(TAG, "Repo specified a new version: from " + repo.version + " to " + version); values.put(RepoTable.Cols.VERSION, version); } - if (maxAge != -1 && maxAge != repo.maxage) { + if (maxAge != Repo.INT_UNSET_VALUE && maxAge != repo.maxage) { Utils.debugLog(TAG, "Repo specified a new maximum age - updated"); values.put(RepoTable.Cols.MAX_AGE, maxAge); } @@ -372,7 +376,7 @@ public class RepoUpdater { * signing setups that would be valid for a regular jar. This validates those * restrictions. */ - private X509Certificate getSigningCertFromJar(JarEntry jarEntry) throws SigningException { + X509Certificate getSigningCertFromJar(JarEntry jarEntry) throws SigningException { final CodeSigner[] codeSigners = jarEntry.getCodeSigners(); if (codeSigners == null || codeSigners.length == 0) { throw new SigningException(repo, "No signature found in index"); @@ -458,7 +462,7 @@ public class RepoUpdater { * should always accept, prompt the user, or ignore those requests on a * per repo basis. */ - private void processRepoPushRequests() { + void processRepoPushRequests() { PackageManager pm = context.getPackageManager(); for (RepoPushRequest repoPushRequest : repoPushRequestList) { diff --git a/app/src/main/java/org/fdroid/fdroid/UpdateService.java b/app/src/main/java/org/fdroid/fdroid/UpdateService.java index 4dcb1c000..265651e6f 100644 --- a/app/src/main/java/org/fdroid/fdroid/UpdateService.java +++ b/app/src/main/java/org/fdroid/fdroid/UpdateService.java @@ -393,10 +393,16 @@ public class UpdateService extends IntentService { } sendStatus(this, STATUS_INFO, getString(R.string.status_connecting_to_repo, repo.address)); - RepoUpdater updater = new RepoUpdater(getBaseContext(), repo); - setProgressListeners(updater); + + try { - updater.update(); + RepoUpdater updater = new IndexV1Updater(this, repo); + //TODO setProgressListeners(updater); + if (!updater.update()) { + updater = new RepoUpdater(getBaseContext(), repo); + setProgressListeners(updater); + updater.update(); + } if (updater.hasChanged()) { updatedRepos++; changes = true; 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 f7e6c3df8..3ba7d9359 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Apk.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Apk.java @@ -8,6 +8,7 @@ import android.os.Build; import android.os.Parcel; import android.os.Parcelable; import android.support.annotation.NonNull; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import org.fdroid.fdroid.BuildConfig; import org.fdroid.fdroid.RepoXMLHandler; @@ -18,6 +19,21 @@ import java.io.File; import java.util.Date; import java.util.HashSet; +/** + * Represents a single package of an application. This represents one particular + * package of a given application, for info about the app in general, see + * {@link App}. + *

    + * Do not rename these instance variables without careful consideration! + * They are mapped to JSON field names, the {@code fdroidserver} internal variable + * names, and the {@code fdroiddata} YAML field names. Only the instance variables + * listed in {@code @JsonIgnoreProperties} are not directly mapped. + * + * @see fdroiddata + * @see fdroidserver + */ +@JsonIgnoreProperties({"compatible", "CREATOR", "installedFile", "repo", "repoAddress", + "repoVersion",}) public class Apk extends ValueObject implements Comparable, Parcelable { // Using only byte-range keeps it only 8-bits in the SQLite database @@ -94,16 +110,16 @@ public class Apk extends ValueObject implements Comparable, Parcelable { * If you need an {@link Apk} but it is no longer in the database any more (e.g. because the * version you have installed is no longer in the repository metadata) then you can instantiate * an {@link Apk} via an {@link InstalledApp} instance. - * + *

    * Note: Many of the fields on this instance will not be known in this circumstance. Currently * the only things that are known are: - * - * + {@link Apk#packageName} - * + {@link Apk#versionName} - * + {@link Apk#versionCode} - * + {@link Apk#hash} - * + {@link Apk#hashType} - * + *

    + * + {@link Apk#packageName} + * + {@link Apk#versionName} + * + {@link Apk#versionCode} + * + {@link Apk#hash} + * + {@link Apk#hashType} + *

    * This could instead be implemented by accepting a {@link PackageInfo} and it would get much * the same information, but it wouldn't have the hash of the package. Seeing as we've already * done the hard work to calculate that hash and stored it in the database, we may as well use 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 fdfe675d6..65f4033b9 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/App.java +++ b/app/src/main/java/org/fdroid/fdroid/data/App.java @@ -16,6 +16,8 @@ import android.support.annotation.Nullable; import android.text.TextUtils; import android.util.Log; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import org.apache.commons.io.filefilter.RegexFileFilter; import org.fdroid.fdroid.AppFilter; import org.fdroid.fdroid.FDroidApp; @@ -39,6 +41,21 @@ import java.util.jar.JarFile; import java.util.regex.Matcher; import java.util.regex.Pattern; +/** + * Represents an application, its availability, and its current installed state. + * This represents the app in general, for a specific version of this app, see + * {@link Apk}. + *

    + * Do not rename these instance variables without careful consideration! + * They are mapped to JSON field names, the {@code fdroidserver} internal variable + * names, and the {@code fdroiddata} YAML field names. Only the instance variables + * listed in {@code @JsonIgnoreProperties} are not directly mapped. + * + * @see fdroiddata + * @see fdroidserver + */ +@JsonIgnoreProperties({"compatible", "CREATOR", "id", "installedApk", "installedSig", + "installedVersionCode", "installedVersionName", "prefs", "repoId", }) public class App extends ValueObject implements Comparable, Parcelable { private static final String TAG = "App"; diff --git a/app/src/main/java/org/fdroid/fdroid/data/Repo.java b/app/src/main/java/org/fdroid/fdroid/data/Repo.java index 589c5d0ce..288a41388 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/Repo.java +++ b/app/src/main/java/org/fdroid/fdroid/data/Repo.java @@ -34,6 +34,14 @@ import java.net.MalformedURLException; import java.net.URL; import java.util.Date; + +/** + * Represents a the descriptive info and metadata about a given repo, as provided + * by the repo index. This also keeps track of the state of the repo. + * + * @see fdroiddata + * @see fdroidserver + */ public class Repo extends ValueObject { public static final int VERSION_DENSITY_SPECIFIC_ICONS = 11; @@ -42,6 +50,8 @@ public class Repo extends ValueObject { public static final int PUSH_REQUEST_PROMPT = 1; public static final int PUSH_REQUEST_ACCEPT_ALWAYS = 2; + public static final int INT_UNSET_VALUE = -1; + // these are never set by the Apk/package index metadata protected long id; public String address; diff --git a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java index 0d5692dad..f44d50334 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/Downloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/Downloader.java @@ -34,6 +34,7 @@ public abstract class Downloader { final URL sourceUrl; String cacheTag; + boolean notFound; /** * For sending download progress, should only be called in {@link #progressTask} @@ -86,6 +87,13 @@ public abstract class Downloader { public abstract boolean isCached(); + /** + * @return whether the requested file was not found in the repo (e.g. HTTP 404 Not Found) + */ + public boolean isNotFound() { + return notFound; + } + void downloadFromStream(int bufferSize, boolean resumable) throws IOException, InterruptedException { Utils.debugLog(TAG, "Downloading from stream"); InputStream input = null; diff --git a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java index d792ed2b0..de4b272e7 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/HttpDownloader.java @@ -79,17 +79,25 @@ public class HttpDownloader extends Downloader { */ @Override public void download() throws IOException, InterruptedException { - boolean resumable = false; - long fileLength = outputFile.length(); - // get the file size from the server HttpURLConnection tmpConn = getConnection(); tmpConn.setRequestMethod("HEAD"); int contentLength = -1; - if (tmpConn.getResponseCode() == 200) { - contentLength = tmpConn.getContentLength(); - } + int statusCode = tmpConn.getResponseCode(); tmpConn.disconnect(); + switch (statusCode) { + case 200: + contentLength = tmpConn.getContentLength(); + break; + case 404: + notFound = true; + return; + default: + Utils.debugLog(TAG, "HEAD check of " + sourceUrl + " returned " + statusCode + ": " + + tmpConn.getResponseMessage()); + } + boolean resumable = false; + long fileLength = outputFile.length(); if (fileLength > contentLength) { FileUtils.deleteQuietly(outputFile); } else if (fileLength == contentLength && outputFile.isFile()) { @@ -127,9 +135,6 @@ public class HttpDownloader extends Downloader { return connection; } - /** - * @return Whether the connection is resumable or not - */ private void setupConnection(boolean resumable) throws IOException { if (connection != null) { return; diff --git a/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java b/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java index 2207a689f..e684aa693 100644 --- a/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java +++ b/app/src/main/java/org/fdroid/fdroid/net/LocalFileDownloader.java @@ -43,7 +43,11 @@ public class LocalFileDownloader extends Downloader { @Override public void download() throws IOException, InterruptedException { - downloadFromStream(1024 * 50, false); + if (new File(sourceUrl.getPath()).exists()) { + downloadFromStream(1024 * 50, false); + } else { + notFound = true; + } } @Override diff --git a/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java new file mode 100644 index 000000000..1731bf53b --- /dev/null +++ b/app/src/test/java/org/fdroid/fdroid/updater/IndexV1UpdaterTest.java @@ -0,0 +1,205 @@ +package org.fdroid.fdroid.updater; + +import android.support.annotation.NonNull; +import android.util.Log; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.core.JsonParser; +import com.fasterxml.jackson.core.type.TypeReference; +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.ObjectReader; + +import org.apache.commons.io.IOUtils; +import org.fdroid.fdroid.BuildConfig; +import org.fdroid.fdroid.IndexV1Updater; +import org.fdroid.fdroid.Preferences; +import org.fdroid.fdroid.RepoUpdater; +import org.fdroid.fdroid.TestUtils; +import org.fdroid.fdroid.data.Apk; +import org.fdroid.fdroid.data.App; +import org.fdroid.fdroid.data.FDroidProviderTest; +import org.fdroid.fdroid.data.Repo; +import org.fdroid.fdroid.data.RepoPushRequest; +import org.fdroid.fdroid.mock.RepoDetails; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.robolectric.RobolectricGradleTestRunner; +import org.robolectric.annotation.Config; + +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +// TODO: Use sdk=24 when Robolectric supports this +@Config(constants = BuildConfig.class, sdk = 23) +@RunWith(RobolectricGradleTestRunner.class) +public class IndexV1UpdaterTest extends FDroidProviderTest { + public static final String TAG = "IndexV1UpdaterTest"; + + private static final String TESTY_JAR = "testy.at.or.at_index-v1.jar"; + private static final String TESTY_CERT = "308204e1308202c9a0030201020204483450fa300d06092a864886f70d01010b050030213110300e060355040b1307462d44726f6964310d300b06035504031304736f7661301e170d3136303832333133333131365a170d3434303130393133333131365a30213110300e060355040b1307462d44726f6964310d300b06035504031304736f766130820222300d06092a864886f70d01010105000382020f003082020a0282020100dfdcd120f3ab224999dddf4ea33ea588d295e4d7130bef48c143e9d76e5c0e0e9e5d45e64208e35feebc79a83f08939dd6a343b7d1e2179930a105a1249ccd36d88ff3feffc6e4dc53dae0163a7876dd45ecc1ddb0adf5099aa56c1a84b52affcd45d0711ffa4de864f35ac0333ebe61ea8673eeda35a88f6af678cc4d0f80b089338ac8f2a8279a64195c611d19445cab3fd1a020afed9bd739bb95142fb2c00a8f847db5ef3325c814f8eb741bacf86ed3907bfe6e4564d2de5895df0c263824e0b75407589bae2d3a4666c13b92102d8781a8ee9bb4a5a1a78c4a9c21efdaf5584da42e84418b28f5a81d0456a3dc5b420991801e6b21e38c99bbe018a5b2d690894a114bc860d35601416aa4dc52216aff8a288d4775cddf8b72d45fd2f87303a8e9c0d67e442530be28eaf139894337266e0b33d57f949256ab32083bcc545bc18a83c9ab8247c12aea037e2b68dee31c734cb1f04f241d3b94caa3a2b258ffaf8e6eae9fbbe029a934dc0a0859c5f120334812693a1c09352340a39f2a678dbc1afa2a978bfee43afefcb7e224a58af2f3d647e5745db59061236b8af6fcfd93b3602f9e456978534f3a7851e800071bf56da80401c81d91c45f82568373af0576b1cc5eef9b85654124b6319770be3cdba3fbebe3715e8918fb6c8966624f3d0e815effac3d2ee06dd34ab9c693218b2c7c06ba99d6b74d4f17b8c3cb0203010001a321301f301d0603551d0e04160414d62bee9f3798509546acc62eb1de14b08b954d4f300d06092a864886f70d01010b05000382020100743f7c5692085895f9d1fffad390fb4202c15f123ed094df259185960fd6dadf66cb19851070f180297bba4e6996a4434616573b375cfee94fee73a4505a7ec29136b7e6c22e6436290e3686fe4379d4e3140ec6a08e70cfd3ed5b634a5eb5136efaaabf5f38e0432d3d79568a556970b8cfba2972f5d23a3856d8a981b9e9bbbbb88f35e708bde9cbc5f681cbd974085b9da28911296fe2579fa64bbe9fa0b93475a7a8db051080b0c5fade0d1c018e7858cd4cbe95145b0620e2f632cbe0f8af9cbf22e2fdaa72245ae31b0877b07181cc69dd2df74454251d8de58d25e76354abe7eb690f22e59b08795a8f2c98c578e0599503d9085927634072c82c9f82abd50fd12b8fd1a9d1954eb5cc0b4cfb5796b5aaec0356643b4a65a368442d92ef94edd3ac6a2b7fe3571b8cf9f462729228aab023ef9183f73792f5379633ccac51079177d604c6bc1873ada6f07d8da6d68c897e88a5fa5d63fdb8df820f46090e0716e7562dd3c140ba279a65b996f60addb0abe29d4bf2f5abe89480771d492307b926d91f02f341b2148502903c43d40f3c6c86a811d060711f0698b384acdcc0add44eb54e42962d3d041accc715afd49407715adc09350cb55e8d9281a3b0b6b5fcd91726eede9b7c8b13afdebb2c2b377629595f1096ba62fb14946dbac5f3c5f0b4e5b712e7acc7dcf6c46cdc5e6d6dfdeee55a0c92c2d70f080ac6"; + + @Test + public void testIndexV1Processing() throws IOException, RepoUpdater.UpdateException { + Preferences.setup(context); + Repo repo = MultiRepoUpdaterTest.createRepo("Testy", TESTY_JAR, context, TESTY_CERT); + IndexV1Updater updater = new IndexV1Updater(context, repo); + JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true); + Log.i(TAG, "jarFile " + jarFile); + JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexV1Updater.DATA_FILE_NAME); + InputStream indexInputStream = jarFile.getInputStream(indexEntry); + updater.processIndexV1(indexInputStream, indexEntry, "fakeEtag"); + IOUtils.closeQuietly(indexInputStream); + } + + @Test(expected = RepoUpdater.SigningException.class) + public void testIndexV1WithWrongCert() throws IOException, RepoUpdater.UpdateException { + String badCert = "308202ed308201d5a003020102020426ffa009300d06092a864886f70d01010b05003027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a656374301e170d3132313030363132303533325a170d3337303933303132303533325a3027310b300906035504061302444531183016060355040a130f4e4f47415050532050726f6a65637430820122300d06092a864886f70d01010105000382010f003082010a02820101009a8d2a5336b0eaaad89ce447828c7753b157459b79e3215dc962ca48f58c2cd7650df67d2dd7bda0880c682791f32b35c504e43e77b43c3e4e541f86e35a8293a54fb46e6b16af54d3a4eda458f1a7c8bc1b7479861ca7043337180e40079d9cdccb7e051ada9b6c88c9ec635541e2ebf0842521c3024c826f6fd6db6fd117c74e859d5af4db04448965ab5469b71ce719939a06ef30580f50febf96c474a7d265bb63f86a822ff7b643de6b76e966a18553c2858416cf3309dd24278374bdd82b4404ef6f7f122cec93859351fc6e5ea947e3ceb9d67374fe970e593e5cd05c905e1d24f5a5484f4aadef766e498adf64f7cf04bddd602ae8137b6eea40722d0203010001a321301f301d0603551d0e04160414110b7aa9ebc840b20399f69a431f4dba6ac42a64300d06092a864886f70d01010b0500038201010007c32ad893349cf86952fb5a49cfdc9b13f5e3c800aece77b2e7e0e9c83e34052f140f357ec7e6f4b432dc1ed542218a14835acd2df2deea7efd3fd5e8f1c34e1fb39ec6a427c6e6f4178b609b369040ac1f8844b789f3694dc640de06e44b247afed11637173f36f5886170fafd74954049858c6096308fc93c1bc4dd5685fa7a1f982a422f2a3b36baa8c9500474cf2af91c39cbec1bc898d10194d368aa5e91f1137ec115087c31962d8f76cd120d28c249cf76f4c70f5baa08c70a7234ce4123be080cee789477401965cfe537b924ef36747e8caca62dfefdd1a6288dcb1c4fd2aaa6131a7ad254e9742022cfd597d2ca5c660ce9e41ff537e5a4041e37"; + Repo repo = MultiRepoUpdaterTest.createRepo("Testy", TESTY_JAR, context, badCert); + IndexV1Updater updater = new IndexV1Updater(context, repo); + JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(TESTY_JAR), true); + JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexV1Updater.DATA_FILE_NAME); + InputStream indexInputStream = jarFile.getInputStream(indexEntry); + updater.processIndexV1(indexInputStream, indexEntry, "fakeEtag"); + fail(); // it should never reach here, it should throw a SigningException + getClass().getResourceAsStream("foo"); + } + + @Test(expected = RepoUpdater.SigningException.class) + public void testIndexV1WithBadTestyJarNoManifest() throws IOException, RepoUpdater.UpdateException { + testBadTestyJar("testy.at.or.at_no-MANIFEST.MF_index-v1.jar"); + } + + @Test(expected = RepoUpdater.SigningException.class) + public void testIndexV1WithBadTestyJarNoSigningCert() throws IOException, RepoUpdater.UpdateException { + testBadTestyJar("testy.at.or.at_no-.RSA_index-v1.jar"); + } + + @Test(expected = RepoUpdater.SigningException.class) + public void testIndexV1WithBadTestyJarNoSignature() throws IOException, RepoUpdater.UpdateException { + testBadTestyJar("testy.at.or.at_no-.SF_index-v1.jar"); + } + + @Test(expected = RepoUpdater.SigningException.class) + public void testIndexV1WithBadTestyJarNoSignatureFiles() throws IOException, RepoUpdater.UpdateException { + testBadTestyJar("testy.at.or.at_no-signature_index-v1.jar"); + } + + private void testBadTestyJar(String jar) throws IOException, RepoUpdater.UpdateException { + Repo repo = MultiRepoUpdaterTest.createRepo("Testy", jar, context, TESTY_CERT); + IndexV1Updater updater = new IndexV1Updater(context, repo); + JarFile jarFile = new JarFile(TestUtils.copyResourceToTempFile(jar), true); + JarEntry indexEntry = (JarEntry) jarFile.getEntry(IndexV1Updater.DATA_FILE_NAME); + InputStream indexInputStream = jarFile.getInputStream(indexEntry); + updater.processIndexV1(indexInputStream, indexEntry, "fakeEtag"); + fail(); // it should never reach here, it should throw a SigningException + } + + @Test + public void testJacksonParsing() throws IOException { + ObjectMapper mapper = new ObjectMapper(); + // the app ignores all unknown fields when complete, do not ignore during dev to catch mistakes + mapper.enable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES); + JsonFactory f = mapper.getFactory(); + JsonParser parser = f.createParser(TestUtils.copyResourceToTempFile("guardianproject_index-v1.json")); + + Repo repo = null; + App[] apps = null; + Map requests = null; + Map> packages = null; + + parser.nextToken(); // go into the main object block + while (true) { + String fieldName = parser.nextFieldName(); + if (fieldName == null) { + break; + } + switch (fieldName) { + case "repo": + repo = parseRepo(mapper, parser); + break; + case "requests": + requests = parseRequests(mapper, parser); + break; + case "apps": + apps = parseApps(mapper, parser); + break; + case "packages": + packages = parsePackages(mapper, parser); + break; + } + } + parser.close(); // ensure resources get cleaned up timely and properly + + RepoDetails indexV0Details = getFromFile("guardianproject_index.xml", + Repo.PUSH_REQUEST_ACCEPT_ALWAYS); + indexV0Details.apps.size(); + + System.out.println("total apps: " + apps.length + " " + indexV0Details.apps.size()); + assertEquals(indexV0Details.apps.size(), apps.length); + assertEquals(apps.length, packages.size()); + + int totalApks = 0; + for (String packageName : packages.keySet()) { + totalApks += packages.get(packageName).size(); + } + assertEquals(totalApks, indexV0Details.apks.size()); + + assertEquals(indexV0Details.icon, repo.icon); + assertEquals(indexV0Details.timestamp, repo.timestamp / 1000); // V1 is in millis + assertEquals(indexV0Details.name, repo.name); + assertArrayEquals(indexV0Details.mirrors, repo.mirrors); + + ArrayList installRequests = new ArrayList<>(); + for (RepoPushRequest repoPushRequest : indexV0Details.repoPushRequestList) { + if ("install".equals(repoPushRequest.request)) { + installRequests.add(repoPushRequest.packageName); + } + } + assertArrayEquals(installRequests.toArray(), requests.get("install")); + } + + private Repo parseRepo(ObjectMapper mapper, JsonParser parser) throws IOException { + System.out.println("parseRepo "); + parser.nextToken(); + parser.nextToken(); + ObjectReader repoReader = mapper.readerFor(Repo.class); + return repoReader.readValue(parser, Repo.class); + } + + private Map parseRequests(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference> typeRef = new TypeReference>() { + }; + parser.nextToken(); // START_OBJECT + return mapper.readValue(parser, typeRef); + } + + private App[] parseApps(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference typeRef = new TypeReference() { + }; + parser.nextToken(); // START_ARRAY + return mapper.readValue(parser, typeRef); + } + + private Map> parsePackages(ObjectMapper mapper, JsonParser parser) throws IOException { + TypeReference>> typeRef = new TypeReference>>() { + }; + parser.nextToken(); // START_OBJECT + return mapper.readValue(parser, typeRef); + } + + @NonNull + private RepoDetails getFromFile(String indexFilename, int pushRequests) { + return RepoXMLHandlerTest.getFromFile(getClass().getClassLoader(), indexFilename, pushRequests); + } +} diff --git a/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java b/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java index 08aadb30d..e457b217a 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/MultiRepoUpdaterTest.java @@ -159,7 +159,7 @@ public abstract class MultiRepoUpdaterTest extends FDroidProviderTest { return createRepo(name, uri, context, PUB_KEY); } - protected Repo createRepo(String name, String uri, Context context, String signingCert) { + static Repo createRepo(String name, String uri, Context context, String signingCert) { Repo repo = new Repo(); repo.signingCertificate = signingCert; repo.address = uri; diff --git a/app/src/test/java/org/fdroid/fdroid/updater/RepoXMLHandlerTest.java b/app/src/test/java/org/fdroid/fdroid/updater/RepoXMLHandlerTest.java index 38acb06cd..b9f7f9e70 100644 --- a/app/src/test/java/org/fdroid/fdroid/updater/RepoXMLHandlerTest.java +++ b/app/src/test/java/org/fdroid/fdroid/updater/RepoXMLHandlerTest.java @@ -842,8 +842,13 @@ public class RepoXMLHandlerTest { @NonNull private RepoDetails getFromFile(String indexFilename, int pushRequests) { - Log.i(TAG, "test file: " + getClass().getClassLoader().getResource(indexFilename)); - InputStream inputStream = getClass().getClassLoader().getResourceAsStream(indexFilename); + return getFromFile(getClass().getClassLoader(), indexFilename, pushRequests); + } + + @NonNull + 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/resources/guardianproject_index-v1.json b/app/src/test/resources/guardianproject_index-v1.json new file mode 100644 index 000000000..750325ce1 --- /dev/null +++ b/app/src/test/resources/guardianproject_index-v1.json @@ -0,0 +1,1974 @@ +{ + "repo": { + "timestamp": 1488828510109, + "version": 18, + "name": "Guardian Project Official Releases", + "icon": "guardianproject.png", + "address": "https://guardianproject.info/fdroid/repo", + "description": "The official app repository of The Guardian Project. Applications in this repository are official binaries build by the original application developers and signed by the same key as the APKs that are released in the Google Play store. ", + "mirrors": [ + "http://bdf2wcxujkg6qqff.onion/fdroid/repo", + "https://guardianproject.info/fdroid/repo", + "https://s3.amazonaws.com/guardianproject/fdroid/repo" + ] + }, + "requests": { + "uninstall": [], + "install": [ + "org.torproject.android", + "info.guardianproject.orfox" + ] + }, + "apps": [ + { + "categories": [ + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Android 4+ allows you to disable certificates from the system Settings and root isn't required, so try that first if you want to manually mess with the certificates. The app won't work with Android 4+ anyway.

    An app to manage security certificates on your phone also containing a version of the Android CACert keystore derived from Mozilla. If a certificate has recently become untrusted you can either install an update to this app or you can backup and remove certificates by yourself.

    Requires root: Yes, it writes to the system partition. You will need a device that has the \u2018grep\u2019 command on it (via busybox: present on most custom ROMs). If the \u2018save\u2019 doesn\u2019t work, then you will need to make your /system partition read-write by using a file explorer like Ghost Commander or via a command in Terminal Emulator.

    ", + "issueTracker": "https://github.com/guardianproject/cacert/issues", + "license": "GPLv3", + "name": "CACertMan", + "sourceCode": "https://github.com/guardianproject/cacert", + "summary": "Disable untrusted certificates", + "webSite": "https://guardianproject.info/2011/09/05/cacertman-app-to-address-diginotar-other-bad-cas", + "added": 1376863200000, + "icon": "info.guardianproject.cacert.4.png", + "packageName": "info.guardianproject.cacert", + "lastUpdated": 1383174000000 + }, + { + "bitcoin": "1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk", + "categories": [ + "Development", + "GuardianProject" + ], + "suggestedVersionCode": "9999999", + "description": "

    An InformaCam app to generate verifiable media.

    ", + "issueTracker": "https://dev.guardianproject.info/projects/informacam/issues", + "license": "GPLv3", + "name": "CameraV", + "sourceCode": "https://github.com/guardianproject/CameraV", + "summary": "An InformaCam app to generate verifiable media", + "webSite": "https://guardianproject.info/apps/camerav/", + "added": 1386716400000, + "icon": "org.witness.informacam.app.206.png", + "packageName": "org.witness.informacam.app", + "lastUpdated": 1446505200000 + }, + { + "categories": [ + "Internet", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    XMPP (Jabber) client that can do end-to-end encryption using the Off-the-Record Messaging protocol and can anonymize your chats via the Orbot app (root not required).

    The app used to be called GibberBot.

    ", + "issueTracker": "https://dev.guardianproject.info/projects/gibberbot", + "license": "Apache2", + "name": "ChatSecure", + "sourceCode": "https://github.com/guardianproject/Gibberbot", + "summary": "Instant Messaging client with OTR", + "webSite": "https://dev.guardianproject.info/projects/gibberbot", + "added": 1363647600000, + "icon": "info.guardianproject.otr.app.im.1423001.png", + "packageName": "info.guardianproject.otr.app.im", + "lastUpdated": 1481029619791 + }, + { + "categories": [ + "Multimedia", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    This is a plugin for ChatSecure. It does not have any function on its own. For Your Ears Only... completely private, end-to-end encryption voice message recording, sending, receiving and playback.

    * For use with ChatSecure's encrypted \"Off-the-record\" data stream * Works over Tor - the ONLY Onion-routed voice messaging system, for total anonymity

    ", + "issueTracker": "https://dev.guardianproject.info/projects/chatsecure/issues", + "license": "SIL Open Font License, MIT License and the CC 3.0 License [CC-By with attribution requirement waived]", + "name": "ChatSecureVoicePlugin", + "sourceCode": "https://github.com/guardianproject/ChatSecureVoicePlugin", + "summary": "ChatSecure Voice Messaging", + "webSite": "https://guardianproject.info/apps/chatsecure", + "added": 1386889200000, + "icon": "info.guardianproject.soundrecorder.2.png", + "packageName": "info.guardianproject.soundrecorder", + "lastUpdated": 1386889200000 + }, + { + "bitcoin": "1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk", + "categories": [ + "Development", + "GuardianProject" + ], + "suggestedVersionCode": "9999999", + "description": "

    Checkey is a utility for getting information about the APKs that are installed on your device. Starting with a list of all of the apps that you have installed on your device, it will show you the APK signature with a single touch, and provides links to virustotal.com and androidobservatory.org to easily access the profiles of that APK. It will also let you export the signing certificate and generate ApkSignaturePin pin files for use with the TrustedIntents library.

    ", + "issueTracker": "https://dev.guardianproject.info/projects/checkey/issues", + "license": "GPLv3", + "name": "Checkey", + "sourceCode": "https://github.com/guardianproject/checkey", + "summary": "Info on local apps", + "webSite": "https://dev.guardianproject.info/projects/checkey", + "added": 1405116000000, + "icon": "info.guardianproject.checkey.102.png", + "packageName": "info.guardianproject.checkey", + "lastUpdated": 1425855600000 + }, + { + "categories": [ + "Reading", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    No description available

    ", + "license": "GPLv3", + "name": "Courier", + "sourceCode": "https://github.com/guardianproject/securereader", + "summary": "Privacy-aware RSS feed reader", + "added": 1400018400000, + "icon": "info.guardianproject.courier.15.png", + "packageName": "info.guardianproject.courier", + "lastUpdated": 1403733600000 + }, + { + "bitcoin": "1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk", + "categories": [ + "Development", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Lil' Debi 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 it has a simple chroot manager that fscks your disk, mounts/unmounts things, starts/stops sshd if you have it installed, etc. You can also then use \u2018apt-get\u2019 to install any package that is released for ARM processors. This includes things like a complete real shell, Tor, TraceRouteTCP, iwconfig/ipconfig, and other security and crypto tools. Works well with Terminal Emulator\u2014just run `/debian/shell` to get a Debian shell.

    The aim of Lil\u2019 Debi is to provide a transparent and tightly integrated Debian install on your Android device. It mounts all of your Android partitions in Debian space, so you see a fusion of both systems. It's even possible to have Lil\u2019 Debi launch the normal Debian init start-up scripts when it starts, so that all you need to do is apt-get install and any servers you install will just work.

    Lil' Debi works with as few modifications to the Android system as possible. Currently, it only adds a /bin symlink, and a /debian mount directory. It does not touch /system at all.

    Requires root: Yes, because it needs to run debootstrap, create dirs in /, mount/umount, etc.

    ", + "issueTracker": "https://github.com/guardianproject/lildebi/issues", + "license": "GPLv3", + "name": "Lil' Debi", + "sourceCode": "https://github.com/guardianproject/lildebi", + "summary": "Run Debian on your phone", + "webSite": "https://github.com/guardianproject/lildebi/wiki", + "added": 1360105200000, + "icon": "info.guardianproject.lildebi.5400.png", + "packageName": "info.guardianproject.lildebi", + "lastUpdated": 1422226800000 + }, + { + "bitcoin": "1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk", + "categories": [ + "Navigation", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "9999999", + "description": "

    LocationPrivacy is not really app but rather a set of \"Intent Filters\" for all of the various ways of sharing location. When you share location from one app, LocationPrivacy offers itself as an option. It then recognizes insecure methods of sharing location, and then converts them to more secure methods. This mostly means that it rewrites URLs to use https, and even to use `geo:` URIs, which can work on fully offline setups. LocationPrivacy mostly works by reading the location information from the URL itself. For many URLs, LocationPrivacy must actually load some of the webpage in order to get the location.

    LocationPrivacy can also serve as a way to redirect all location links to your favorite mapping app. All map apps in Android can view `geo:` URIs, and LocationPrivacy converts many kinds of links to `geo:` URIs, including: Google Maps, OpenStreetMap, Amap, Baidu Map, QQ Map, Nokia HERE, Yandex Maps.

    This was started as part of the T2 Panic work, since sharing location is so often a part of panic apps. Follow our progress here: https://guardianproject.info/tag/panic

    Don\u2019t see your language? Join us and help translate the app: https://www.transifex.com/projects/p/locationprivacy

    ", + "issueTracker": "https://dev.guardianproject.info/projects/panic/issues", + "license": "GPLv3", + "name": "LocationPrivacy", + "sourceCode": "https://github.com/guardianproject/LocationPrivacy", + "summary": "privacy filters for when you are sharing your location", + "webSite": "https://dev.guardianproject.info/projects/panic", + "added": 1422486000000, + "icon": "info.guardianproject.locationprivacy.30.png", + "packageName": "info.guardianproject.locationprivacy", + "lastUpdated": 1481029454284 + }, + { + "categories": [ + "Office", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Simple app for taking notes that encrypts everything behind a password.

    Status: Beta.

    ", + "issueTracker": "https://github.com/guardianproject/notecipher/issues", + "license": "Apache2", + "name": "NoteCipher", + "sourceCode": "https://github.com/guardianproject/notecipher", + "summary": "Notepad with lock", + "webSite": "https://guardianproject.info", + "added": 1358290800000, + "icon": "info.guardianproject.notepadbot.12.png", + "packageName": "info.guardianproject.notepadbot", + "lastUpdated": 1394406000000 + }, + { + "categories": [ + "Multimedia", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Ever capture someone in a photo or video, then realize they may not want to be in it? Not comfortable posting a friend, family member or child\u2019s face on the internet? Worried about the geolocation data in the picture giving away private hideaway? Tired of Facebook, Google and other sites \u201cauto detecting\u201d faces in your photos? Then this is for you, giving you the power to better protect the identity of those captures in your photos, before you post them online.

    Take a picture or load a photo or video from the Gallery, and ObscuraCam will automatically detect faces that you can pixelate, redact (blackout) or protect with funny nose and glasses. You can also invert pixelate, so that only the person you select is visible, and no one in the background can be recognized.

    This app will also remove all identifying data stored in photos including GPS location data and phone make & model. You can save the protected photo back to the Gallery, or share it directly to Facebook, Twitter or any other \u201cShare\u201d enabled app.

    ", + "issueTracker": "https://github.com/guardianproject/obscuracam/issues", + "license": "GPLv3", + "name": "ObscuraCam", + "sourceCode": "https://github.com/guardianproject/obscuracam", + "summary": "A camera app that keeps certain information private", + "webSite": "https://guardianproject.info/apps/obscuracam", + "added": 1376863200000, + "icon": "org.witness.sscphase1.34.png", + "packageName": "org.witness.sscphase1", + "lastUpdated": 1383174000000 + }, + { + "categories": [ + "Security", + "Internet", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Tor is both software and an open network that helps you defend against network surveillance that threatens personal freedom and privacy, confidential business activities and relationships.

    Orbot allows access to Tor by accessing a local SOCKS or HTTP proxy. On a rooted device, the proxying can be completely transparent i.e. the app that accesses the network need not be aware of the proxy's existence; you can choose which apps go via the proxy in the settings.

    If you don't have root access, there are some apps that are designed to work closely with tor or allow proxied connections: ChatSecure, Orweb and Twidere. There is also a proxy configurator addon for org.mozilla.firefox called ProxyMob (not yet available from the Mozilla addon site).

    Requires root: No, but you will need to use apps that allow proxies if root is not granted.

    ", + "donate": "https://www.torproject.org/donate/donate.html.en", + "flattrID": "5649", + "issueTracker": "https://dev.guardianproject.info/projects/orbot/issues", + "license": "NewBSD", + "name": "Orbot", + "sourceCode": "https://gitweb.torproject.org/orbot.git", + "summary": "Tor (anonymity) client", + "webSite": "http://www.torproject.org/docs/android.html.en", + "added": 1374444000000, + "icon": "org.torproject.android.15208000.png", + "packageName": "org.torproject.android", + "lastUpdated": 1481029552790 + }, + { + "categories": [ + "Internet", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Orfox is the most privacy-enhancing web browser on Android, for visiting any website, even if it\u2019s normally censored, monitored, or on the hidden web. It is a port of the desktop Tor Browser to the Android version of Firefox.

    Orfox is a companion browser to Orbot, the port of Tor to Android. Orbot anonymizes internet traffic by routing it through many different stages and you must have that enabled first, though root isn't needed. Orfox disables certain other browser features that could be used to identify you.

    Orfox replaces Orweb as your private browser.

    ", + "issueTracker": "https://dev.guardianproject.info/projects/orfox/issues?set_filter=1", + "license": "MPL", + "name": "Orfox", + "sourceCode": "https://github.com/guardianproject/orfox", + "summary": "Orfox: Tor Browser for Android", + "added": 1474668000000, + "icon": "info.guardianproject.orfox.4.png", + "packageName": "info.guardianproject.orfox", + "lastUpdated": 1481029470199 + }, + { + "categories": [ + "Internet", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Orweb is a companion browser to Orbot, the port of Tor to Android.

    Orbot anonymizes internet traffic by routing it through many different stages and you must have that enabled first, though root isn't needed. Orweb disables certain other browser features that could be used to identify you.

    ", + "issueTracker": "https://dev.guardianproject.info/projects/orweb/issues?set_filter=1", + "license": "GPL", + "name": "Orweb", + "sourceCode": "https://github.com/guardianproject/orweb", + "summary": "Privacy-enhanced browser", + "webSite": "https://guardianproject.info/apps/orweb", + "added": 1350856800000, + "icon": "info.guardianproject.browser.7010.png", + "packageName": "info.guardianproject.browser", + "lastUpdated": 1448492400000 + }, + { + "categories": [ + "Office", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Image steganography app with old school F5 steganography

    ", + "issueTracker": "https://github.com/guardianproject/PixelKnot/issues", + "license": "GPLv3", + "name": "PixelKnot", + "sourceCode": "https://github.com/guardianproject/PixelKnot", + "summary": "Hide messages inside files", + "webSite": "https://guardianproject.info", + "added": 1361833200000, + "icon": "info.guardianproject.pixelknot.100.png", + "packageName": "info.guardianproject.pixelknot", + "lastUpdated": 1481029472671 + }, + { + "bitcoin": "1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk", + "categories": [ + "Navigation", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "9999999", + "description": "

    Ripple is a \"panic button\" that can send it's trigger message to any app that is a \"panic responder\". Such apps can do things like lock, disguise themselves, delete private data, send an emergency message, and more. It is meant for situations where there is time to react, but where users need to be sure it is not mistakenly set off.

    This is a BETA version of this app! We are working now to add support to as many other apps as possible. ChatSecure, Orweb, Umbrella, and Zom already have support, these apps are coming soon: Courier, PanicButton, OpenKeychain, Orfox, SMSSecure, and StoryMaker.

    Here are two example scenarios:

    • An organization gets regularly raided by the security forces, who search all of the computers and mobile devices on the premises. The organization usually has at least a minute or two of warning before a raid starts. They need a very reliable way to trigger wiping all of the data from the sensitive apps.
    • An aid worker has lots of sensitive data about people on their device. They regularly sync that data up with a secure, central database. Occasionally, the aid worker has to leave the country on very short notice. The border guards regularly download the entire contents of mobile devices of people crossing through. While waiting in line at the border, the aid worker sees the border guards seizing people's devices, and then remembers all the data on the device, so she unlocks her phone and hits the wipe trigger, which wipes all sensitive apps from the device. When the aid worker returns to the central office, the device is again synced up with the central database.

    This was started as part of the T2 Panic work, since sharing location is so often a part of panic apps. Follow our progress here:

    \u2605 https://guardianproject.info/tag/panic \u2605 https://dev.guardianproject.info/projects/panic Don\u2019t see your language? Join us and help translate the app: https://www.transifex.com/projects/p/rippleapp

    ==Learn More==

    \u2605 ABOUT US: Guardian Project is a group of developers that make secure mobile apps and open-source code for a better tomorrow \u2605 OUR WEBSITE: https://GuardianProject.info \u2605 ON TWITTER: https://twitter.com/guardianproject \u2605 FREE SOFTWARE: Ripple is free software. You can take a look at our source code, or contribute to help make Ripple even better: https://github.com/guardianproject/Ripple \u2605 MESSAGE US: Are we missing your favorite feature? Found an annoying bug? Please tell us! We\u2019d love to hear from you. Send us an email: support@guardianproject.info or find us in our chat room https://guardianproject.info/contact

    ", + "issueTracker": "https://dev.guardianproject.info/projects/panic/issues", + "license": "GPLv3", + "name": "Ripple", + "sourceCode": "https://github.com/guardianproject/ripple", + "summary": "Trigger apps to protect your privacy when in anxious or panic situations", + "webSite": "https://dev.guardianproject.info/projects/panic", + "added": 1481029448654, + "icon": "info.guardianproject.ripple.75.png", + "packageName": "info.guardianproject.ripple", + "lastUpdated": 1481029466419 + }, + { + "categories": [ + "Multimedia", + "Security", + "GuardianProject" + ], + "suggestedVersionCode": "999999999", + "description": "

    Plugin for ChatSecure to support for core emoji input and display. Based on \"Phantom Open Emoji\" project.

    ", + "issueTracker": "https://dev.guardianproject.info/projects/chatsecure/issues", + "license": "SIL Open Font License, MIT License and the CC 3.0 License [CC-By with attribution requirement waived]", + "name": "StickerPack", + "sourceCode": "https://github.com/guardianproject/ChatSecureVoicePlugin", + "summary": "ChatSecure Open Emoji Plugin", + "webSite": "https://guardianproject.info/apps/chatsecure", + "added": 1385938800000, + "icon": "info.guardianproject.chatsecure.emoji.core.1.png", + "packageName": "info.guardianproject.chatsecure.emoji.core", + "lastUpdated": 1385938800000 + } + ], + "packages": { + "info.guardianproject.courier": [ + { + "added": 1400018400000, + "apkName": "Courier-0.1.8.apk", + "hash": "e013db095e8da843fae5ac44be6152e51377ee717e5c8a7b6d913d7720566b5a", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "info.guardianproject.courier", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 16536125, + "targetSdkVersion": "15", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.BLUETOOTH", + null + ], + [ + "android.permission.BLUETOOTH_ADMIN", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ] + ], + "versionCode": 14, + "versionName": "0.1.8" + }, + { + "added": 1403733600000, + "apkName": "Courier-0.1.9.apk", + "hash": "bf6566da1f90831887f5bf5605f8d816b1f7f694969459dec599b8bc01a827d3", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "info.guardianproject.courier", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 16484753, + "targetSdkVersion": "15", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.BLUETOOTH", + null + ], + [ + "android.permission.BLUETOOTH_ADMIN", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ] + ], + "versionCode": 15, + "versionName": "0.1.9" + } + ], + "info.guardianproject.cacert": [ + { + "added": 1376863200000, + "apkName": "CACertMan-0.0.2-alpha-20111011.apk", + "hash": "251ebd40ce4a281a2292692707fb1e9c91428994cbad80a416a297db51069eb8", + "hashType": "sha256", + "minSdkVersion": "7", + "packageName": "info.guardianproject.cacert", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 172263, + "targetSdkVersion": "7", + "versionCode": 4, + "versionName": "0.0.2.20111012" + }, + { + "added": 1383174000000, + "apkName": "CACertMan-0.0.2-20110906.apk", + "hash": "c217c49abe5134007ceb2623a6189a73fa02af9d2b2bbcc5cbc4cb5da7b36a5d", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.cacert", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 170305, + "targetSdkVersion": "8", + "versionCode": 3, + "versionName": "0.0.2-20110906" + } + ], + "info.guardianproject.soundrecorder": [ + { + "added": 1386889200000, + "apkName": "ChatSecureVoiceMessaging-0.2.apk", + "hash": "abae18cc9cfa62fca5dce072c4c50d41b4fece506967ce9a3e2711cd1031dbee", + "hashType": "sha256", + "minSdkVersion": "10", + "packageName": "info.guardianproject.soundrecorder", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 394212, + "targetSdkVersion": "10", + "uses-permission": [ + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.RECORD_AUDIO", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.READ_PHONE_STATE", + null + ] + ], + "versionCode": 2, + "versionName": "0.2" + } + ], + "info.guardianproject.browser": [ + { + "added": 1404079200000, + "apkName": "Orweb-release-0.6.1.apk", + "hash": "103f4a98fa282923c07e445b2a383e946b6c15e10ed08005af3d0743249a0359", + "hashType": "sha256", + "minSdkVersion": "9", + "packageName": "info.guardianproject.browser", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 931433, + "targetSdkVersion": "19", + "uses-permission": [ + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 27, + "versionName": "0.6.1" + }, + { + "added": 1448492400000, + "apkName": "Orweb-0.7.1.apk", + "hash": "949d65d6e8a1eadd0aa626bdc7c5a3e2b0dbe5a38dea1d725cce2a34ec84f0d4", + "hashType": "sha256", + "minSdkVersion": "9", + "packageName": "info.guardianproject.browser", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 2424394, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 7010, + "versionName": "0.7.1" + }, + { + "added": 1415833200000, + "apkName": "Orweb-release-0.7.apk", + "hash": "763541f43f5dc136744b4361fe67d36f25cc036526d6c3e934287d72d1b411ab", + "hashType": "sha256", + "minSdkVersion": "9", + "packageName": "info.guardianproject.browser", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1244875, + "targetSdkVersion": "18", + "uses-permission": [ + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 28, + "versionName": "0.7" + } + ], + "info.guardianproject.notepadbot": [ + { + "added": 1394406000000, + "apkName": "NoteCipher-beta-0.1.apk", + "hash": "b560a3d6364c32990ea7505f53b019f64fde597d67513f41a50e7d034af48caa", + "hashType": "sha256", + "minSdkVersion": "10", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "info.guardianproject.notepadbot", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 7321123, + "targetSdkVersion": "19", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.VIBRATE", + null + ] + ], + "versionCode": 12, + "versionName": "0.1" + }, + { + "added": 1358290800000, + "apkName": "NoteCipher-0.0.7.apk", + "hash": "8fa7536a87634c6b3441053c4f16315e4fd5aa6ef672a0026a594c107308d7bf", + "hashType": "sha256", + "minSdkVersion": "7", + "nativecode": [ + "armeabi" + ], + "packageName": "info.guardianproject.notepadbot", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 3731119, + "targetSdkVersion": "17", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 10, + "versionName": "0.0.7" + }, + { + "added": 1383174000000, + "apkName": "NoteCipher-0.0.7.1.apk", + "hash": "da518f13206d2218234bfcc83205b7b2b81ec67a4cc448f818c617332235e700", + "hashType": "sha256", + "minSdkVersion": "11", + "nativecode": [ + "armeabi" + ], + "packageName": "info.guardianproject.notepadbot", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 3729342, + "targetSdkVersion": "17", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 11, + "versionName": "0.0.7.1" + } + ], + "info.guardianproject.orfox": [ + { + "added": 1481029470199, + "apkName": "Orfox-1.2.1-TorBrowser-6.5-Fennec45.5.1-build2.apk", + "hash": "d43032e79c7c31cabb194b8c1c4b14fbf73dd2cfda958ba415879ddf2f38ace2", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi-v7a" + ], + "packageName": "info.guardianproject.orfox", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 35273126, + "targetSdkVersion": "22", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION", + null + ], + [ + "info.guardianproject.orfox.permissions.BROWSER_PROVIDER", + null + ], + [ + "com.android.launcher.permission.UNINSTALL_SHORTCUT", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.CHANGE_WIFI_STATE", + null + ], + [ + "info.guardianproject.orfox.permissions.FORMHISTORY_PROVIDER", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "com.android.launcher.permission.INSTALL_SHORTCUT", + null + ], + [ + "com.android.browser.permission.READ_HISTORY_BOOKMARKS", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ], + [ + "info.guardianproject.orfox.permissions.PASSWORD_PROVIDER", + null + ] + ], + "versionCode": 4, + "versionName": "Fennec-45.5.1esr/TorBrowser-6.5-1/Orfox-1.2.1" + }, + { + "added": 1474668000000, + "apkName": "Orfox-1.2-TorBrowser-6.5-Fennec45.4.0.apk", + "hash": "9b5f6614b94a47ae561e8c974d42056ba6cb6da520766deda09aec3699aeff94", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi-v7a" + ], + "packageName": "info.guardianproject.orfox", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 35242066, + "targetSdkVersion": "22", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.DOWNLOAD_WITHOUT_NOTIFICATION", + null + ], + [ + "info.guardianproject.orfox.permissions.BROWSER_PROVIDER", + null + ], + [ + "com.android.launcher.permission.UNINSTALL_SHORTCUT", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.CHANGE_WIFI_STATE", + null + ], + [ + "info.guardianproject.orfox.permissions.FORMHISTORY_PROVIDER", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "com.android.launcher.permission.INSTALL_SHORTCUT", + null + ], + [ + "com.android.browser.permission.READ_HISTORY_BOOKMARKS", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ], + [ + "info.guardianproject.orfox.permissions.PASSWORD_PROVIDER", + null + ] + ], + "versionCode": 3, + "versionName": "Fennec-45.4.0esr/TorBrowser-6.5-1/Orfox-1.2" + } + ], + "info.guardianproject.chatsecure.emoji.core": [ + { + "added": 1385938800000, + "apkName": "ChatSecurePluginOpenEmoji-release-v1.apk", + "hash": "131c1ebaf795c3f053701285699f0b7e517de1c7fdba56e247b1ec31766b2808", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.chatsecure.emoji.core", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1814271, + "targetSdkVersion": "17", + "versionCode": 1, + "versionName": "1.0" + } + ], + "info.guardianproject.pixelknot": [ + { + "added": 1374444000000, + "apkName": "PixelKnot-release-0.3.1.apk", + "hash": "a3101fe8a2d47ab205cb00459fa62c639a6fac4538f6cd9d06eb48d2965c4d21", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi" + ], + "packageName": "info.guardianproject.pixelknot", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 3976822, + "targetSdkVersion": "17", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.CAMERA", + null + ] + ], + "versionCode": 4, + "versionName": "0.3.1" + }, + { + "added": 1481029472671, + "apkName": "PixelKnot-release-1.0.0.apk", + "hash": "f97557cf7ec81ade50c308c5552dc6dc827d0e02ce90f84b1df6b7477d9f5a39", + "hashType": "sha256", + "minSdkVersion": "17", + "nativecode": [ + "arm64-v8a", + "armeabi", + "armeabi-v7a", + "mips", + "mips64", + "x86", + "x86_64" + ], + "packageName": "info.guardianproject.pixelknot", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1983586, + "targetSdkVersion": "25", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + 18 + ], + [ + "android.permission.VIBRATE", + 18 + ] + ], + "versionCode": 100, + "versionName": "1.0.0" + }, + { + "added": 1435269600000, + "apkName": "PixelKnot-release-0.3.3.apk", + "hash": "6beede8519a9e87ba8edaa5a76f203cfefd5f39eb911e789031cc6e911714b89", + "hashType": "sha256", + "minSdkVersion": "14", + "nativecode": [ + "armeabi" + ], + "packageName": "info.guardianproject.pixelknot", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 4751233, + "targetSdkVersion": "17", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.CAMERA", + null + ] + ], + "versionCode": 6, + "versionName": "0.3.3" + } + ], + "org.witness.informacam.app": [ + { + "added": 1443736800000, + "apkName": "CameraV-release-0.2.4.apk", + "hash": "a10eefaed5a12c353525b07e655f6959fe1eb06cd5c549be56afaca6db0c6ce0", + "hashType": "sha256", + "minSdkVersion": "16", + "nativecode": [ + "armeabi", + "armeabi-v7a", + "x86" + ], + "packageName": "org.witness.informacam.app", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 24062229, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.KILL_BACKGROUND_PROCESSES", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.RECORD_AUDIO", + null + ], + [ + "android.permission.ACCESS_COARSE_LOCATION", + null + ], + [ + "android.permission.CAMERA", + null + ], + [ + "android.permission.BLUETOOTH", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.READ_PHONE_STATE", + null + ], + [ + "android.permission.USE_CREDENTIALS", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.GET_ACCOUNTS", + null + ], + [ + "android.permission.CHANGE_WIFI_STATE", + null + ], + [ + "android.permission.BLUETOOTH_ADMIN", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.ACCESS_FINE_LOCATION", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ], + [ + "android.permission.GET_TASKS", + null + ] + ], + "versionCode": 204, + "versionName": "0.2.4" + }, + { + "added": 1446505200000, + "apkName": "CameraVApp-release-0.2.6.apk", + "hash": "508f453e26c8c83dba858b53b21d909d549fe5646d01eb198c96c22d8e521e7c", + "hashType": "sha256", + "minSdkVersion": "16", + "nativecode": [ + "armeabi", + "armeabi-v7a", + "x86" + ], + "packageName": "org.witness.informacam.app", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 24123646, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.KILL_BACKGROUND_PROCESSES", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.RECORD_AUDIO", + null + ], + [ + "android.permission.ACCESS_COARSE_LOCATION", + null + ], + [ + "android.permission.CAMERA", + null + ], + [ + "android.permission.BLUETOOTH", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.READ_PHONE_STATE", + null + ], + [ + "android.permission.USE_CREDENTIALS", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.GET_TOP_ACTIVITY_INFO", + null + ], + [ + "android.permission.GET_ACCOUNTS", + null + ], + [ + "android.permission.CHANGE_WIFI_STATE", + null + ], + [ + "android.permission.BLUETOOTH_ADMIN", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.ACCESS_FINE_LOCATION", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ] + ], + "versionCode": 206, + "versionName": "0.2.6" + }, + { + "added": 1442354400000, + "apkName": "CameraVApp-release-0.2.2.apk", + "hash": "8b17cbe2a5cb777b49f5ef67a390f9d9d68765c90213ac64f3ca0456860dc9b7", + "hashType": "sha256", + "minSdkVersion": "16", + "nativecode": [ + "armeabi", + "armeabi-v7a", + "x86" + ], + "packageName": "org.witness.informacam.app", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 24283932, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.KILL_BACKGROUND_PROCESSES", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.RECORD_AUDIO", + null + ], + [ + "android.permission.ACCESS_COARSE_LOCATION", + null + ], + [ + "android.permission.CAMERA", + null + ], + [ + "android.permission.BLUETOOTH", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.READ_PHONE_STATE", + null + ], + [ + "android.permission.USE_CREDENTIALS", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.GET_ACCOUNTS", + null + ], + [ + "android.permission.CHANGE_WIFI_STATE", + null + ], + [ + "android.permission.BLUETOOTH_ADMIN", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.ACCESS_FINE_LOCATION", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ], + [ + "android.permission.GET_TASKS", + null + ] + ], + "versionCode": 202, + "versionName": "0.2.2" + } + ], + "info.guardianproject.checkey": [ + { + "added": 1425855600000, + "apkName": "Checkey-0.1.2.apk", + "hash": "754701dbac52de5ca3930c2393970c03ef9aa07d1456911e9bf254d6014e0645", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.checkey", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 842881, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 102, + "versionName": "0.1.2" + }, + { + "added": 1422399600000, + "apkName": "Checkey-0.1.1.apk", + "hash": "2d81f339bb69626af42e8868dc6928c9072ebcbae76e1ff5ac8172e78ebe9cdd", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.checkey", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 967083, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 101, + "versionName": "0.1.1" + }, + { + "added": 1405116000000, + "apkName": "Checkey-0.1.apk", + "hash": "a8e3c102d5279a3029d0eebdeda2ffdbe1f8a3493ea7dbdc31a11affc708ee57", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.checkey", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 878679, + "targetSdkVersion": "19", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 1, + "versionName": "0.1" + } + ], + "info.guardianproject.lildebi": [ + { + "added": 1413928800000, + "apkName": "LilDebi-0.5.2-release.apk", + "hash": "07fa3dfb690e44eb540942ba2a51718c72351c91a253a56a0c90649f6d8903dd", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.lildebi", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1861790, + "targetSdkVersion": "19", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_SUPERUSER", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "jackpal.androidterm.permission.RUN_SCRIPT", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 5200, + "versionName": "0.5.2" + }, + { + "added": 1422226800000, + "apkName": "LilDebi-0.5.3-release.apk", + "hash": "01c5a8e1fd778c141e70633d14f1b69228d6f492961098616e0446c116cf9e44", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.lildebi", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1879560, + "targetSdkVersion": "19", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_SUPERUSER", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "jackpal.androidterm.permission.RUN_SCRIPT", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 5300, + "versionName": "0.5.3" + }, + { + "added": 1422226800000, + "apkName": "LilDebi-0.5.4-release.apk", + "hash": "2c490376d8853fae04e79541f5d61e66a42ed0e890208945a11036c4a7b111da", + "hashType": "sha256", + "maxSdkVersion": "20", + "minSdkVersion": "8", + "packageName": "info.guardianproject.lildebi", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1876705, + "targetSdkVersion": "20", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_SUPERUSER", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "jackpal.androidterm.permission.RUN_SCRIPT", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 5400, + "versionName": "0.5.4" + } + ], + "info.guardianproject.otr.app.im": [ + { + "added": 1481029471580, + "apkName": "ChatSecure-v14.2.2.apk", + "hash": "9d4620fec0c7837ddffccde7918d7a7db0976fbcd361b96659abd93b5cc0d9e3", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "info.guardianproject.otr.app.im", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 10502135, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.CHANGE_WIFI_MULTICAST_STATE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "info.guardianproject.otr.app.providers.imps.permission.READ_ONLY", + null + ], + [ + "info.guardianproject.otr.app.im.permission.IM_SERVICE", + null + ], + [ + "com.google.android.googleapps.permission.GOOGLE_AUTH", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.USE_CREDENTIALS", + null + ], + [ + "android.permission.UPDATE_APP_OPS_STATS", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ], + [ + "android.permission.GET_ACCOUNTS", + null + ], + [ + "info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY", + null + ], + [ + "android.permission.MANAGE_ACCOUNTS", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ] + ], + "versionCode": 1422001, + "versionName": "14.2.2" + }, + { + "added": 1454454000000, + "apkName": "ChatSecure-v14.2.3a.apk", + "hash": "36d7d71c8a2115bdd2bd63bb639af286ee3242cce11cdb5c53378d1a7f35528e", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "info.guardianproject.otr.app.im", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 10502397, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.CHANGE_WIFI_MULTICAST_STATE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "info.guardianproject.otr.app.providers.imps.permission.READ_ONLY", + null + ], + [ + "info.guardianproject.otr.app.im.permission.IM_SERVICE", + null + ], + [ + "com.google.android.googleapps.permission.GOOGLE_AUTH", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.USE_CREDENTIALS", + null + ], + [ + "android.permission.UPDATE_APP_OPS_STATS", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ], + [ + "android.permission.GET_ACCOUNTS", + null + ], + [ + "info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY", + null + ], + [ + "android.permission.MANAGE_ACCOUNTS", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ] + ], + "versionCode": 1423001, + "versionName": "14.2.3" + }, + { + "added": 1440367200000, + "apkName": "ChatSecure-v14.2.1.apk", + "hash": "f82a3a7a823f5540b335743eb1399d0fd1f61bc68958750b5ef6aa0d95ad9a54", + "hashType": "sha256", + "minSdkVersion": "9", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "info.guardianproject.otr.app.im", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 10463010, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.CHANGE_WIFI_MULTICAST_STATE", + null + ], + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "info.guardianproject.otr.app.providers.imps.permission.READ_ONLY", + null + ], + [ + "info.guardianproject.otr.app.im.permission.IM_SERVICE", + null + ], + [ + "com.google.android.googleapps.permission.GOOGLE_AUTH", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.USE_CREDENTIALS", + null + ], + [ + "android.permission.UPDATE_APP_OPS_STATS", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ], + [ + "android.permission.GET_ACCOUNTS", + null + ], + [ + "info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY", + null + ], + [ + "android.permission.MANAGE_ACCOUNTS", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.ACCESS_WIFI_STATE", + null + ] + ], + "versionCode": 1421001, + "versionName": "14.2.1" + } + ], + "org.torproject.android": [ + { + "added": 1478127600000, + "apkName": "Orbot-v15.2.0-RC-5-arm.apk", + "hash": "51c7e2b6a6de542e0d44f82d89ddf1d3216ec7a28297381ef15b12da2f3246f7", + "hashType": "sha256", + "minSdkVersion": "16", + "nativecode": [ + "arm64-v8a", + "armeabi", + "armeabi-v7a" + ], + "packageName": "org.torproject.android", + "sig": "8bd7e51b479aeba908ff46ada3305a29", + "size": 7600548, + "targetSdkVersion": "23", + "uses-permission": [ + [ + "android.permission.ACCESS_SUPERUSER", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ] + ], + "versionCode": 15205000, + "versionName": "15.2.0-RC-5" + }, + { + "added": 1478214000000, + "apkName": "Orbot-v15.2.0-RC-7-multi.apk", + "hash": "8dc3edf0a9799eb23b5e478e15547e38831b28cc3e88b049aa5f41b7b72e7bf9", + "hashType": "sha256", + "minSdkVersion": "16", + "nativecode": [ + "arm64-v8a", + "armeabi", + "armeabi-v7a", + "x86" + ], + "packageName": "org.torproject.android", + "sig": "8bd7e51b479aeba908ff46ada3305a29", + "size": 12457510, + "targetSdkVersion": "23", + "uses-permission": [ + [ + "android.permission.ACCESS_SUPERUSER", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ] + ], + "versionCode": 15207000, + "versionName": "15.2.0-RC-7-multi" + }, + { + "added": 1478473200000, + "apkName": "Orbot-v15.2.0-RC-8-multi.apk", + "hash": "3758e1b6e6b9a3b7848b253d08d6c0b1b1b3223184da4bd2ba1aaff8cf676357", + "hashType": "sha256", + "minSdkVersion": "16", + "nativecode": [ + "armeabi", + "x86" + ], + "packageName": "org.torproject.android", + "sig": "8bd7e51b479aeba908ff46ada3305a29", + "size": 12296544, + "targetSdkVersion": "23", + "uses-permission": [ + [ + "android.permission.ACCESS_SUPERUSER", + null + ], + [ + "android.permission.INTERNET", + null + ], + [ + "android.permission.ACCESS_NETWORK_STATE", + null + ], + [ + "android.permission.RECEIVE_BOOT_COMPLETED", + null + ] + ], + "versionCode": 15208000, + "versionName": "15.2.0-RC-8-multi" + } + ], + "org.witness.sscphase1": [ + { + "added": 1376863200000, + "apkName": "ObscuraCam-1.2-FINAL.apk", + "hash": "fc4b1e26b09ab79b1ab174e8985b89985a0110f9d97d2b0472e529c85e3a1d89", + "hashType": "sha256", + "minSdkVersion": "8", + "nativecode": [ + "armeabi" + ], + "packageName": "org.witness.sscphase1", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 1728825, + "targetSdkVersion": "8", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.VIBRATE", + null + ] + ], + "versionCode": 25, + "versionName": "1.2-FINAL" + }, + { + "added": 1383174000000, + "apkName": "ObscuraCam-2.0-RC2b.apk", + "hash": "eeea54985c96769524ec82fb1d3599b193a2d20d1f57f3afc4c97b11bd48df8f", + "hashType": "sha256", + "minSdkVersion": "10", + "nativecode": [ + "armeabi" + ], + "packageName": "org.witness.sscphase1", + "sig": "a0eeebb161f946e3516945fae8a92a3e", + "size": 8240221, + "targetSdkVersion": "11", + "uses-permission": [ + [ + "android.permission.READ_EXTERNAL_STORAGE", + null + ], + [ + "android.permission.READ_MEDIA_STORAGE", + null + ], + [ + "android.permission.WRITE_MEDIA_STORAGE", + null + ], + [ + "android.permission.WAKE_LOCK", + null + ], + [ + "android.permission.VIBRATE", + null + ], + [ + "android.permission.WRITE_EXTERNAL_STORAGE", + null + ] + ], + "versionCode": 34, + "versionName": "2.0-RC2b" + } + ], + "info.guardianproject.locationprivacy": [ + { + "added": 1481029454284, + "apkName": "LocationPrivacy-0.3.apk", + "hash": "ec2b2c6e3a99422fbe8229711dfc7b741961c2ba7bc171c745818d8b76fc4d63", + "hashType": "sha256", + "minSdkVersion": "9", + "packageName": "info.guardianproject.locationprivacy", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 1130602, + "targetSdkVersion": "22", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 30, + "versionName": "0.3" + }, + { + "added": 1422486000000, + "apkName": "LocationPrivacy-0.1.apk", + "hash": "130cfcc8b916682d974aa4e13385b47bdc23d07b0de852640563b880aeb61d1f", + "hashType": "sha256", + "minSdkVersion": "8", + "packageName": "info.guardianproject.locationprivacy", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 818384, + "targetSdkVersion": "21", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 10, + "versionName": "0.1" + }, + { + "added": 1481029439166, + "apkName": "LocationPrivacy-0.2.apk", + "hash": "3cad63152ef9b04e1c2b880c286a80c65c083880612aaa36c0c4480b96adfea8", + "hashType": "sha256", + "minSdkVersion": "9", + "packageName": "info.guardianproject.locationprivacy", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 1129409, + "targetSdkVersion": "22", + "uses-permission": [ + [ + "android.permission.INTERNET", + null + ] + ], + "versionCode": 20, + "versionName": "0.2" + } + ], + "info.guardianproject.ripple": [ + { + "added": 1481029466419, + "apkName": "Ripple-0.1.apk", + "hash": "9fd24cbb3552123e6ee119f912f1646dd21cd7a683734a8d502d8b44854a284b", + "hashType": "sha256", + "minSdkVersion": "10", + "packageName": "info.guardianproject.ripple", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 1670285, + "targetSdkVersion": "23", + "versionCode": 2, + "versionName": "0.1" + }, + { + "added": 1481029448654, + "apkName": "Ripple-0.0.apk", + "hash": "025894a5f3a39a288ee60bb6c9cc2c559d395f22fed020d1086308ba12df85a3", + "hashType": "sha256", + "minSdkVersion": "10", + "packageName": "info.guardianproject.ripple", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 1664407, + "targetSdkVersion": "23", + "versionCode": 1, + "versionName": "0.0" + }, + { + "added": 1481029455428, + "apkName": "Ripple-0.2-release.apk", + "hash": "4b14b1b402f0197e1e6ffe2c11e052432fc8a52749f5f02d9cc67799658df239", + "hashType": "sha256", + "minSdkVersion": "10", + "packageName": "info.guardianproject.ripple", + "sig": "d70ac6a02b53ebdd1354ea7af7b9ceee", + "size": 1669315, + "targetSdkVersion": "23", + "versionCode": 75, + "versionName": "0.2" + } + ] + } +} diff --git a/app/src/test/resources/guardianproject_index.xml b/app/src/test/resources/guardianproject_index.xml new file mode 100644 index 000000000..25865f6b6 --- /dev/null +++ b/app/src/test/resources/guardianproject_index.xml @@ -0,0 +1,790 @@ + + + + The official app repository of The Guardian Project. Applications in this repository are official binaries build by the original application developers and signed by the same key as the APKs that are released in the Google Play store. + http://bdf2wcxujkg6qqff.onion/fdroid/repo + https://guardianproject.info/fdroid/repo + https://s3.amazonaws.com/guardianproject/fdroid/repo + + + + + info.guardianproject.cacert + 2013-08-19 + 2013-10-31 + CACertMan + Disable untrusted certificates + info.guardianproject.cacert.4.png + <p>Android 4+ allows you to disable certificates from the system Settings and root isn't required, so try that first if you want to manually mess with the certificates. The app won't work with Android 4+ anyway.</p><p>An app to manage security certificates on your phone also containing a version of the Android CACert keystore derived from Mozilla. If a certificate has recently become untrusted you can either install an update to this app or you can backup and remove certificates by yourself.</p><p>Requires root: Yes, it writes to the system partition. You will need a device that has the ‘grep’ command on it (via busybox: present on most custom ROMs). If the ‘save’ doesn’t work, then you will need to make your /system partition read-write by using a file explorer like <a href="fdroid.app:com.ghostsq.commander">Ghost Commander</a> or via a command in <a href="fdroid.app:jackpal.androidterm">Terminal Emulator</a>.</p> + GPLv3 + Security,GuardianProject + Security + https://guardianproject.info/2011/09/05/cacertman-app-to-address-diginotar-other-bad-cas + https://github.com/guardianproject/cacert + https://github.com/guardianproject/cacert/issues + + 999999999 + root + + 0.0.2.20111012 + 4 + CACertMan-0.0.2-alpha-20111011.apk + 251ebd40ce4a281a2292692707fb1e9c91428994cbad80a416a297db51069eb8 + 172263 + 7 + 7 + 2013-08-19 + a0eeebb161f946e3516945fae8a92a3e + + + 0.0.2-20110906 + 3 + CACertMan-0.0.2-20110906.apk + c217c49abe5134007ceb2623a6189a73fa02af9d2b2bbcc5cbc4cb5da7b36a5d + 170305 + 8 + 8 + 2013-10-31 + a0eeebb161f946e3516945fae8a92a3e + + + + org.witness.informacam.app + 2013-12-11 + 2015-11-03 + CameraV + An InformaCam app to generate verifiable media + org.witness.informacam.app.206.png + <p>An InformaCam app to generate verifiable media.</p> + GPLv3 + Development,GuardianProject + Development + https://guardianproject.info/apps/camerav/ + https://github.com/guardianproject/CameraV + https://dev.guardianproject.info/projects/informacam/issues + 1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk + + 9999999 + + 0.2.6 + 206 + CameraVApp-release-0.2.6.apk + 508f453e26c8c83dba858b53b21d909d549fe5646d01eb198c96c22d8e521e7c + 24123646 + 16 + 21 + 2015-11-03 + d70ac6a02b53ebdd1354ea7af7b9ceee + CAMERA,READ_EXTERNAL_STORAGE,BLUETOOTH_ADMIN,USE_CREDENTIALS,RECORD_AUDIO,VIBRATE,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,ACCESS_FINE_LOCATION,GET_ACCOUNTS,INTERNET,ACCESS_COARSE_LOCATION,READ_PHONE_STATE,KILL_BACKGROUND_PROCESSES,GET_TOP_ACTIVITY_INFO,ACCESS_NETWORK_STATE,BLUETOOTH,WAKE_LOCK + armeabi,armeabi-v7a,x86 + + + 0.2.4 + 204 + CameraV-release-0.2.4.apk + a10eefaed5a12c353525b07e655f6959fe1eb06cd5c549be56afaca6db0c6ce0 + 24062229 + 16 + 21 + 2015-10-02 + d70ac6a02b53ebdd1354ea7af7b9ceee + CAMERA,READ_EXTERNAL_STORAGE,BLUETOOTH_ADMIN,USE_CREDENTIALS,RECORD_AUDIO,VIBRATE,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,ACCESS_FINE_LOCATION,GET_ACCOUNTS,INTERNET,ACCESS_COARSE_LOCATION,READ_PHONE_STATE,KILL_BACKGROUND_PROCESSES,ACCESS_NETWORK_STATE,GET_TASKS,BLUETOOTH,WAKE_LOCK + armeabi,armeabi-v7a,x86 + + + 0.2.2 + 202 + CameraVApp-release-0.2.2.apk + 8b17cbe2a5cb777b49f5ef67a390f9d9d68765c90213ac64f3ca0456860dc9b7 + 24283932 + 16 + 21 + 2015-09-16 + d70ac6a02b53ebdd1354ea7af7b9ceee + CAMERA,READ_EXTERNAL_STORAGE,BLUETOOTH_ADMIN,USE_CREDENTIALS,RECORD_AUDIO,VIBRATE,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,ACCESS_FINE_LOCATION,GET_ACCOUNTS,INTERNET,ACCESS_COARSE_LOCATION,READ_PHONE_STATE,KILL_BACKGROUND_PROCESSES,ACCESS_NETWORK_STATE,GET_TASKS,BLUETOOTH,WAKE_LOCK + armeabi,armeabi-v7a,x86 + + + + info.guardianproject.otr.app.im + 2013-03-19 + 2016-12-06 + ChatSecure + Instant Messaging client with OTR + info.guardianproject.otr.app.im.1423001.png + <p>XMPP (Jabber) client that can do end-to-end encryption using the <a href="http://en.wikipedia.org/wiki/Off-the-Record_Messaging">Off-the-Record Messaging</a> protocol and can anonymize your chats via the <a href="fdroid.app:org.torproject.android">Orbot</a> app (root not required).</p><p>The app used to be called GibberBot.</p> + Apache2 + Internet,GuardianProject + Internet + https://dev.guardianproject.info/projects/gibberbot + https://github.com/guardianproject/Gibberbot + https://dev.guardianproject.info/projects/gibberbot + + 999999999 + + 14.2.3 + 1423001 + ChatSecure-v14.2.3a.apk + 36d7d71c8a2115bdd2bd63bb639af286ee3242cce11cdb5c53378d1a7f35528e + 10502397 + 9 + 21 + 2016-02-03 + a0eeebb161f946e3516945fae8a92a3e + info.guardianproject.otr.app.providers.imps.permission.READ_ONLY,RECEIVE_BOOT_COMPLETED,CHANGE_WIFI_MULTICAST_STATE,READ_EXTERNAL_STORAGE,com.google.android.googleapps.permission.GOOGLE_AUTH,USE_CREDENTIALS,VIBRATE,WRITE_EXTERNAL_STORAGE,GET_ACCOUNTS,ACCESS_WIFI_STATE,UPDATE_APP_OPS_STATS,INTERNET,info.guardianproject.otr.app.im.permission.IM_SERVICE,ACCESS_NETWORK_STATE,MANAGE_ACCOUNTS,info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY,WAKE_LOCK + armeabi,x86 + + + 14.2.2 + 1422001 + ChatSecure-v14.2.2.apk + 9d4620fec0c7837ddffccde7918d7a7db0976fbcd361b96659abd93b5cc0d9e3 + 10502135 + 9 + 21 + 2016-12-06 + a0eeebb161f946e3516945fae8a92a3e + info.guardianproject.otr.app.providers.imps.permission.READ_ONLY,RECEIVE_BOOT_COMPLETED,CHANGE_WIFI_MULTICAST_STATE,READ_EXTERNAL_STORAGE,com.google.android.googleapps.permission.GOOGLE_AUTH,USE_CREDENTIALS,VIBRATE,WRITE_EXTERNAL_STORAGE,GET_ACCOUNTS,ACCESS_WIFI_STATE,UPDATE_APP_OPS_STATS,INTERNET,info.guardianproject.otr.app.im.permission.IM_SERVICE,ACCESS_NETWORK_STATE,MANAGE_ACCOUNTS,info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY,WAKE_LOCK + armeabi,x86 + + + 14.2.1 + 1421001 + ChatSecure-v14.2.1.apk + f82a3a7a823f5540b335743eb1399d0fd1f61bc68958750b5ef6aa0d95ad9a54 + 10463010 + 9 + 21 + 2015-08-24 + a0eeebb161f946e3516945fae8a92a3e + info.guardianproject.otr.app.providers.imps.permission.READ_ONLY,RECEIVE_BOOT_COMPLETED,CHANGE_WIFI_MULTICAST_STATE,READ_EXTERNAL_STORAGE,com.google.android.googleapps.permission.GOOGLE_AUTH,USE_CREDENTIALS,VIBRATE,WRITE_EXTERNAL_STORAGE,GET_ACCOUNTS,ACCESS_WIFI_STATE,UPDATE_APP_OPS_STATS,INTERNET,info.guardianproject.otr.app.im.permission.IM_SERVICE,ACCESS_NETWORK_STATE,MANAGE_ACCOUNTS,info.guardianproject.otr.app.providers.imps.permission.WRITE_ONLY,WAKE_LOCK + armeabi,x86 + + + + info.guardianproject.soundrecorder + 2013-12-13 + 2013-12-13 + ChatSecureVoicePlugin + ChatSecure Voice Messaging + info.guardianproject.soundrecorder.2.png + <p>This is a plugin for <a href="fdroid.app:info.guardianproject.otr.app.im">ChatSecure</a>. It does not have any function on its own. For Your Ears Only... completely private, end-to-end encryption voice message recording, sending, receiving and playback.</p><p> * For use with <a href="fdroid.app:info.guardianproject.otr.app.im">ChatSecure</a>'s encrypted "Off-the-record" data stream * Works over Tor - the ONLY Onion-routed voice messaging system, for total anonymity</p> + SIL Open Font License, MIT License and the CC 3.0 License [CC-By with attribution requirement waived] + Multimedia,Security,GuardianProject + Multimedia + https://guardianproject.info/apps/chatsecure + https://github.com/guardianproject/ChatSecureVoicePlugin + https://dev.guardianproject.info/projects/chatsecure/issues + + 999999999 + + 0.2 + 2 + ChatSecureVoiceMessaging-0.2.apk + abae18cc9cfa62fca5dce072c4c50d41b4fece506967ce9a3e2711cd1031dbee + 394212 + 10 + 10 + 2013-12-13 + a0eeebb161f946e3516945fae8a92a3e + READ_PHONE_STATE,READ_EXTERNAL_STORAGE,RECORD_AUDIO,WRITE_EXTERNAL_STORAGE,WAKE_LOCK + + + + info.guardianproject.checkey + 2014-07-12 + 2015-03-09 + Checkey + Info on local apps + info.guardianproject.checkey.102.png + <p>Checkey is a utility for getting information about the APKs that are installed on your device. Starting with a list of all of the apps that you have installed on your device, it will show you the APK signature with a single touch, and provides links to virustotal.com and androidobservatory.org to easily access the profiles of that APK. It will also let you export the signing certificate and generate ApkSignaturePin pin files for use with the TrustedIntents library.</p> + GPLv3 + Development,GuardianProject + Development + https://dev.guardianproject.info/projects/checkey + https://github.com/guardianproject/checkey + https://dev.guardianproject.info/projects/checkey/issues + 1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk + + 9999999 + + 0.1.2 + 102 + Checkey-0.1.2.apk + 754701dbac52de5ca3930c2393970c03ef9aa07d1456911e9bf254d6014e0645 + 842881 + 8 + 21 + 2015-03-09 + d70ac6a02b53ebdd1354ea7af7b9ceee + INTERNET + + + 0.1.1 + 101 + Checkey-0.1.1.apk + 2d81f339bb69626af42e8868dc6928c9072ebcbae76e1ff5ac8172e78ebe9cdd + 967083 + 8 + 21 + 2015-01-28 + d70ac6a02b53ebdd1354ea7af7b9ceee + INTERNET + + + 0.1 + 1 + Checkey-0.1.apk + a8e3c102d5279a3029d0eebdeda2ffdbe1f8a3493ea7dbdc31a11affc708ee57 + 878679 + 8 + 19 + 2014-07-12 + d70ac6a02b53ebdd1354ea7af7b9ceee + INTERNET + + + + info.guardianproject.courier + 2014-05-14 + 2014-06-26 + Courier + Privacy-aware RSS feed reader + info.guardianproject.courier.15.png + <p>No description available</p> + GPLv3 + Reading,GuardianProject + Reading + + https://github.com/guardianproject/securereader + + + 999999999 + + 0.1.9 + 15 + Courier-0.1.9.apk + bf6566da1f90831887f5bf5605f8d816b1f7f694969459dec599b8bc01a827d3 + 16484753 + 9 + 15 + 2014-06-26 + d70ac6a02b53ebdd1354ea7af7b9ceee + READ_EXTERNAL_STORAGE,BLUETOOTH_ADMIN,VIBRATE,ACCESS_WIFI_STATE,INTERNET,ACCESS_NETWORK_STATE,BLUETOOTH,WRITE_EXTERNAL_STORAGE + armeabi,x86 + + + 0.1.8 + 14 + Courier-0.1.8.apk + e013db095e8da843fae5ac44be6152e51377ee717e5c8a7b6d913d7720566b5a + 16536125 + 9 + 15 + 2014-05-14 + d70ac6a02b53ebdd1354ea7af7b9ceee + READ_EXTERNAL_STORAGE,BLUETOOTH_ADMIN,VIBRATE,ACCESS_WIFI_STATE,INTERNET,ACCESS_NETWORK_STATE,BLUETOOTH,WRITE_EXTERNAL_STORAGE + armeabi,x86 + + + + info.guardianproject.lildebi + 2013-02-06 + 2015-01-26 + Lil' Debi + Run Debian on your phone + info.guardianproject.lildebi.5400.png + <p>Lil' Debi 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.</p><p>Then it has a simple chroot manager that fscks your disk, mounts/unmounts things, starts/stops sshd if you have it installed, etc. You can also then use ‘apt-get’ to install any package that is released for ARM processors. This includes things like a complete real shell, Tor, TraceRouteTCP, iwconfig/ipconfig, and other security and crypto tools. Works well with <a href="fdroid.app:jackpal.androidterm">Terminal Emulator</a>—just run `/debian/shell` to get a Debian shell.</p><p>The aim of Lil’ Debi is to provide a transparent and tightly integrated Debian install on your Android device. It mounts all of your Android partitions in Debian space, so you see a fusion of both systems. It's even possible to have Lil’ Debi launch the normal Debian init start-up scripts when it starts, so that all you need to do is apt-get install and any servers you install will just work.</p><p>Lil' Debi works with as few modifications to the Android system as possible. Currently, it only adds a /bin symlink, and a /debian mount directory. It does not touch /system at all.</p><p>Requires root: Yes, because it needs to run debootstrap, create dirs in /, mount/umount, etc.</p> + GPLv3 + Development,GuardianProject + Development + https://github.com/guardianproject/lildebi/wiki + https://github.com/guardianproject/lildebi + https://github.com/guardianproject/lildebi/issues + 1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk + + 999999999 + root + + 0.5.4 + 5400 + LilDebi-0.5.4-release.apk + 2c490376d8853fae04e79541f5d61e66a42ed0e890208945a11036c4a7b111da + 1876705 + 8 + 20 + 20 + 2015-01-26 + a0eeebb161f946e3516945fae8a92a3e + RECEIVE_BOOT_COMPLETED,READ_EXTERNAL_STORAGE,ACCESS_SUPERUSER,WRITE_EXTERNAL_STORAGE,INTERNET,ACCESS_NETWORK_STATE,jackpal.androidterm.permission.RUN_SCRIPT,WAKE_LOCK + + + 0.5.3 + 5300 + LilDebi-0.5.3-release.apk + 01c5a8e1fd778c141e70633d14f1b69228d6f492961098616e0446c116cf9e44 + 1879560 + 8 + 19 + 2015-01-26 + a0eeebb161f946e3516945fae8a92a3e + RECEIVE_BOOT_COMPLETED,READ_EXTERNAL_STORAGE,ACCESS_SUPERUSER,WRITE_EXTERNAL_STORAGE,INTERNET,ACCESS_NETWORK_STATE,jackpal.androidterm.permission.RUN_SCRIPT,WAKE_LOCK + + + 0.5.2 + 5200 + LilDebi-0.5.2-release.apk + 07fa3dfb690e44eb540942ba2a51718c72351c91a253a56a0c90649f6d8903dd + 1861790 + 8 + 19 + 2014-10-22 + a0eeebb161f946e3516945fae8a92a3e + RECEIVE_BOOT_COMPLETED,READ_EXTERNAL_STORAGE,ACCESS_SUPERUSER,WRITE_EXTERNAL_STORAGE,INTERNET,ACCESS_NETWORK_STATE,jackpal.androidterm.permission.RUN_SCRIPT,WAKE_LOCK + + + + info.guardianproject.locationprivacy + 2015-01-29 + 2016-12-06 + LocationPrivacy + privacy filters for when you are sharing your location + info.guardianproject.locationprivacy.30.png + <p>LocationPrivacy is not really app but rather a set of "Intent Filters" for all of the various ways of sharing location. When you share location from one app, LocationPrivacy offers itself as an option. It then recognizes insecure methods of sharing location, and then converts them to more secure methods. This mostly means that it rewrites URLs to use https, and even to use `geo:` URIs, which can work on fully offline setups. LocationPrivacy mostly works by reading the location information from the URL itself. For many URLs, LocationPrivacy must actually load some of the webpage in order to get the location.</p><p>LocationPrivacy can also serve as a way to redirect all location links to your favorite mapping app. All map apps in Android can view `geo:` URIs, and LocationPrivacy converts many kinds of links to `geo:` URIs, including: Google Maps, OpenStreetMap, Amap, Baidu Map, QQ Map, Nokia HERE, Yandex Maps.</p><p>This was started as part of the T2 Panic work, since sharing location is so often a part of panic apps. Follow our progress here: https://guardianproject.info/tag/panic</p><p>Don’t see your language? Join us and help translate the app: https://www.transifex.com/projects/p/locationprivacy</p> + GPLv3 + Navigation,Security,GuardianProject + Navigation + https://dev.guardianproject.info/projects/panic + https://github.com/guardianproject/LocationPrivacy + https://dev.guardianproject.info/projects/panic/issues + 1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk + + 9999999 + + 0.3 + 30 + LocationPrivacy-0.3.apk + ec2b2c6e3a99422fbe8229711dfc7b741961c2ba7bc171c745818d8b76fc4d63 + 1130602 + 9 + 22 + 2016-12-06 + d70ac6a02b53ebdd1354ea7af7b9ceee + INTERNET + + + 0.2 + 20 + LocationPrivacy-0.2.apk + 3cad63152ef9b04e1c2b880c286a80c65c083880612aaa36c0c4480b96adfea8 + 1129409 + 9 + 22 + 2016-12-06 + d70ac6a02b53ebdd1354ea7af7b9ceee + INTERNET + + + 0.1 + 10 + LocationPrivacy-0.1.apk + 130cfcc8b916682d974aa4e13385b47bdc23d07b0de852640563b880aeb61d1f + 818384 + 8 + 21 + 2015-01-29 + d70ac6a02b53ebdd1354ea7af7b9ceee + INTERNET + + + + info.guardianproject.notepadbot + 2013-01-16 + 2014-03-10 + NoteCipher + Notepad with lock + info.guardianproject.notepadbot.12.png + <p>Simple app for taking notes that encrypts everything behind a password.</p><p>Status: Beta.</p> + Apache2 + Office,GuardianProject + Office + https://guardianproject.info + https://github.com/guardianproject/notecipher + https://github.com/guardianproject/notecipher/issues + + 999999999 + + 0.1 + 12 + NoteCipher-beta-0.1.apk + b560a3d6364c32990ea7505f53b019f64fde597d67513f41a50e7d034af48caa + 7321123 + 10 + 19 + 2014-03-10 + a0eeebb161f946e3516945fae8a92a3e + VIBRATE,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + armeabi,x86 + + + 0.0.7.1 + 11 + NoteCipher-0.0.7.1.apk + da518f13206d2218234bfcc83205b7b2b81ec67a4cc448f818c617332235e700 + 3729342 + 11 + 17 + 2013-10-31 + a0eeebb161f946e3516945fae8a92a3e + READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + armeabi + + + 0.0.7 + 10 + NoteCipher-0.0.7.apk + 8fa7536a87634c6b3441053c4f16315e4fd5aa6ef672a0026a594c107308d7bf + 3731119 + 7 + 17 + 2013-01-16 + a0eeebb161f946e3516945fae8a92a3e + READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + armeabi + + + + org.witness.sscphase1 + 2013-08-19 + 2013-10-31 + ObscuraCam + A camera app that keeps certain information private + org.witness.sscphase1.34.png + <p>Ever capture someone in a photo or video, then realize they may not want to be in it? Not comfortable posting a friend, family member or child’s face on the internet? Worried about the geolocation data in the picture giving away private hideaway? Tired of Facebook, Google and other sites “auto detecting” faces in your photos? Then this is for you, giving you the power to better protect the identity of those captures in your photos, before you post them online.</p><p>Take a picture or load a photo or video from the Gallery, and ObscuraCam will automatically detect faces that you can pixelate, redact (blackout) or protect with funny nose and glasses. You can also invert pixelate, so that only the person you select is visible, and no one in the background can be recognized.</p><p>This app will also remove all identifying data stored in photos including GPS location data and phone make &amp; model. You can save the protected photo back to the Gallery, or share it directly to Facebook, Twitter or any other “Share” enabled app.</p> + GPLv3 + Multimedia,Security,GuardianProject + Multimedia + https://guardianproject.info/apps/obscuracam + https://github.com/guardianproject/obscuracam + https://github.com/guardianproject/obscuracam/issues + + 999999999 + + 2.0-RC2b + 34 + ObscuraCam-2.0-RC2b.apk + eeea54985c96769524ec82fb1d3599b193a2d20d1f57f3afc4c97b11bd48df8f + 8240221 + 10 + 11 + 2013-10-31 + a0eeebb161f946e3516945fae8a92a3e + READ_EXTERNAL_STORAGE,READ_MEDIA_STORAGE,WRITE_MEDIA_STORAGE,VIBRATE,WAKE_LOCK,WRITE_EXTERNAL_STORAGE + armeabi + + + 1.2-FINAL + 25 + ObscuraCam-1.2-FINAL.apk + fc4b1e26b09ab79b1ab174e8985b89985a0110f9d97d2b0472e529c85e3a1d89 + 1728825 + 8 + 8 + 2013-08-19 + a0eeebb161f946e3516945fae8a92a3e + VIBRATE,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + armeabi + + + + org.torproject.android + 2013-07-22 + 2016-12-06 + Orbot + Tor (anonymity) client + org.torproject.android.15208000.png + <p>Tor is both software and an open network that helps you defend against network surveillance that threatens personal freedom and privacy, confidential business activities and relationships.</p><p>Orbot allows access to Tor by accessing a local SOCKS or HTTP proxy. On a rooted device, the proxying can be completely transparent i.e. the app that accesses the network need not be aware of the proxy's existence; you can choose which apps go via the proxy in the settings.</p><p>If you don't have root access, there are some apps that are designed to work closely with tor or allow proxied connections: <a href="fdroid.app:info.guardianproject.otr.app.im">ChatSecure</a>, <a href="fdroid.app:info.guardianproject.browser">Orweb</a> and <a href="fdroid.app:org.mariotaku.twidere">Twidere</a>. There is also a proxy configurator addon for <a href="fdroid.app:org.mozilla.firefox">org.mozilla.firefox</a> called <a href="https://github.com/guardianproject/ProxyMob/downloads">ProxyMob</a> (not yet available from the Mozilla addon site).</p><p>Requires root: No, but you will need to use apps that allow proxies if root is not granted.</p> + NewBSD + Security,Internet,GuardianProject + Security + http://www.torproject.org/docs/android.html.en + https://gitweb.torproject.org/orbot.git + https://dev.guardianproject.info/projects/orbot/issues + https://www.torproject.org/donate/donate.html.en + 5649 + + 999999999 + + 15.2.0-RC-8-multi + 15208000 + Orbot-v15.2.0-RC-8-multi.apk + 3758e1b6e6b9a3b7848b253d08d6c0b1b1b3223184da4bd2ba1aaff8cf676357 + 12296544 + 16 + 23 + 2016-11-07 + 8bd7e51b479aeba908ff46ada3305a29 + ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,INTERNET,RECEIVE_BOOT_COMPLETED + armeabi,x86 + + + 15.2.0-RC-7-multi + 15207000 + Orbot-v15.2.0-RC-7-multi.apk + 8dc3edf0a9799eb23b5e478e15547e38831b28cc3e88b049aa5f41b7b72e7bf9 + 12457510 + 16 + 23 + 2016-11-04 + 8bd7e51b479aeba908ff46ada3305a29 + ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,INTERNET,RECEIVE_BOOT_COMPLETED + arm64-v8a,armeabi,armeabi-v7a,x86 + + + 15.2.0-RC-5 + 15205000 + Orbot-v15.2.0-RC-5-arm.apk + 51c7e2b6a6de542e0d44f82d89ddf1d3216ec7a28297381ef15b12da2f3246f7 + 7600548 + 16 + 23 + 2016-11-03 + 8bd7e51b479aeba908ff46ada3305a29 + ACCESS_NETWORK_STATE,ACCESS_SUPERUSER,INTERNET,RECEIVE_BOOT_COMPLETED + arm64-v8a,armeabi,armeabi-v7a + + + + info.guardianproject.orfox + 2016-09-24 + 2016-12-06 + Orfox + Orfox: Tor Browser for Android + info.guardianproject.orfox.4.png + <p>Orfox is the most privacy-enhancing web browser on Android, for visiting any website, even if it’s normally censored, monitored, or on the hidden web. It is a port of the desktop Tor Browser to the Android version of Firefox.</p><p>Orfox is a companion browser to <a href="fdroid.app:org.torproject.android">Orbot</a>, the port of Tor to Android. Orbot anonymizes internet traffic by routing it through many different stages and you must have that enabled first, though root isn't needed. Orfox disables certain other browser features that could be used to identify you.</p><p>Orfox replaces <a href="fdroid.app:info.guardianproject.browser">Orweb</a> as your private browser.</p> + MPL + Internet,Security,GuardianProject + Internet + + https://github.com/guardianproject/orfox + https://dev.guardianproject.info/projects/orfox/issues?set_filter=1 + + 999999999 + + Fennec-45.5.1esr/TorBrowser-6.5-1/Orfox-1.2.1 + 4 + Orfox-1.2.1-TorBrowser-6.5-Fennec45.5.1-build2.apk + d43032e79c7c31cabb194b8c1c4b14fbf73dd2cfda958ba415879ddf2f38ace2 + 35273126 + 9 + 22 + 2016-12-06 + d70ac6a02b53ebdd1354ea7af7b9ceee + info.guardianproject.orfox.permissions.FORMHISTORY_PROVIDER,info.guardianproject.orfox.permissions.PASSWORD_PROVIDER,READ_EXTERNAL_STORAGE,VIBRATE,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,DOWNLOAD_WITHOUT_NOTIFICATION,INTERNET,com.android.launcher.permission.UNINSTALL_SHORTCUT,info.guardianproject.orfox.permissions.BROWSER_PROVIDER,com.android.browser.permission.READ_HISTORY_BOOKMARKS,com.android.launcher.permission.INSTALL_SHORTCUT,ACCESS_NETWORK_STATE,WAKE_LOCK + armeabi-v7a + + + Fennec-45.4.0esr/TorBrowser-6.5-1/Orfox-1.2 + 3 + Orfox-1.2-TorBrowser-6.5-Fennec45.4.0.apk + 9b5f6614b94a47ae561e8c974d42056ba6cb6da520766deda09aec3699aeff94 + 35242066 + 9 + 22 + 2016-09-24 + d70ac6a02b53ebdd1354ea7af7b9ceee + info.guardianproject.orfox.permissions.FORMHISTORY_PROVIDER,info.guardianproject.orfox.permissions.PASSWORD_PROVIDER,READ_EXTERNAL_STORAGE,VIBRATE,WRITE_EXTERNAL_STORAGE,CHANGE_WIFI_STATE,ACCESS_WIFI_STATE,DOWNLOAD_WITHOUT_NOTIFICATION,INTERNET,com.android.launcher.permission.UNINSTALL_SHORTCUT,info.guardianproject.orfox.permissions.BROWSER_PROVIDER,com.android.browser.permission.READ_HISTORY_BOOKMARKS,com.android.launcher.permission.INSTALL_SHORTCUT,ACCESS_NETWORK_STATE,WAKE_LOCK + armeabi-v7a + + + + info.guardianproject.browser + 2012-10-22 + 2015-11-26 + Orweb + Privacy-enhanced browser + info.guardianproject.browser.7010.png + <p>Orweb is a companion browser to <a href="fdroid.app:org.torproject.android">Orbot</a>, the port of Tor to Android.</p><p>Orbot anonymizes internet traffic by routing it through many different stages and you must have that enabled first, though root isn't needed. Orweb disables certain other browser features that could be used to identify you.</p> + GPL + Internet,Security,GuardianProject + Internet + https://guardianproject.info/apps/orweb + https://github.com/guardianproject/orweb + https://dev.guardianproject.info/projects/orweb/issues?set_filter=1 + + 999999999 + + 0.7.1 + 7010 + Orweb-0.7.1.apk + 949d65d6e8a1eadd0aa626bdc7c5a3e2b0dbe5a38dea1d725cce2a34ec84f0d4 + 2424394 + 9 + 21 + 2015-11-26 + a0eeebb161f946e3516945fae8a92a3e + READ_EXTERNAL_STORAGE,INTERNET,WRITE_EXTERNAL_STORAGE + + + 0.7 + 28 + Orweb-release-0.7.apk + 763541f43f5dc136744b4361fe67d36f25cc036526d6c3e934287d72d1b411ab + 1244875 + 9 + 18 + 2014-11-13 + a0eeebb161f946e3516945fae8a92a3e + READ_EXTERNAL_STORAGE,INTERNET,WRITE_EXTERNAL_STORAGE + + + 0.6.1 + 27 + Orweb-release-0.6.1.apk + 103f4a98fa282923c07e445b2a383e946b6c15e10ed08005af3d0743249a0359 + 931433 + 9 + 19 + 2014-06-30 + a0eeebb161f946e3516945fae8a92a3e + READ_EXTERNAL_STORAGE,INTERNET,WRITE_EXTERNAL_STORAGE + + + + info.guardianproject.pixelknot + 2013-02-26 + 2016-12-06 + PixelKnot + Hide messages inside files + info.guardianproject.pixelknot.100.png + <p>Image steganography app with old school F5 steganography</p> + GPLv3 + Office,GuardianProject + Office + https://guardianproject.info + https://github.com/guardianproject/PixelKnot + https://github.com/guardianproject/PixelKnot/issues + + 999999999 + + 1.0.0 + 100 + PixelKnot-release-1.0.0.apk + f97557cf7ec81ade50c308c5552dc6dc827d0e02ce90f84b1df6b7477d9f5a39 + 1983586 + 17 + 25 + 2016-12-06 + a0eeebb161f946e3516945fae8a92a3e + VIBRATE,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + + + arm64-v8a,armeabi,armeabi-v7a,mips,mips64,x86,x86_64 + + + 0.3.3 + 6 + PixelKnot-release-0.3.3.apk + 6beede8519a9e87ba8edaa5a76f203cfefd5f39eb911e789031cc6e911714b89 + 4751233 + 14 + 17 + 2015-06-26 + a0eeebb161f946e3516945fae8a92a3e + CAMERA,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + armeabi + + + 0.3.1 + 4 + PixelKnot-release-0.3.1.apk + a3101fe8a2d47ab205cb00459fa62c639a6fac4538f6cd9d06eb48d2965c4d21 + 3976822 + 9 + 17 + 2013-07-22 + a0eeebb161f946e3516945fae8a92a3e + CAMERA,READ_EXTERNAL_STORAGE,WRITE_EXTERNAL_STORAGE + armeabi + + + + info.guardianproject.ripple + 2016-12-06 + 2016-12-06 + Ripple + Trigger apps to protect your privacy when in anxious or panic situations + info.guardianproject.ripple.75.png + <p>Ripple is a "panic button" that can send it's trigger message to any app that is a "panic responder". Such apps can do things like lock, disguise themselves, delete private data, send an emergency message, and more. It is meant for situations where there is time to react, but where users need to be sure it is not mistakenly set off.</p><p>This is a BETA version of this app! We are working now to add support to as many other apps as possible. ChatSecure, Orweb, Umbrella, and Zom already have support, these apps are coming soon: Courier, PanicButton, OpenKeychain, Orfox, SMSSecure, and StoryMaker.</p><p>Here are two example scenarios:</p><ul><li> An organization gets regularly raided by the security forces, who search all of the computers and mobile devices on the premises. The organization usually has at least a minute or two of warning before a raid starts. They need a very reliable way to trigger wiping all of the data from the sensitive apps.</li></ul><ul><li> An aid worker has lots of sensitive data about people on their device. They regularly sync that data up with a secure, central database. Occasionally, the aid worker has to leave the country on very short notice. The border guards regularly download the entire contents of mobile devices of people crossing through. While waiting in line at the border, the aid worker sees the border guards seizing people's devices, and then remembers all the data on the device, so she unlocks her phone and hits the wipe trigger, which wipes all sensitive apps from the device. When the aid worker returns to the central office, the device is again synced up with the central database.</li></ul><p>This was started as part of the T2 Panic work, since sharing location is so often a part of panic apps. Follow our progress here:</p><p>★ <a href="https://guardianproject.info/tag/panic">https://guardianproject.info/tag/panic</a> ★ <a href="https://dev.guardianproject.info/projects/panic">https://dev.guardianproject.info/projects/panic</a> Don’t see your language? Join us and help translate the app: <a href="https://www.transifex.com/projects/p/rippleapp">https://www.transifex.com/projects/p/rippleapp</a></p><p>==Learn More==</p><p>★ ABOUT US: Guardian Project is a group of developers that make secure mobile apps and open-source code for a better tomorrow ★ OUR WEBSITE: <a href="https://GuardianProject.info">https://GuardianProject.info</a> ★ ON TWITTER: <a href="https://twitter.com/guardianproject">https://twitter.com/guardianproject</a> ★ FREE SOFTWARE: Ripple is free software. You can take a look at our source code, or contribute to help make Ripple even better: <a href="https://github.com/guardianproject/Ripple">https://github.com/guardianproject/Ripple</a> ★ MESSAGE US: Are we missing your favorite feature? Found an annoying bug? Please tell us! We’d love to hear from you. Send us an email: support@guardianproject.info or find us in our chat room <a href="https://guardianproject.info/contact">https://guardianproject.info/contact</a></p> + GPLv3 + Navigation,Security,GuardianProject + Navigation + https://dev.guardianproject.info/projects/panic + https://github.com/guardianproject/ripple + https://dev.guardianproject.info/projects/panic/issues + 1Fi5xUHiAPRKxHvyUGVFGt9extBe8Srdbk + + 9999999 + + 0.2 + 75 + Ripple-0.2-release.apk + 4b14b1b402f0197e1e6ffe2c11e052432fc8a52749f5f02d9cc67799658df239 + 1669315 + 10 + 23 + 2016-12-06 + d70ac6a02b53ebdd1354ea7af7b9ceee + + + 0.1 + 2 + Ripple-0.1.apk + 9fd24cbb3552123e6ee119f912f1646dd21cd7a683734a8d502d8b44854a284b + 1670285 + 10 + 23 + 2016-12-06 + d70ac6a02b53ebdd1354ea7af7b9ceee + + + 0.0 + 1 + Ripple-0.0.apk + 025894a5f3a39a288ee60bb6c9cc2c559d395f22fed020d1086308ba12df85a3 + 1664407 + 10 + 23 + 2016-12-06 + d70ac6a02b53ebdd1354ea7af7b9ceee + + + + info.guardianproject.chatsecure.emoji.core + 2013-12-02 + 2013-12-02 + StickerPack + ChatSecure Open Emoji Plugin + info.guardianproject.chatsecure.emoji.core.1.png + <p>Plugin for <a href="fdroid.app:info.guardianproject.otr.app.im">ChatSecure</a> to support for core emoji input and display. Based on "Phantom Open Emoji" project.</p> + SIL Open Font License, MIT License and the CC 3.0 License [CC-By with attribution requirement waived] + Multimedia,Security,GuardianProject + Multimedia + https://guardianproject.info/apps/chatsecure + https://github.com/guardianproject/ChatSecureVoicePlugin + https://dev.guardianproject.info/projects/chatsecure/issues + + 999999999 + + 1.0 + 1 + ChatSecurePluginOpenEmoji-release-v1.apk + 131c1ebaf795c3f053701285699f0b7e517de1c7fdba56e247b1ec31766b2808 + 1814271 + 8 + 17 + 2013-12-02 + a0eeebb161f946e3516945fae8a92a3e + + + diff --git a/app/src/test/resources/testy.at.or.at_index-v1.jar b/app/src/test/resources/testy.at.or.at_index-v1.jar new file mode 100644 index 0000000000000000000000000000000000000000..11cfd5f2cd13106fae484f1f69334d19399f4322 GIT binary patch literal 24734 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 literal 0 HcmV?d00001 diff --git a/app/src/test/resources/testy.at.or.at_no-.RSA_index-v1.jar b/app/src/test/resources/testy.at.or.at_no-.RSA_index-v1.jar new file mode 100644 index 0000000000000000000000000000000000000000..9b3267a73ee89642d1d8da46fd7b73ef97c73f3c GIT binary patch literal 22726 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 R!QXA%yWVm){xbf%`VWXF0+9d! literal 0 HcmV?d00001 diff --git a/app/src/test/resources/testy.at.or.at_no-.SF_index-v1.jar b/app/src/test/resources/testy.at.or.at_no-.SF_index-v1.jar new file mode 100644 index 0000000000000000000000000000000000000000..113a17e553895da12997d78cfdd8f90b2aa16516 GIT binary patch literal 24353 zcmV)?K!U$eO9KQH000OG0A{3!No*W@jDr9G0EYko02BZK08K?yK`lv6MlVf4PDw^Z zQ&cWZM)OU~%S=lxF3}B3Eh^5;&$Ci6)HC4aaxO|uEJ;n#b*cmjnCltD8yXoZX!sW; zCg-FoIOi7?qa`AHcCFZ7DDP-oQq*myb8R}&f=jZWq1$#Ie>bhj60}Z!Q zaPiakaWyVA^7ryFcL{d&it_LaH_oig3GsKe1(^T@6aWAS2mofJh)LnOPira% z0040Z000pH002!zR6#9CPDU?NPgX%LQd2>VlzBK5h#$ty!3<)Q2@$z#Fq&!HQf_h= zF^))%BIHVx72~Ket{GQ38Vq(a%0#mmve-yD*42mxv*V@^Q8|Bp&$G|&{(gV$pWpX+ z-}n2^`+QJ1NH8D2N{VI5Hz5E7Sb~FiqHqv5AOL_CMDg?SstSXElDs@9!M{y_5*&C2 zg#-VA!U5lwfPerX5NxU8u!R!(%L5QRh{&NuP{Mqm%V0rKh&j?U{8oT3TIitYKmmz@ zBW^``qh!Q|&{`;+GZ-`mgGOt)i3@3HpwKAYKhJ+tfdk6_^D%&z2ZRH{cn)*{APxxN znPd;huG8c%JRYC4qnxXFIG8&dwdLEix%%Ygo z4{*gFqe^*86^nYcK4h-%?RQSI9mhCgdeKqiW}n)|>CZO!3o3#nlNc)dy=MJkC$?`Y<18}k$6Wp2t%r9E!qNL19avhY@i zt-G!cIRlIW%h{LY0{2r-rCZ$Yog{=0dkub%08tlOS#hRHsFqWUUv%*%+R7n7|h}1?f6%6Q-CcgHS8if1=Ay6dvA1Bq98vDz7S~SHs-JCF z_tioOYo+X�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:)u) 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 literal 0 HcmV?d00001 diff --git a/app/src/test/resources/testy.at.or.at_no-MANIFEST.MF_index-v1.jar b/app/src/test/resources/testy.at.or.at_no-MANIFEST.MF_index-v1.jar new file mode 100644 index 0000000000000000000000000000000000000000..feee0f85da78c2745c6968ee41b9e7f09cb0fe9e GIT binary patch literal 24423 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 OTlwbHxG~QX5&Z|qQ!!uw literal 0 HcmV?d00001