Merge branch 'push-install-uninstall-requetss' into 'master'
Push requests for install/uninstall This is the first basic implementation of the idea of "push requests" from the server. This implements two requests that the server can ask of all clients: `install` and `uninstall`. A default repository in the client can be marked to `ignore` or `always` accept push requests in this merge request. There is also the sketch of a third option called `prompt` which gives the user the standard "Just Once/Always" choice; that is not yet implemented. This allows central management of app installs/uninstalls for a pool of devices, as well as other ideas. A use case for this feature is documented here: https://f-droid.org/wiki/page/Whitelabel_Builds See merge request !386
This commit is contained in:
commit
723be967ca
@ -1,18 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Blue Jay Wireless
|
||||
* Copyright (C) 2015-2016 Daniel Martí <mvdan@mvdan.cc>
|
||||
* Copyright (C) 2014-2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
* Copyright (C) 2014-2016 Peter Serwylo <peter@serwylo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.ApkProvider;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.AppProvider;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoPersister;
|
||||
import org.fdroid.fdroid.data.RepoProvider;
|
||||
import org.fdroid.fdroid.data.RepoPushRequest;
|
||||
import org.fdroid.fdroid.data.Schema.RepoTable;
|
||||
import org.fdroid.fdroid.installer.InstallManagerService;
|
||||
import org.fdroid.fdroid.installer.InstallerService;
|
||||
import org.fdroid.fdroid.net.Downloader;
|
||||
import org.fdroid.fdroid.net.DownloaderFactory;
|
||||
import org.xml.sax.InputSource;
|
||||
@ -27,6 +57,7 @@ import java.net.URL;
|
||||
import java.security.CodeSigner;
|
||||
import java.security.cert.Certificate;
|
||||
import java.security.cert.X509Certificate;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.jar.JarEntry;
|
||||
@ -37,12 +68,15 @@ import javax.xml.parsers.SAXParser;
|
||||
import javax.xml.parsers.SAXParserFactory;
|
||||
|
||||
/**
|
||||
* Responsible for updating an individual repository. This will:
|
||||
* * Download the index.jar
|
||||
* * Verify that it is signed correctly and by the correct certificate
|
||||
* * Parse the index.xml from the .jar file
|
||||
* * Save the resulting repo, apps, and apks to the database.
|
||||
*
|
||||
* Updates the local database with a repository's app/apk metadata and verifying
|
||||
* the JAR signature on the file received from the repository. As an overview:
|
||||
* <ul>
|
||||
* <li>Download the {@code index.jar}
|
||||
* <li>Verify that it is signed correctly and by the correct certificate
|
||||
* <li>Parse the {@code index.xml} that is in {@code index.jar}
|
||||
* <li>Save the resulting repo, apps, and apks to the database.
|
||||
* <li>Process any push install/uninstall requests included in the repository
|
||||
* </ul>
|
||||
* <b>WARNING</b>: this class is the central piece of the entire security model of
|
||||
* FDroid! Avoid modifying it when possible, if you absolutely must, be very,
|
||||
* very careful with the changes that you are making!
|
||||
@ -66,7 +100,10 @@ public class RepoUpdater {
|
||||
private String cacheTag;
|
||||
private X509Certificate signingCertFromJar;
|
||||
|
||||
@NonNull private final RepoPersister persister;
|
||||
@NonNull
|
||||
private final RepoPersister persister;
|
||||
|
||||
private final List<RepoPushRequest> repoPushRequestList = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Updates an app repo as read out of the database into a {@link Repo} instance.
|
||||
@ -148,6 +185,7 @@ public class RepoUpdater {
|
||||
// successful download, then we will have a file ready to use:
|
||||
cacheTag = downloader.getCacheTag();
|
||||
processDownloadedFile(downloader.outputFile);
|
||||
processRepoPushRequests();
|
||||
}
|
||||
}
|
||||
|
||||
@ -170,6 +208,11 @@ public class RepoUpdater {
|
||||
throw new RuntimeException("Error while saving repo details to database.", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveRepoPushRequest(RepoPushRequest repoPushRequest) {
|
||||
repoPushRequestList.add(repoPushRequest);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@ -188,7 +231,7 @@ public class RepoUpdater {
|
||||
JarFile jarFile = new JarFile(downloadedFile, true);
|
||||
JarEntry indexEntry = (JarEntry) jarFile.getEntry("index.xml");
|
||||
indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry),
|
||||
processXmlProgressListener, new URL(repo.address), (int) indexEntry.getSize());
|
||||
processXmlProgressListener, new URL(repo.address), (int) indexEntry.getSize());
|
||||
|
||||
// Process the index...
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
@ -396,4 +439,57 @@ public class RepoUpdater {
|
||||
throw new SigningException(repo, "Signing certificate does not match!");
|
||||
}
|
||||
|
||||
/**
|
||||
* Server index XML can include optional {@code install} and {@code uninstall}
|
||||
* requests. This processes those requests, figuring out whether the client
|
||||
* should always accept, prompt the user, or ignore those requests on a
|
||||
* per repo basis.
|
||||
*/
|
||||
private void processRepoPushRequests() {
|
||||
PackageManager pm = context.getPackageManager();
|
||||
|
||||
for (RepoPushRequest repoPushRequest : repoPushRequestList) {
|
||||
String packageName = repoPushRequest.packageName;
|
||||
PackageInfo packageInfo = null;
|
||||
try {
|
||||
packageInfo = pm.getPackageInfo(packageName, 0);
|
||||
} catch (PackageManager.NameNotFoundException e) {
|
||||
// ignored
|
||||
}
|
||||
if (RepoPushRequest.INSTALL.equals(repoPushRequest.request)) {
|
||||
ContentResolver cr = context.getContentResolver();
|
||||
App app = AppProvider.Helper.findByPackageName(cr, packageName);
|
||||
if (app == null) {
|
||||
Utils.debugLog(TAG, packageName + " not in local database, ignoring request to"
|
||||
+ repoPushRequest.request);
|
||||
continue;
|
||||
}
|
||||
int versionCode;
|
||||
if (repoPushRequest.versionCode == null) {
|
||||
versionCode = app.suggestedVersionCode;
|
||||
} else {
|
||||
versionCode = repoPushRequest.versionCode;
|
||||
}
|
||||
if (packageInfo != null && versionCode == packageInfo.versionCode) {
|
||||
Utils.debugLog(TAG, repoPushRequest + " already installed, ignoring");
|
||||
} else {
|
||||
Apk apk = ApkProvider.Helper.find(context, packageName, versionCode);
|
||||
InstallManagerService.queue(context, app, apk);
|
||||
}
|
||||
} else if (RepoPushRequest.UNINSTALL.equals(repoPushRequest.request)) {
|
||||
if (packageInfo == null) {
|
||||
Utils.debugLog(TAG, "ignoring request, not installed: " + repoPushRequest);
|
||||
continue;
|
||||
}
|
||||
if (repoPushRequest.versionCode == null
|
||||
|| repoPushRequest.versionCode == packageInfo.versionCode) {
|
||||
InstallerService.uninstall(context, packageName);
|
||||
} else {
|
||||
Utils.debugLog(TAG, "ignoring request based on versionCode:" + repoPushRequest);
|
||||
}
|
||||
} else {
|
||||
Utils.debugLog(TAG, "Unknown Repo Push Request: " + repoPushRequest.request);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@ import android.support.annotation.Nullable;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoPushRequest;
|
||||
import org.xml.sax.Attributes;
|
||||
import org.xml.sax.SAXException;
|
||||
import org.xml.sax.helpers.DefaultHandler;
|
||||
@ -64,6 +65,8 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
void receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp);
|
||||
|
||||
void receiveApp(App app, List<Apk> packages);
|
||||
|
||||
void receiveRepoPushRequest(RepoPushRequest repoPushRequest);
|
||||
}
|
||||
|
||||
private final IndexReceiver receiver;
|
||||
@ -250,6 +253,10 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
receiver.receiveRepo(repoName, repoDescription, repoSigningCert, repoMaxAge, repoVersion, repoTimestamp);
|
||||
}
|
||||
|
||||
private void onRepoPushRequestParsed(RepoPushRequest repoPushRequest) {
|
||||
receiver.receiveRepoPushRequest(repoPushRequest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startElement(String uri, String localName, String qName,
|
||||
Attributes attributes) throws SAXException {
|
||||
@ -262,6 +269,15 @@ public class RepoXMLHandler extends DefaultHandler {
|
||||
repoName = cleanWhiteSpace(attributes.getValue("", "name"));
|
||||
repoDescription = cleanWhiteSpace(attributes.getValue("", "description"));
|
||||
repoTimestamp = parseLong(attributes.getValue("", "timestamp"), 0);
|
||||
} else if (RepoPushRequest.INSTALL.equals(localName)
|
||||
|| RepoPushRequest.UNINSTALL.equals(localName)) {
|
||||
if (repo.pushRequests == Repo.PUSH_REQUEST_ACCEPT_ALWAYS) {
|
||||
RepoPushRequest r = new RepoPushRequest(
|
||||
localName,
|
||||
attributes.getValue("packageName"),
|
||||
attributes.getValue("versionCode"));
|
||||
onRepoPushRequestParsed(r);
|
||||
}
|
||||
} else if ("application".equals(localName) && curapp == null) {
|
||||
curapp = new App();
|
||||
curapp.packageName = attributes.getValue("", "id");
|
||||
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Blue Jay Wireless
|
||||
* Copyright (C) 2015-2016 Daniel Martí <mvdan@mvdan.cc>
|
||||
* Copyright (C) 2015 Christian Morgner
|
||||
* Copyright (C) 2014-2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
* Copyright (C) 2013-2016 Peter Serwylo <peter@serwylo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
@ -23,6 +46,8 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
|
||||
private static final String TAG = "DBHelper";
|
||||
|
||||
public static final int REPO_XML_ARG_COUNT = 8;
|
||||
|
||||
private static final String DATABASE_NAME = "fdroid";
|
||||
|
||||
private static final String CREATE_TABLE_REPO = "create table "
|
||||
@ -42,7 +67,8 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
+ RepoTable.Cols.IS_SWAP + " integer boolean default 0,"
|
||||
+ RepoTable.Cols.USERNAME + " string, "
|
||||
+ RepoTable.Cols.PASSWORD + " string,"
|
||||
+ RepoTable.Cols.TIMESTAMP + " integer not null default 0"
|
||||
+ RepoTable.Cols.TIMESTAMP + " integer not null default 0, "
|
||||
+ RepoTable.Cols.PUSH_REQUESTS + " integer not null default " + Repo.PUSH_REQUEST_IGNORE
|
||||
+ ");";
|
||||
|
||||
static final String CREATE_TABLE_APK =
|
||||
@ -120,7 +146,7 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
+ " );";
|
||||
private static final String DROP_TABLE_INSTALLED_APP = "DROP TABLE " + InstalledAppTable.NAME + ";";
|
||||
|
||||
private static final int DB_VERSION = 61;
|
||||
private static final int DB_VERSION = 62;
|
||||
|
||||
private final Context context;
|
||||
|
||||
@ -229,55 +255,30 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
db.execSQL(CREATE_TABLE_APP_PREFS);
|
||||
ensureIndexes(db);
|
||||
|
||||
insertRepo(
|
||||
db,
|
||||
context.getString(R.string.fdroid_repo_name),
|
||||
context.getString(R.string.fdroid_repo_address),
|
||||
context.getString(R.string.fdroid_repo_description),
|
||||
context.getString(R.string.fdroid_repo_pubkey),
|
||||
context.getResources().getInteger(R.integer.fdroid_repo_version),
|
||||
context.getResources().getInteger(R.integer.fdroid_repo_inuse),
|
||||
context.getResources().getInteger(R.integer.fdroid_repo_priority)
|
||||
);
|
||||
|
||||
insertRepo(
|
||||
db,
|
||||
context.getString(R.string.fdroid_archive_name),
|
||||
context.getString(R.string.fdroid_archive_address),
|
||||
context.getString(R.string.fdroid_archive_description),
|
||||
context.getString(R.string.fdroid_archive_pubkey),
|
||||
context.getResources().getInteger(R.integer.fdroid_archive_version),
|
||||
context.getResources().getInteger(R.integer.fdroid_archive_inuse),
|
||||
context.getResources().getInteger(R.integer.fdroid_archive_priority)
|
||||
);
|
||||
|
||||
insertRepo(
|
||||
db,
|
||||
context.getString(R.string.guardianproject_repo_name),
|
||||
context.getString(R.string.guardianproject_repo_address),
|
||||
context.getString(R.string.guardianproject_repo_description),
|
||||
context.getString(R.string.guardianproject_repo_pubkey),
|
||||
context.getResources().getInteger(R.integer.guardianproject_repo_version),
|
||||
context.getResources().getInteger(R.integer.guardianproject_repo_inuse),
|
||||
context.getResources().getInteger(R.integer.guardianproject_repo_priority)
|
||||
);
|
||||
|
||||
insertRepo(
|
||||
db,
|
||||
context.getString(R.string.guardianproject_archive_name),
|
||||
context.getString(R.string.guardianproject_archive_address),
|
||||
context.getString(R.string.guardianproject_archive_description),
|
||||
context.getString(R.string.guardianproject_archive_pubkey),
|
||||
context.getResources().getInteger(R.integer.guardianproject_archive_version),
|
||||
context.getResources().getInteger(R.integer.guardianproject_archive_inuse),
|
||||
context.getResources().getInteger(R.integer.guardianproject_archive_priority)
|
||||
);
|
||||
String[] defaultRepos = context.getResources().getStringArray(R.array.default_repos);
|
||||
if (defaultRepos.length % REPO_XML_ARG_COUNT != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"default_repo.xml array does not have the right number of elements");
|
||||
}
|
||||
for (int i = 0; i < defaultRepos.length / REPO_XML_ARG_COUNT; i++) {
|
||||
int offset = i * REPO_XML_ARG_COUNT;
|
||||
insertRepo(
|
||||
db,
|
||||
defaultRepos[offset], // name
|
||||
defaultRepos[offset + 1], // address
|
||||
defaultRepos[offset + 2], // description
|
||||
defaultRepos[offset + 3], // version
|
||||
defaultRepos[offset + 4], // enabled
|
||||
defaultRepos[offset + 5], // priority
|
||||
defaultRepos[offset + 6], // pushRequests
|
||||
defaultRepos[offset + 7] // pubkey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void insertRepo(SQLiteDatabase db, String name, String address,
|
||||
String description, String pubKey, int version, int inUse,
|
||||
int priority) {
|
||||
|
||||
String description, String version, String enabled,
|
||||
String priority, String pushRequests, String pubKey) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(RepoTable.Cols.ADDRESS, address);
|
||||
values.put(RepoTable.Cols.NAME, name);
|
||||
@ -285,13 +286,27 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
values.put(RepoTable.Cols.SIGNING_CERT, pubKey);
|
||||
values.put(RepoTable.Cols.FINGERPRINT, Utils.calcFingerprint(pubKey));
|
||||
values.put(RepoTable.Cols.MAX_AGE, 0);
|
||||
values.put(RepoTable.Cols.VERSION, version);
|
||||
values.put(RepoTable.Cols.IN_USE, inUse);
|
||||
values.put(RepoTable.Cols.PRIORITY, priority);
|
||||
values.put(RepoTable.Cols.VERSION, Utils.parseInt(version, 0));
|
||||
values.put(RepoTable.Cols.IN_USE, Utils.parseInt(enabled, 0));
|
||||
values.put(RepoTable.Cols.PRIORITY, Utils.parseInt(priority, Integer.MAX_VALUE));
|
||||
values.put(RepoTable.Cols.LAST_ETAG, (String) null);
|
||||
values.put(RepoTable.Cols.TIMESTAMP, 0);
|
||||
|
||||
Utils.debugLog(TAG, "Adding repository " + name);
|
||||
switch (pushRequests) {
|
||||
case "ignore":
|
||||
values.put(RepoTable.Cols.PUSH_REQUESTS, Repo.PUSH_REQUEST_IGNORE);
|
||||
break;
|
||||
case "prompt":
|
||||
values.put(RepoTable.Cols.PUSH_REQUESTS, Repo.PUSH_REQUEST_PROMPT);
|
||||
break;
|
||||
case "always":
|
||||
values.put(RepoTable.Cols.PUSH_REQUESTS, Repo.PUSH_REQUEST_ACCEPT_ALWAYS);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException(pushRequests + " is not a supported option!");
|
||||
}
|
||||
|
||||
Utils.debugLog(TAG, "Adding repository " + name + " with push requests as " + pushRequests);
|
||||
db.insert(RepoTable.NAME, null, values);
|
||||
}
|
||||
|
||||
@ -328,6 +343,7 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
removeApkPackageNameColumn(db, oldVersion);
|
||||
addAppPrefsTable(db, oldVersion);
|
||||
lowerCaseApkHashes(db, oldVersion);
|
||||
supportRepoPushRequests(db, oldVersion);
|
||||
}
|
||||
|
||||
private void lowerCaseApkHashes(SQLiteDatabase db, int oldVersion) {
|
||||
@ -516,13 +532,13 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
}
|
||||
|
||||
private void insertNameAndDescription(SQLiteDatabase db,
|
||||
int addressResId, int nameResId, int descriptionResId) {
|
||||
String name, String address, String description) {
|
||||
ContentValues values = new ContentValues();
|
||||
values.clear();
|
||||
values.put(RepoTable.Cols.NAME, context.getString(nameResId));
|
||||
values.put(RepoTable.Cols.DESCRIPTION, context.getString(descriptionResId));
|
||||
db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[] {
|
||||
context.getString(addressResId),
|
||||
values.put(RepoTable.Cols.NAME, name);
|
||||
values.put(RepoTable.Cols.DESCRIPTION, description);
|
||||
db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[]{
|
||||
address,
|
||||
});
|
||||
}
|
||||
|
||||
@ -542,15 +558,16 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
if (!descriptionExists) {
|
||||
db.execSQL("alter table " + RepoTable.NAME + " add column " + RepoTable.Cols.DESCRIPTION + " text");
|
||||
}
|
||||
insertNameAndDescription(db, R.string.fdroid_repo_address,
|
||||
R.string.fdroid_repo_name, R.string.fdroid_repo_description);
|
||||
insertNameAndDescription(db, R.string.fdroid_archive_address,
|
||||
R.string.fdroid_archive_name, R.string.fdroid_archive_description);
|
||||
insertNameAndDescription(db, R.string.guardianproject_repo_address,
|
||||
R.string.guardianproject_repo_name, R.string.guardianproject_repo_description);
|
||||
insertNameAndDescription(db, R.string.guardianproject_archive_address,
|
||||
R.string.guardianproject_archive_name, R.string.guardianproject_archive_description);
|
||||
|
||||
String[] defaultRepos = context.getResources().getStringArray(R.array.default_repos);
|
||||
for (int i = 0; i < defaultRepos.length / REPO_XML_ARG_COUNT; i++) {
|
||||
int offset = i * REPO_XML_ARG_COUNT;
|
||||
insertNameAndDescription(db,
|
||||
defaultRepos[offset], // name
|
||||
defaultRepos[offset + 1], // address
|
||||
defaultRepos[offset + 2] // description
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -795,6 +812,17 @@ class DBHelper extends SQLiteOpenHelper {
|
||||
+ ApkTable.Cols.TARGET_SDK_VERSION + " integer");
|
||||
}
|
||||
|
||||
private void supportRepoPushRequests(SQLiteDatabase db, int oldVersion) {
|
||||
if (oldVersion >= 61) {
|
||||
return;
|
||||
}
|
||||
Utils.debugLog(TAG, "Adding " + RepoTable.Cols.PUSH_REQUESTS
|
||||
+ " columns to " + RepoTable.NAME);
|
||||
db.execSQL("alter table " + RepoTable.NAME + " add column "
|
||||
+ RepoTable.Cols.PUSH_REQUESTS + " integer not null default "
|
||||
+ Repo.PUSH_REQUEST_IGNORE);
|
||||
}
|
||||
|
||||
private static boolean columnExists(SQLiteDatabase db, String table, String column) {
|
||||
Cursor cursor = db.rawQuery("select * from " + table + " limit 0,1", null);
|
||||
boolean exists = cursor.getColumnIndex(column) != -1;
|
||||
|
@ -1,3 +1,26 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Blue Jay Wireless
|
||||
* Copyright (C) 2014-2016 Daniel Martí <mvdan@mvdan.cc>
|
||||
* Copyright (C) 2014-2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
* Copyright (C) 2014-2016 Peter Serwylo <peter@serwylo.com>
|
||||
* Copyright (C) 2015 Christian Morgner
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.content.ContentValues;
|
||||
@ -15,6 +38,10 @@ public class Repo extends ValueObject {
|
||||
|
||||
public static final int VERSION_DENSITY_SPECIFIC_ICONS = 11;
|
||||
|
||||
public static final int PUSH_REQUEST_IGNORE = 0;
|
||||
public static final int PUSH_REQUEST_PROMPT = 1;
|
||||
public static final int PUSH_REQUEST_ACCEPT_ALWAYS = 2;
|
||||
|
||||
protected long id;
|
||||
|
||||
public String address;
|
||||
@ -44,6 +71,9 @@ public class Repo extends ValueObject {
|
||||
/** When the signed repo index was generated, used to protect against replay attacks */
|
||||
public long timestamp;
|
||||
|
||||
/** How to treat push requests included in this repo's index XML */
|
||||
public int pushRequests = PUSH_REQUEST_IGNORE;
|
||||
|
||||
public Repo() {
|
||||
}
|
||||
|
||||
@ -101,6 +131,9 @@ public class Repo extends ValueObject {
|
||||
case Cols.TIMESTAMP:
|
||||
timestamp = cursor.getLong(i);
|
||||
break;
|
||||
case Cols.PUSH_REQUESTS:
|
||||
pushRequests = cursor.getInt(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -223,5 +256,9 @@ public class Repo extends ValueObject {
|
||||
if (values.containsKey(Cols.TIMESTAMP)) {
|
||||
timestamp = toInt(values.getAsInteger(Cols.TIMESTAMP));
|
||||
}
|
||||
|
||||
if (values.containsKey(Cols.PUSH_REQUESTS)) {
|
||||
pushRequests = toInt(values.getAsInteger(Cols.PUSH_REQUESTS));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Blue Jay Wireless
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.support.annotation.Nullable;
|
||||
|
||||
/**
|
||||
* Represents action requests embedded in the index XML received from a repo.
|
||||
* When {@link #versionCode} is {@code null}, that means that the
|
||||
* {@code versionCode} was not specified by the server, and F-Droid should
|
||||
* install the best available version.
|
||||
*/
|
||||
public class RepoPushRequest {
|
||||
public static final String TAG = "RepoPushRequest";
|
||||
|
||||
public static final String INSTALL = "install";
|
||||
public static final String UNINSTALL = "uninstall";
|
||||
|
||||
public final String request;
|
||||
public final String packageName;
|
||||
@Nullable
|
||||
public final Integer versionCode;
|
||||
|
||||
public RepoPushRequest(String request, String packageName, String versionCode) {
|
||||
this.request = request;
|
||||
this.packageName = packageName;
|
||||
|
||||
Integer i;
|
||||
try {
|
||||
i = Integer.parseInt(versionCode);
|
||||
} catch (NumberFormatException e) {
|
||||
i = null;
|
||||
}
|
||||
this.versionCode = i;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return request + " " + packageName + " " + versionCode;
|
||||
}
|
||||
}
|
@ -196,11 +196,12 @@ public interface Schema {
|
||||
String USERNAME = "username";
|
||||
String PASSWORD = "password";
|
||||
String TIMESTAMP = "timestamp";
|
||||
String PUSH_REQUESTS = "pushRequests";
|
||||
|
||||
String[] ALL = {
|
||||
_ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT,
|
||||
FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP,
|
||||
USERNAME, PASSWORD, TIMESTAMP,
|
||||
USERNAME, PASSWORD, TIMESTAMP, PUSH_REQUESTS,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -148,6 +148,10 @@ public class InstallManagerService extends Service {
|
||||
|
||||
App app = intent.getParcelableExtra(EXTRA_APP);
|
||||
Apk apk = intent.getParcelableExtra(EXTRA_APK);
|
||||
if (app == null || apk == null) {
|
||||
Utils.debugLog(TAG, "Intent had null EXTRA_APP and/or EXTRA_APK: " + intent);
|
||||
return START_NOT_STICKY;
|
||||
}
|
||||
addToActive(urlString, app, apk);
|
||||
|
||||
NotificationCompat.Builder builder = createNotificationBuilder(urlString, apk);
|
||||
|
@ -24,6 +24,7 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
|
||||
import org.fdroid.fdroid.Utils;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
|
||||
/**
|
||||
@ -41,6 +42,7 @@ import org.fdroid.fdroid.data.Apk;
|
||||
* {@link InstallManagerService}.
|
||||
*/
|
||||
public class InstallerService extends IntentService {
|
||||
public static final String TAG = "InstallerService";
|
||||
|
||||
private static final String ACTION_INSTALL = "org.fdroid.fdroid.installer.InstallerService.action.INSTALL";
|
||||
private static final String ACTION_UNINSTALL = "org.fdroid.fdroid.installer.InstallerService.action.UNINSTALL";
|
||||
@ -52,7 +54,10 @@ public class InstallerService extends IntentService {
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
Apk apk = intent.getParcelableExtra(Installer.EXTRA_APK);
|
||||
|
||||
if (apk == null) {
|
||||
Utils.debugLog(TAG, "ignoring intent with null EXTRA_APK: " + intent);
|
||||
return;
|
||||
}
|
||||
Installer installer = InstallerFactory.create(this, apk);
|
||||
|
||||
if (ACTION_INSTALL.equals(intent.getAction())) {
|
||||
|
@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<!-- 1 - https://f-droid.org/repo -->
|
||||
<string name="fdroid_repo_name" formatted="false" translatable="false">F-Droid</string>
|
||||
|
||||
<integer name="fdroid_repo_version">13</integer>
|
||||
<integer name="fdroid_repo_inuse">1</integer>
|
||||
<integer name="fdroid_repo_priority">10</integer>
|
||||
|
||||
<string name="fdroid_repo_address" formatted="false" translatable="false">https://f-droid.org/repo</string>
|
||||
<string name="fdroid_repo_description" formatted="false" translatable="false">The official F-Droid repository. Applications in this repository are mostly built directory from the source code. Some are official binaries built by the original application developers - these will be replaced by source-built versions over time.</string>
|
||||
<string name="fdroid_repo_pubkey" formatted="false" translatable="false">3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef</string>
|
||||
|
||||
<!-- 2 - https://f-droid.org/archive -->
|
||||
<string name="fdroid_archive_name" formatted="false" translatable="false">F-Droid Archive</string>
|
||||
|
||||
<integer name="fdroid_archive_version">13</integer>
|
||||
<integer name="fdroid_archive_inuse">0</integer>
|
||||
<integer name="fdroid_archive_priority">20</integer>
|
||||
|
||||
<string name="fdroid_archive_address" formatted="false" translatable="false">https://f-droid.org/archive</string>
|
||||
<string name="fdroid_archive_description" formatted="false" translatable="false">The archive repository of the F-Droid client. This contains older versions of applications from the main repository.</string>
|
||||
<string name="fdroid_archive_pubkey" formatted="false" translatable="false">3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef</string>
|
||||
|
||||
<!-- https://guardianproject.info/fdroid/repo -->
|
||||
<string name="guardianproject_repo_name" formatted="false" translatable="false">Guardian Project</string>
|
||||
|
||||
<integer name="guardianproject_repo_version">13</integer>
|
||||
<integer name="guardianproject_repo_inuse">0</integer>
|
||||
<integer name="guardianproject_repo_priority">10</integer>
|
||||
|
||||
<string name="guardianproject_repo_address" formatted="false" translatable="false">https://guardianproject.info/fdroid/repo</string>
|
||||
<string name="guardianproject_repo_description" formatted="false" translatable="false">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.</string>
|
||||
<string name="guardianproject_repo_pubkey" formatted="false" translatable="false">308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f</string>
|
||||
|
||||
<!-- https://guardianproject.info/fdroid/archive -->
|
||||
<string name="guardianproject_archive_name" formatted="false" translatable="false">Guardian Project Archive</string>
|
||||
|
||||
<integer name="guardianproject_archive_version">13</integer>
|
||||
<integer name="guardianproject_archive_inuse">0</integer>
|
||||
<integer name="guardianproject_archive_priority">20</integer>
|
||||
|
||||
<string name="guardianproject_archive_address" formatted="false" translatable="false">https://guardianproject.info/fdroid/archive</string>
|
||||
<string name="guardianproject_archive_description" formatted="false" translatable="false">The official repository of The Guardian Project apps for use with F-Droid client. This contains older versions of applications from the main repository.</string>
|
||||
<string name="guardianproject_archive_pubkey" formatted="false" translatable="false">308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f</string>
|
||||
|
||||
</resources>
|
94
app/src/main/res/values/default_repos.xml
Normal file
94
app/src/main/res/values/default_repos.xml
Normal file
@ -0,0 +1,94 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
|
||||
<string-array name="default_repos">
|
||||
|
||||
<!-- name -->
|
||||
<item>F-Droid</item>
|
||||
<!-- address -->
|
||||
<item>https://f-droid.org/repo</item>
|
||||
<!-- description -->
|
||||
<item>The official F-Droid repository. Applications in this repository are mostly built
|
||||
directory from the source code. Some are official binaries built by the original
|
||||
application developers - these will be replaced by source-built versions over time.
|
||||
</item>
|
||||
<!-- version -->
|
||||
<item>13</item>
|
||||
<!-- enabled -->
|
||||
<item>1</item>
|
||||
<!-- priority -->
|
||||
<item>10</item>
|
||||
<!-- push requests -->
|
||||
<item>ignore</item>
|
||||
<!-- pubkey -->
|
||||
<item>
|
||||
3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef
|
||||
</item>
|
||||
|
||||
<!-- name -->
|
||||
<item>F-Droid Archive</item>
|
||||
<!-- address -->
|
||||
<item>https://f-droid.org/archive</item>
|
||||
<!-- description -->
|
||||
<item>The archive repository of the F-Droid client. This contains older versions of
|
||||
applications from the main repository.
|
||||
</item>
|
||||
<!-- version -->
|
||||
<item>13</item>
|
||||
<!-- enabled -->
|
||||
<item>0</item>
|
||||
<!-- priority -->
|
||||
<item>20</item>
|
||||
<!-- push requests -->
|
||||
<item>ignore</item>
|
||||
<!-- pubkey -->
|
||||
<item>
|
||||
3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef
|
||||
</item>
|
||||
|
||||
<!-- name -->
|
||||
<item>Guardian Project</item>
|
||||
<!-- address -->
|
||||
<item>https://guardianproject.info/fdroid/repo</item>
|
||||
<!-- description -->
|
||||
<item>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.
|
||||
</item>
|
||||
<!-- version -->
|
||||
<item>13</item>
|
||||
<!-- enabled -->
|
||||
<item>0</item>
|
||||
<!-- priority -->
|
||||
<item>10</item>
|
||||
<!-- push requests -->
|
||||
<item>ignore</item>
|
||||
<!-- pubkey -->
|
||||
<item>
|
||||
308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f
|
||||
</item>
|
||||
|
||||
<!-- name -->
|
||||
<item>Guardian Project Archive</item>
|
||||
<!-- address -->
|
||||
<item>https://guardianproject.info/fdroid/archive</item>
|
||||
<!-- description -->
|
||||
<item>The official repository of The Guardian Project apps for use with F-Droid client. This
|
||||
contains older versions of applications from the main repository.
|
||||
</item>
|
||||
<!-- version -->
|
||||
<item>13</item>
|
||||
<!-- enabled -->
|
||||
<item>0</item>
|
||||
<!-- priority -->
|
||||
<item>20</item>
|
||||
<!-- push requests -->
|
||||
<item>ignore</item>
|
||||
<!-- pubkey -->
|
||||
<item>
|
||||
308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f
|
||||
</item>
|
||||
|
||||
</string-array>
|
||||
|
||||
</resources>
|
@ -1,3 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Blue Jay Wireless
|
||||
* Copyright (C) 2015 Daniel Martí <mvdan@mvdan.cc>
|
||||
* Copyright (C) 2014-2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
* Copyright (C) 2014-2016 Peter Serwylo <peter@serwylo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid;
|
||||
|
||||
@ -8,6 +29,7 @@ import android.util.Log;
|
||||
import org.fdroid.fdroid.data.Apk;
|
||||
import org.fdroid.fdroid.data.App;
|
||||
import org.fdroid.fdroid.data.Repo;
|
||||
import org.fdroid.fdroid.data.RepoPushRequest;
|
||||
import org.fdroid.fdroid.mock.MockRepo;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -82,6 +104,38 @@ public class RepoXMLHandlerTest {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushRequestsRepoIgnore() {
|
||||
Repo expectedRepo = new Repo();
|
||||
expectedRepo.name = "non-public test repo";
|
||||
expectedRepo.signingCertificate = "308204e1308202c9a0030201020204483450fa300d06092a864886f70d01010b050030213110300e060355040b1307462d44726f6964310d300b06035504031304736f7661301e170d3136303832333133333131365a170d3434303130393133333131365a30213110300e060355040b1307462d44726f6964310d300b06035504031304736f766130820222300d06092a864886f70d01010105000382020f003082020a0282020100dfdcd120f3ab224999dddf4ea33ea588d295e4d7130bef48c143e9d76e5c0e0e9e5d45e64208e35feebc79a83f08939dd6a343b7d1e2179930a105a1249ccd36d88ff3feffc6e4dc53dae0163a7876dd45ecc1ddb0adf5099aa56c1a84b52affcd45d0711ffa4de864f35ac0333ebe61ea8673eeda35a88f6af678cc4d0f80b089338ac8f2a8279a64195c611d19445cab3fd1a020afed9bd739bb95142fb2c00a8f847db5ef3325c814f8eb741bacf86ed3907bfe6e4564d2de5895df0c263824e0b75407589bae2d3a4666c13b92102d8781a8ee9bb4a5a1a78c4a9c21efdaf5584da42e84418b28f5a81d0456a3dc5b420991801e6b21e38c99bbe018a5b2d690894a114bc860d35601416aa4dc52216aff8a288d4775cddf8b72d45fd2f87303a8e9c0d67e442530be28eaf139894337266e0b33d57f949256ab32083bcc545bc18a83c9ab8247c12aea037e2b68dee31c734cb1f04f241d3b94caa3a2b258ffaf8e6eae9fbbe029a934dc0a0859c5f120334812693a1c09352340a39f2a678dbc1afa2a978bfee43afefcb7e224a58af2f3d647e5745db59061236b8af6fcfd93b3602f9e456978534f3a7851e800071bf56da80401c81d91c45f82568373af0576b1cc5eef9b85654124b6319770be3cdba3fbebe3715e8918fb6c8966624f3d0e815effac3d2ee06dd34ab9c693218b2c7c06ba99d6b74d4f17b8c3cb0203010001a321301f301d0603551d0e04160414d62bee9f3798509546acc62eb1de14b08b954d4f300d06092a864886f70d01010b05000382020100743f7c5692085895f9d1fffad390fb4202c15f123ed094df259185960fd6dadf66cb19851070f180297bba4e6996a4434616573b375cfee94fee73a4505a7ec29136b7e6c22e6436290e3686fe4379d4e3140ec6a08e70cfd3ed5b634a5eb5136efaaabf5f38e0432d3d79568a556970b8cfba2972f5d23a3856d8a981b9e9bbbbb88f35e708bde9cbc5f681cbd974085b9da28911296fe2579fa64bbe9fa0b93475a7a8db051080b0c5fade0d1c018e7858cd4cbe95145b0620e2f632cbe0f8af9cbf22e2fdaa72245ae31b0877b07181cc69dd2df74454251d8de58d25e76354abe7eb690f22e59b08795a8f2c98c578e0599503d9085927634072c82c9f82abd50fd12b8fd1a9d1954eb5cc0b4cfb5796b5aaec0356643b4a65a368442d92ef94edd3ac6a2b7fe3571b8cf9f462729228aab023ef9183f73792f5379633ccac51079177d604c6bc1873ada6f07d8da6d68c897e88a5fa5d63fdb8df820f46090e0716e7562dd3c140ba279a65b996f60addb0abe29d4bf2f5abe89480771d492307b926d91f02f341b2148502903c43d40f3c6c86a811d060711f0698b384acdcc0add44eb54e42962d3d041accc715afd49407715adc09350cb55e8d9281a3b0b6b5fcd91726eede9b7c8b13afdebb2c2b377629595f1096ba62fb14946dbac5f3c5f0b4e5b712e7acc7dcf6c46cdc5e6d6dfdeee55a0c92c2d70f080ac6";
|
||||
expectedRepo.description = "This is a repository of apps to be used with F-Droid. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitlab.com/u/fdroid.";
|
||||
expectedRepo.timestamp = 1472071347;
|
||||
RepoDetails actualDetails = getFromFile("pushRequestsIndex.xml", Repo.PUSH_REQUEST_IGNORE);
|
||||
handlerTestSuite(expectedRepo, actualDetails, 2, 14, -1, 17);
|
||||
checkPushRequests(actualDetails);
|
||||
|
||||
List<RepoPushRequest> repoPushRequests = actualDetails.repoPushRequestList;
|
||||
assertNotNull(repoPushRequests);
|
||||
assertEquals(0, repoPushRequests.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testPushRequestsRepoAlways() {
|
||||
Repo expectedRepo = new Repo();
|
||||
expectedRepo.name = "non-public test repo";
|
||||
expectedRepo.signingCertificate = "308204e1308202c9a0030201020204483450fa300d06092a864886f70d01010b050030213110300e060355040b1307462d44726f6964310d300b06035504031304736f7661301e170d3136303832333133333131365a170d3434303130393133333131365a30213110300e060355040b1307462d44726f6964310d300b06035504031304736f766130820222300d06092a864886f70d01010105000382020f003082020a0282020100dfdcd120f3ab224999dddf4ea33ea588d295e4d7130bef48c143e9d76e5c0e0e9e5d45e64208e35feebc79a83f08939dd6a343b7d1e2179930a105a1249ccd36d88ff3feffc6e4dc53dae0163a7876dd45ecc1ddb0adf5099aa56c1a84b52affcd45d0711ffa4de864f35ac0333ebe61ea8673eeda35a88f6af678cc4d0f80b089338ac8f2a8279a64195c611d19445cab3fd1a020afed9bd739bb95142fb2c00a8f847db5ef3325c814f8eb741bacf86ed3907bfe6e4564d2de5895df0c263824e0b75407589bae2d3a4666c13b92102d8781a8ee9bb4a5a1a78c4a9c21efdaf5584da42e84418b28f5a81d0456a3dc5b420991801e6b21e38c99bbe018a5b2d690894a114bc860d35601416aa4dc52216aff8a288d4775cddf8b72d45fd2f87303a8e9c0d67e442530be28eaf139894337266e0b33d57f949256ab32083bcc545bc18a83c9ab8247c12aea037e2b68dee31c734cb1f04f241d3b94caa3a2b258ffaf8e6eae9fbbe029a934dc0a0859c5f120334812693a1c09352340a39f2a678dbc1afa2a978bfee43afefcb7e224a58af2f3d647e5745db59061236b8af6fcfd93b3602f9e456978534f3a7851e800071bf56da80401c81d91c45f82568373af0576b1cc5eef9b85654124b6319770be3cdba3fbebe3715e8918fb6c8966624f3d0e815effac3d2ee06dd34ab9c693218b2c7c06ba99d6b74d4f17b8c3cb0203010001a321301f301d0603551d0e04160414d62bee9f3798509546acc62eb1de14b08b954d4f300d06092a864886f70d01010b05000382020100743f7c5692085895f9d1fffad390fb4202c15f123ed094df259185960fd6dadf66cb19851070f180297bba4e6996a4434616573b375cfee94fee73a4505a7ec29136b7e6c22e6436290e3686fe4379d4e3140ec6a08e70cfd3ed5b634a5eb5136efaaabf5f38e0432d3d79568a556970b8cfba2972f5d23a3856d8a981b9e9bbbbb88f35e708bde9cbc5f681cbd974085b9da28911296fe2579fa64bbe9fa0b93475a7a8db051080b0c5fade0d1c018e7858cd4cbe95145b0620e2f632cbe0f8af9cbf22e2fdaa72245ae31b0877b07181cc69dd2df74454251d8de58d25e76354abe7eb690f22e59b08795a8f2c98c578e0599503d9085927634072c82c9f82abd50fd12b8fd1a9d1954eb5cc0b4cfb5796b5aaec0356643b4a65a368442d92ef94edd3ac6a2b7fe3571b8cf9f462729228aab023ef9183f73792f5379633ccac51079177d604c6bc1873ada6f07d8da6d68c897e88a5fa5d63fdb8df820f46090e0716e7562dd3c140ba279a65b996f60addb0abe29d4bf2f5abe89480771d492307b926d91f02f341b2148502903c43d40f3c6c86a811d060711f0698b384acdcc0add44eb54e42962d3d041accc715afd49407715adc09350cb55e8d9281a3b0b6b5fcd91726eede9b7c8b13afdebb2c2b377629595f1096ba62fb14946dbac5f3c5f0b4e5b712e7acc7dcf6c46cdc5e6d6dfdeee55a0c92c2d70f080ac6";
|
||||
expectedRepo.description = "This is a repository of apps to be used with F-Droid. Applications in this repository are either official binaries built by the original application developers, or are binaries built from source by the admin of f-droid.org using the tools on https://gitlab.com/u/fdroid.";
|
||||
expectedRepo.timestamp = 1472071347;
|
||||
RepoDetails actualDetails = getFromFile("pushRequestsIndex.xml", Repo.PUSH_REQUEST_ACCEPT_ALWAYS);
|
||||
handlerTestSuite(expectedRepo, actualDetails, 2, 14, -1, 17);
|
||||
checkPushRequests(actualDetails);
|
||||
|
||||
List<RepoPushRequest> repoPushRequests = actualDetails.repoPushRequestList;
|
||||
assertNotNull(repoPushRequests);
|
||||
assertEquals(6, repoPushRequests.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMediumRepo() {
|
||||
Repo expectedRepo = new Repo();
|
||||
@ -697,6 +751,30 @@ public class RepoXMLHandlerTest {
|
||||
}
|
||||
}
|
||||
|
||||
private void checkPushRequests(RepoDetails actualDetails) {
|
||||
final Object[] expectedPushRequestsIndex = new Object[]{
|
||||
"install", "org.fdroid.fdroid", 101002,
|
||||
"install", "org.fdroid.fdroid.privileged", null,
|
||||
"uninstall", "com.android.vending", null,
|
||||
"uninstall", "com.facebook.orca", -12345,
|
||||
"uninstall", null, null, // request with no data
|
||||
"install", "asdfasdfasdf", null, // non-existent app
|
||||
};
|
||||
|
||||
checkIncludedApps(actualDetails.apps, new String[]{
|
||||
"org.fdroid.fdroid", "org.fdroid.fdroid.privileged",
|
||||
});
|
||||
|
||||
List<RepoPushRequest> repoPushRequestList = actualDetails.repoPushRequestList;
|
||||
int i = 0;
|
||||
for (RepoPushRequest repoPushRequest : repoPushRequestList) {
|
||||
assertEquals(repoPushRequest.request, expectedPushRequestsIndex[i]);
|
||||
assertEquals(repoPushRequest.packageName, expectedPushRequestsIndex[i + 1]);
|
||||
assertEquals(repoPushRequest.versionCode, expectedPushRequestsIndex[i + 2]);
|
||||
i += 3;
|
||||
}
|
||||
}
|
||||
|
||||
private void handlerTestSuite(Repo expectedRepo, RepoDetails actualDetails, int appCount, int apkCount, int maxAge, int version) {
|
||||
assertNotNull(actualDetails);
|
||||
assertFalse(TextUtils.isEmpty(actualDetails.signingCert));
|
||||
@ -736,6 +814,7 @@ public class RepoXMLHandlerTest {
|
||||
|
||||
public List<Apk> apks = new ArrayList<>();
|
||||
public List<App> apps = new ArrayList<>();
|
||||
public List<RepoPushRequest> repoPushRequestList = new ArrayList<>();
|
||||
|
||||
@Override
|
||||
public void receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp) {
|
||||
@ -753,17 +832,27 @@ public class RepoXMLHandlerTest {
|
||||
apps.add(app);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveRepoPushRequest(RepoPushRequest repoPushRequest) {
|
||||
repoPushRequestList.add(repoPushRequest);
|
||||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private RepoDetails getFromFile(String indexFilename) {
|
||||
return getFromFile(indexFilename, Repo.PUSH_REQUEST_IGNORE);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private RepoDetails getFromFile(String indexFilename, int pushRequests) {
|
||||
try {
|
||||
SAXParserFactory factory = SAXParserFactory.newInstance();
|
||||
factory.setNamespaceAware(true);
|
||||
SAXParser parser = factory.newSAXParser();
|
||||
XMLReader reader = parser.getXMLReader();
|
||||
RepoDetails repoDetails = new RepoDetails();
|
||||
RepoXMLHandler handler = new RepoXMLHandler(new MockRepo(100), repoDetails);
|
||||
MockRepo mockRepo = new MockRepo(100, pushRequests);
|
||||
RepoXMLHandler handler = new RepoXMLHandler(mockRepo, repoDetails);
|
||||
reader.setContentHandler(handler);
|
||||
Log.i(TAG, "test file: " + getClass().getClassLoader().getResource(indexFilename));
|
||||
InputStream input = getClass().getClassLoader().getResourceAsStream(indexFilename);
|
||||
|
@ -1,3 +1,24 @@
|
||||
/*
|
||||
* Copyright (C) 2016 Blue Jay Wireless
|
||||
* Copyright (C) 2014-2016 Hans-Christoph Steiner <hans@eds.org>
|
||||
* Copyright (C) 2014-2016 Peter Serwylo <peter@serwylo.com>
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* as published by the Free Software Foundation; either version 3
|
||||
* of the License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
|
||||
* MA 02110-1301, USA.
|
||||
*/
|
||||
|
||||
package org.fdroid.fdroid.data;
|
||||
|
||||
import android.app.Application;
|
||||
@ -74,48 +95,29 @@ public class RepoProviderTest extends FDroidProviderTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* The {@link DBHelper} class populates four default repos when it first creates a database:
|
||||
* * F-Droid
|
||||
* * F-Droid (Archive)
|
||||
* * Guardian Project
|
||||
* * Guardian Project (Archive)
|
||||
* The {@link DBHelper} class populates the default repos when it first creates a database.
|
||||
* The names/URLs/signing certificates for these repos are all hard coded in the source/res.
|
||||
*/
|
||||
@Test
|
||||
public void defaultRepos() {
|
||||
List<Repo> defaultRepos = RepoProvider.Helper.all(context);
|
||||
assertEquals(defaultRepos.size(), 4);
|
||||
assertRepo(
|
||||
defaultRepos.get(0),
|
||||
context.getString(R.string.fdroid_repo_address),
|
||||
context.getString(R.string.fdroid_repo_description),
|
||||
Utils.calcFingerprint(context.getString(R.string.fdroid_repo_pubkey)),
|
||||
context.getString(R.string.fdroid_repo_name)
|
||||
);
|
||||
assertEquals(defaultRepos.size(), 4); // based on app/src/main/res/default_repo.xml
|
||||
|
||||
assertRepo(
|
||||
defaultRepos.get(1),
|
||||
context.getString(R.string.fdroid_archive_address),
|
||||
context.getString(R.string.fdroid_archive_description),
|
||||
Utils.calcFingerprint(context.getString(R.string.fdroid_archive_pubkey)),
|
||||
context.getString(R.string.fdroid_archive_name)
|
||||
);
|
||||
|
||||
assertRepo(
|
||||
defaultRepos.get(2),
|
||||
context.getString(R.string.guardianproject_repo_address),
|
||||
context.getString(R.string.guardianproject_repo_description),
|
||||
Utils.calcFingerprint(context.getString(R.string.guardianproject_repo_pubkey)),
|
||||
context.getString(R.string.guardianproject_repo_name)
|
||||
);
|
||||
|
||||
assertRepo(
|
||||
defaultRepos.get(3),
|
||||
context.getString(R.string.guardianproject_archive_address),
|
||||
context.getString(R.string.guardianproject_archive_description),
|
||||
Utils.calcFingerprint(context.getString(R.string.guardianproject_archive_pubkey)),
|
||||
context.getString(R.string.guardianproject_archive_name)
|
||||
);
|
||||
String[] reposFromXml = context.getResources().getStringArray(R.array.default_repos);
|
||||
if (reposFromXml.length % DBHelper.REPO_XML_ARG_COUNT != 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"default_repo.xml array does not have the right number of elements");
|
||||
}
|
||||
for (int i = 0; i < reposFromXml.length / DBHelper.REPO_XML_ARG_COUNT; i++) {
|
||||
int offset = i * DBHelper.REPO_XML_ARG_COUNT;
|
||||
assertRepo(
|
||||
defaultRepos.get(i),
|
||||
reposFromXml[offset + 1], // address
|
||||
reposFromXml[offset + 2], // description
|
||||
Utils.calcFingerprint(reposFromXml[offset + 7]), // pubkey
|
||||
reposFromXml[offset] // name
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -4,8 +4,13 @@ import org.fdroid.fdroid.data.Repo;
|
||||
|
||||
public class MockRepo extends Repo {
|
||||
|
||||
public MockRepo(long repoId) {
|
||||
id = repoId;
|
||||
public MockRepo(long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public MockRepo(long id, int pushRequests) {
|
||||
this.id = id;
|
||||
this.pushRequests = pushRequests;
|
||||
}
|
||||
|
||||
}
|
||||
|
1
app/src/test/resources/pushRequestsIndex.xml
Normal file
1
app/src/test/resources/pushRequestsIndex.xml
Normal file
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user