basic support for repo push requests, configed in default_repos
This allows whitelabel versions of apps to specify built-in app repos that have push requests accepted by default. This is useful for the case where there is a central manager of the core apps that are installed. https://gitlab.com/fdroid/fdroidserver/issues/177
This commit is contained in:
		
							parent
							
								
									d34a1285e8
								
							
						
					
					
						commit
						5c9dd1a11e
					
				| @ -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; | package org.fdroid.fdroid; | ||||||
| 
 | 
 | ||||||
|  | import android.content.ContentResolver; | ||||||
| import android.content.ContentValues; | import android.content.ContentValues; | ||||||
| import android.content.Context; | import android.content.Context; | ||||||
|  | import android.content.pm.PackageInfo; | ||||||
|  | import android.content.pm.PackageManager; | ||||||
| import android.support.annotation.NonNull; | import android.support.annotation.NonNull; | ||||||
| import android.support.annotation.Nullable; | import android.support.annotation.Nullable; | ||||||
| import android.text.TextUtils; | import android.text.TextUtils; | ||||||
| import android.util.Log; | import android.util.Log; | ||||||
| 
 | 
 | ||||||
| import org.fdroid.fdroid.data.Apk; | import org.fdroid.fdroid.data.Apk; | ||||||
|  | import org.fdroid.fdroid.data.ApkProvider; | ||||||
| import org.fdroid.fdroid.data.App; | import org.fdroid.fdroid.data.App; | ||||||
|  | import org.fdroid.fdroid.data.AppProvider; | ||||||
| import org.fdroid.fdroid.data.Repo; | import org.fdroid.fdroid.data.Repo; | ||||||
| import org.fdroid.fdroid.data.RepoPersister; | import org.fdroid.fdroid.data.RepoPersister; | ||||||
| import org.fdroid.fdroid.data.RepoProvider; | import org.fdroid.fdroid.data.RepoProvider; | ||||||
|  | import org.fdroid.fdroid.data.RepoPushRequest; | ||||||
| import org.fdroid.fdroid.data.Schema.RepoTable; | 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.Downloader; | ||||||
| import org.fdroid.fdroid.net.DownloaderFactory; | import org.fdroid.fdroid.net.DownloaderFactory; | ||||||
| import org.xml.sax.InputSource; | import org.xml.sax.InputSource; | ||||||
| @ -27,6 +57,7 @@ import java.net.URL; | |||||||
| import java.security.CodeSigner; | import java.security.CodeSigner; | ||||||
| import java.security.cert.Certificate; | import java.security.cert.Certificate; | ||||||
| import java.security.cert.X509Certificate; | import java.security.cert.X509Certificate; | ||||||
|  | import java.util.ArrayList; | ||||||
| import java.util.Date; | import java.util.Date; | ||||||
| import java.util.List; | import java.util.List; | ||||||
| import java.util.jar.JarEntry; | import java.util.jar.JarEntry; | ||||||
| @ -37,12 +68,15 @@ import javax.xml.parsers.SAXParser; | |||||||
| import javax.xml.parsers.SAXParserFactory; | import javax.xml.parsers.SAXParserFactory; | ||||||
| 
 | 
 | ||||||
| /** | /** | ||||||
|  * Responsible for updating an individual repository. This will: |  * Updates the local database with a repository's app/apk metadata and verifying | ||||||
|  *  * Download the index.jar |  * the JAR signature on the file received from the repository. As an overview: | ||||||
|  *  * Verify that it is signed correctly and by the correct certificate |  * <ul> | ||||||
|  *  * Parse the index.xml from the .jar file |  * <li>Download the {@code index.jar} | ||||||
|  *  * Save the resulting repo, apps, and apks to the database. |  * <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 |  * <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, |  * FDroid!  Avoid modifying it when possible, if you absolutely must, be very, | ||||||
|  * very careful with the changes that you are making! |  * very careful with the changes that you are making! | ||||||
| @ -66,7 +100,10 @@ public class RepoUpdater { | |||||||
|     private String cacheTag; |     private String cacheTag; | ||||||
|     private X509Certificate signingCertFromJar; |     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. |      * 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: |             // successful download, then we will have a file ready to use: | ||||||
|             cacheTag = downloader.getCacheTag(); |             cacheTag = downloader.getCacheTag(); | ||||||
|             processDownloadedFile(downloader.outputFile); |             processDownloadedFile(downloader.outputFile); | ||||||
|  |             processRepoPushRequests(); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -170,6 +208,11 @@ public class RepoUpdater { | |||||||
|                     throw new RuntimeException("Error while saving repo details to database.", e); |                     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); |             JarFile jarFile = new JarFile(downloadedFile, true); | ||||||
|             JarEntry indexEntry = (JarEntry) jarFile.getEntry("index.xml"); |             JarEntry indexEntry = (JarEntry) jarFile.getEntry("index.xml"); | ||||||
|             indexInputStream = new ProgressBufferedInputStream(jarFile.getInputStream(indexEntry), |             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... |             // Process the index... | ||||||
|             SAXParserFactory factory = SAXParserFactory.newInstance(); |             SAXParserFactory factory = SAXParserFactory.newInstance(); | ||||||
| @ -396,4 +439,52 @@ public class RepoUpdater { | |||||||
|         throw new SigningException(repo, "Signing certificate does not match!"); |         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); | ||||||
|  |                 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.Apk; | ||||||
| import org.fdroid.fdroid.data.App; | import org.fdroid.fdroid.data.App; | ||||||
| import org.fdroid.fdroid.data.Repo; | import org.fdroid.fdroid.data.Repo; | ||||||
|  | import org.fdroid.fdroid.data.RepoPushRequest; | ||||||
| import org.xml.sax.Attributes; | import org.xml.sax.Attributes; | ||||||
| import org.xml.sax.SAXException; | import org.xml.sax.SAXException; | ||||||
| import org.xml.sax.helpers.DefaultHandler; | 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 receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp); | ||||||
| 
 | 
 | ||||||
|         void receiveApp(App app, List<Apk> packages); |         void receiveApp(App app, List<Apk> packages); | ||||||
|  | 
 | ||||||
|  |         void receiveRepoPushRequest(RepoPushRequest repoPushRequest); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private final IndexReceiver receiver; |     private final IndexReceiver receiver; | ||||||
| @ -250,6 +253,10 @@ public class RepoXMLHandler extends DefaultHandler { | |||||||
|         receiver.receiveRepo(repoName, repoDescription, repoSigningCert, repoMaxAge, repoVersion, repoTimestamp); |         receiver.receiveRepo(repoName, repoDescription, repoSigningCert, repoMaxAge, repoVersion, repoTimestamp); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     private void onRepoPushRequestParsed(RepoPushRequest repoPushRequest) { | ||||||
|  |         receiver.receiveRepoPushRequest(repoPushRequest); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|     @Override |     @Override | ||||||
|     public void startElement(String uri, String localName, String qName, |     public void startElement(String uri, String localName, String qName, | ||||||
|                              Attributes attributes) throws SAXException { |                              Attributes attributes) throws SAXException { | ||||||
| @ -262,6 +269,15 @@ public class RepoXMLHandler extends DefaultHandler { | |||||||
|             repoName = cleanWhiteSpace(attributes.getValue("", "name")); |             repoName = cleanWhiteSpace(attributes.getValue("", "name")); | ||||||
|             repoDescription = cleanWhiteSpace(attributes.getValue("", "description")); |             repoDescription = cleanWhiteSpace(attributes.getValue("", "description")); | ||||||
|             repoTimestamp = parseLong(attributes.getValue("", "timestamp"), 0); |             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) { |         } else if ("application".equals(localName) && curapp == null) { | ||||||
|             curapp = new App(); |             curapp = new App(); | ||||||
|             curapp.packageName = attributes.getValue("", "id"); |             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; | package org.fdroid.fdroid.data; | ||||||
| 
 | 
 | ||||||
| import android.content.ContentValues; | import android.content.ContentValues; | ||||||
| @ -23,6 +46,8 @@ class DBHelper extends SQLiteOpenHelper { | |||||||
| 
 | 
 | ||||||
|     private static final String TAG = "DBHelper"; |     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 DATABASE_NAME = "fdroid"; | ||||||
| 
 | 
 | ||||||
|     private static final String CREATE_TABLE_REPO = "create table " |     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.IS_SWAP + " integer boolean default 0," | ||||||
|             + RepoTable.Cols.USERNAME + " string, " |             + RepoTable.Cols.USERNAME + " string, " | ||||||
|             + RepoTable.Cols.PASSWORD + " 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 = |     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 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; |     private final Context context; | ||||||
| 
 | 
 | ||||||
| @ -244,14 +270,15 @@ class DBHelper extends SQLiteOpenHelper { | |||||||
|                     defaultRepos[offset + 3], // version |                     defaultRepos[offset + 3], // version | ||||||
|                     defaultRepos[offset + 4], // enabled |                     defaultRepos[offset + 4], // enabled | ||||||
|                     defaultRepos[offset + 5], // priority |                     defaultRepos[offset + 5], // priority | ||||||
|                     defaultRepos[offset + 6]  // pubkey |                     defaultRepos[offset + 6], // pushRequests | ||||||
|  |                     defaultRepos[offset + 7]  // pubkey | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void insertRepo(SQLiteDatabase db, String name, String address, |     private void insertRepo(SQLiteDatabase db, String name, String address, | ||||||
|                             String description, String version, String enabled, |                             String description, String version, String enabled, | ||||||
|                             String priority, String pubKey) { |                             String priority, String pushRequests, String pubKey) { | ||||||
|         ContentValues values = new ContentValues(); |         ContentValues values = new ContentValues(); | ||||||
|         values.put(RepoTable.Cols.ADDRESS, address); |         values.put(RepoTable.Cols.ADDRESS, address); | ||||||
|         values.put(RepoTable.Cols.NAME, name); |         values.put(RepoTable.Cols.NAME, name); | ||||||
| @ -265,7 +292,21 @@ class DBHelper extends SQLiteOpenHelper { | |||||||
|         values.put(RepoTable.Cols.LAST_ETAG, (String) null); |         values.put(RepoTable.Cols.LAST_ETAG, (String) null); | ||||||
|         values.put(RepoTable.Cols.TIMESTAMP, 0); |         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); |         db.insert(RepoTable.NAME, null, values); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -302,6 +343,7 @@ class DBHelper extends SQLiteOpenHelper { | |||||||
|         removeApkPackageNameColumn(db, oldVersion); |         removeApkPackageNameColumn(db, oldVersion); | ||||||
|         addAppPrefsTable(db, oldVersion); |         addAppPrefsTable(db, oldVersion); | ||||||
|         lowerCaseApkHashes(db, oldVersion); |         lowerCaseApkHashes(db, oldVersion); | ||||||
|  |         supportRepoPushRequests(db, oldVersion); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void lowerCaseApkHashes(SQLiteDatabase db, int oldVersion) { |     private void lowerCaseApkHashes(SQLiteDatabase db, int oldVersion) { | ||||||
| @ -490,13 +532,13 @@ class DBHelper extends SQLiteOpenHelper { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     private void insertNameAndDescription(SQLiteDatabase db, |     private void insertNameAndDescription(SQLiteDatabase db, | ||||||
|             int addressResId, int nameResId, int descriptionResId) { |                                           String name, String address, String description) { | ||||||
|         ContentValues values = new ContentValues(); |         ContentValues values = new ContentValues(); | ||||||
|         values.clear(); |         values.clear(); | ||||||
|         values.put(RepoTable.Cols.NAME, context.getString(nameResId)); |         values.put(RepoTable.Cols.NAME, name); | ||||||
|         values.put(RepoTable.Cols.DESCRIPTION, context.getString(descriptionResId)); |         values.put(RepoTable.Cols.DESCRIPTION, description); | ||||||
|         db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[] { |         db.update(RepoTable.NAME, values, RepoTable.Cols.ADDRESS + " = ?", new String[]{ | ||||||
|                 context.getString(addressResId), |                 address, | ||||||
|         }); |         }); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -770,6 +812,17 @@ class DBHelper extends SQLiteOpenHelper { | |||||||
|                 + ApkTable.Cols.TARGET_SDK_VERSION + " integer"); |                 + 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) { |     private static boolean columnExists(SQLiteDatabase db, String table, String column) { | ||||||
|         Cursor cursor = db.rawQuery("select * from " + table + " limit 0,1", null); |         Cursor cursor = db.rawQuery("select * from " + table + " limit 0,1", null); | ||||||
|         boolean exists = cursor.getColumnIndex(column) != -1; |         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; | package org.fdroid.fdroid.data; | ||||||
| 
 | 
 | ||||||
| import android.content.ContentValues; | 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 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; |     protected long id; | ||||||
| 
 | 
 | ||||||
|     public String address; |     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 */ |     /** When the signed repo index was generated, used to protect against replay attacks */ | ||||||
|     public long timestamp; |     public long timestamp; | ||||||
| 
 | 
 | ||||||
|  |     /** How to treat push requests included in this repo's index XML */ | ||||||
|  |     public int pushRequests = PUSH_REQUEST_IGNORE; | ||||||
|  | 
 | ||||||
|     public Repo() { |     public Repo() { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -101,6 +131,9 @@ public class Repo extends ValueObject { | |||||||
|                 case Cols.TIMESTAMP: |                 case Cols.TIMESTAMP: | ||||||
|                     timestamp = cursor.getLong(i); |                     timestamp = cursor.getLong(i); | ||||||
|                     break; |                     break; | ||||||
|  |                 case Cols.PUSH_REQUESTS: | ||||||
|  |                     pushRequests = cursor.getInt(i); | ||||||
|  |                     break; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| @ -223,5 +256,9 @@ public class Repo extends ValueObject { | |||||||
|         if (values.containsKey(Cols.TIMESTAMP)) { |         if (values.containsKey(Cols.TIMESTAMP)) { | ||||||
|             timestamp = toInt(values.getAsInteger(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 USERNAME     = "username"; | ||||||
|             String PASSWORD     = "password"; |             String PASSWORD     = "password"; | ||||||
|             String TIMESTAMP    = "timestamp"; |             String TIMESTAMP    = "timestamp"; | ||||||
|  |             String PUSH_REQUESTS = "pushRequests"; | ||||||
| 
 | 
 | ||||||
|             String[] ALL = { |             String[] ALL = { | ||||||
|                     _ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT, |                     _ID, ADDRESS, NAME, DESCRIPTION, IN_USE, PRIORITY, SIGNING_CERT, | ||||||
|                     FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP, |                     FINGERPRINT, MAX_AGE, LAST_UPDATED, LAST_ETAG, VERSION, IS_SWAP, | ||||||
|                     USERNAME, PASSWORD, TIMESTAMP, |                     USERNAME, PASSWORD, TIMESTAMP, PUSH_REQUESTS, | ||||||
|             }; |             }; | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  | |||||||
| @ -18,6 +18,8 @@ | |||||||
|         <item>1</item> |         <item>1</item> | ||||||
|         <!-- priority --> |         <!-- priority --> | ||||||
|         <item>10</item> |         <item>10</item> | ||||||
|  |         <!-- push requests --> | ||||||
|  |         <item>ignore</item> | ||||||
|         <!-- pubkey --> |         <!-- pubkey --> | ||||||
|         <item> |         <item> | ||||||
|             3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef |             3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef | ||||||
| @ -37,6 +39,8 @@ | |||||||
|         <item>0</item> |         <item>0</item> | ||||||
|         <!-- priority --> |         <!-- priority --> | ||||||
|         <item>20</item> |         <item>20</item> | ||||||
|  |         <!-- push requests --> | ||||||
|  |         <item>ignore</item> | ||||||
|         <!-- pubkey --> |         <!-- pubkey --> | ||||||
|         <item> |         <item> | ||||||
|             3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef |             3082035e30820246a00302010202044c49cd00300d06092a864886f70d01010505003071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b73301e170d3130303732333137313032345a170d3337313230383137313032345a3071310b300906035504061302554b3110300e06035504081307556e6b6e6f776e3111300f0603550407130857657468657262793110300e060355040a1307556e6b6e6f776e3110300e060355040b1307556e6b6e6f776e311930170603550403131043696172616e2047756c746e69656b7330820122300d06092a864886f70d01010105000382010f003082010a028201010096d075e47c014e7822c89fd67f795d23203e2a8843f53ba4e6b1bf5f2fd0e225938267cfcae7fbf4fe596346afbaf4070fdb91f66fbcdf2348a3d92430502824f80517b156fab00809bdc8e631bfa9afd42d9045ab5fd6d28d9e140afc1300917b19b7c6c4df4a494cf1f7cb4a63c80d734265d735af9e4f09455f427aa65a53563f87b336ca2c19d244fcbba617ba0b19e56ed34afe0b253ab91e2fdb1271f1b9e3c3232027ed8862a112f0706e234cf236914b939bcf959821ecb2a6c18057e070de3428046d94b175e1d89bd795e535499a091f5bc65a79d539a8d43891ec504058acb28c08393b5718b57600a211e803f4a634e5c57f25b9b8c4422c6fd90203010001300d06092a864886f70d0101050500038201010008e4ef699e9807677ff56753da73efb2390d5ae2c17e4db691d5df7a7b60fc071ae509c5414be7d5da74df2811e83d3668c4a0b1abc84b9fa7d96b4cdf30bba68517ad2a93e233b042972ac0553a4801c9ebe07bf57ebe9a3b3d6d663965260e50f3b8f46db0531761e60340a2bddc3426098397fda54044a17e5244549f9869b460ca5e6e216b6f6a2db0580b480ca2afe6ec6b46eedacfa4aa45038809ece0c5978653d6c85f678e7f5a2156d1bedd8117751e64a4b0dcd140f3040b021821a8d93aed8d01ba36db6c82372211fed714d9a32607038cdfd565bd529ffc637212aaa2c224ef22b603eccefb5bf1e085c191d4b24fe742b17ab3f55d4e6f05ef | ||||||
| @ -57,6 +61,8 @@ | |||||||
|         <item>0</item> |         <item>0</item> | ||||||
|         <!-- priority --> |         <!-- priority --> | ||||||
|         <item>10</item> |         <item>10</item> | ||||||
|  |         <!-- push requests --> | ||||||
|  |         <item>ignore</item> | ||||||
|         <!-- pubkey --> |         <!-- pubkey --> | ||||||
|         <item> |         <item> | ||||||
|             308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f |             308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f | ||||||
| @ -76,6 +82,8 @@ | |||||||
|         <item>0</item> |         <item>0</item> | ||||||
|         <!-- priority --> |         <!-- priority --> | ||||||
|         <item>20</item> |         <item>20</item> | ||||||
|  |         <!-- push requests --> | ||||||
|  |         <item>ignore</item> | ||||||
|         <!-- pubkey --> |         <!-- pubkey --> | ||||||
|         <item> |         <item> | ||||||
|             308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f |             308205d8308203c0020900a397b4da7ecda034300d06092a864886f70d01010505003081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f301e170d3134303632363139333931385a170d3431313131303139333931385a3081ad310b30090603550406130255533111300f06035504080c084e657720596f726b3111300f06035504070c084e657720596f726b31143012060355040b0c0b4644726f6964205265706f31193017060355040a0c10477561726469616e2050726f6a656374311d301b06035504030c14677561726469616e70726f6a6563742e696e666f3128302606092a864886f70d0109011619726f6f7440677561726469616e70726f6a6563742e696e666f30820222300d06092a864886f70d01010105000382020f003082020a0282020100b3cd79121b9b883843be3c4482e320809106b0a23755f1dd3c7f46f7d315d7bb2e943486d61fc7c811b9294dcc6b5baac4340f8db2b0d5e14749e7f35e1fc211fdbc1071b38b4753db201c314811bef885bd8921ad86facd6cc3b8f74d30a0b6e2e6e576f906e9581ef23d9c03e926e06d1f033f28bd1e21cfa6a0e3ff5c9d8246cf108d82b488b9fdd55d7de7ebb6a7f64b19e0d6b2ab1380a6f9d42361770d1956701a7f80e2de568acd0bb4527324b1e0973e89595d91c8cc102d9248525ae092e2c9b69f7414f724195b81427f28b1d3d09a51acfe354387915fd9521e8c890c125fc41a12bf34d2a1b304067ab7251e0e9ef41833ce109e76963b0b256395b16b886bca21b831f1408f836146019e7908829e716e72b81006610a2af08301de5d067c9e114a1e5759db8a6be6a3cc2806bcfe6fafd41b5bc9ddddb3dc33d6f605b1ca7d8a9e0ecdd6390d38906649e68a90a717bea80fa220170eea0c86fc78a7e10dac7b74b8e62045a3ecca54e035281fdc9fe5920a855fde3c0be522e3aef0c087524f13d973dff3768158b01a5800a060c06b451ec98d627dd052eda804d0556f60dbc490d94e6e9dea62ffcafb5beffbd9fc38fb2f0d7050004fe56b4dda0a27bc47554e1e0a7d764e17622e71f83a475db286bc7862deee1327e2028955d978272ea76bf0b88e70a18621aba59ff0c5993ef5f0e5d6b6b98e68b70203010001300d06092a864886f70d0101050500038202010079c79c8ef408a20d243d8bd8249fb9a48350dc19663b5e0fce67a8dbcb7de296c5ae7bbf72e98a2020fb78f2db29b54b0e24b181aa1c1d333cc0303685d6120b03216a913f96b96eb838f9bff125306ae3120af838c9fc07ebb5100125436bd24ec6d994d0bff5d065221871f8410daf536766757239bf594e61c5432c9817281b985263bada8381292e543a49814061ae11c92a316e7dc100327b59e3da90302c5ada68c6a50201bda1fcce800b53f381059665dbabeeb0b50eb22b2d7d2d9b0aa7488ca70e67ac6c518adb8e78454a466501e89d81a45bf1ebc350896f2c3ae4b6679ecfbf9d32960d4f5b493125c7876ef36158562371193f600bc511000a67bdb7c664d018f99d9e589868d103d7e0994f166b2ba18ff7e67d8c4da749e44dfae1d930ae5397083a51675c409049dfb626a96246c0015ca696e94ebb767a20147834bf78b07fece3f0872b057c1c519ff882501995237d8206b0b3832f78753ebd8dcbd1d3d9f5ba733538113af6b407d960ec4353c50eb38ab29888238da843cd404ed8f4952f59e4bbc0035fc77a54846a9d419179c46af1b4a3b7fc98e4d312aaa29b9b7d79e739703dc0fa41c7280d5587709277ffa11c3620f5fba985b82c238ba19b17ebd027af9424be0941719919f620dd3bb3c3f11638363708aa11f858e153cf3a69bce69978b90e4a273836100aa1e617ba455cd00426847f | ||||||
|  | |||||||
| @ -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; | package org.fdroid.fdroid; | ||||||
| 
 | 
 | ||||||
| @ -8,6 +29,7 @@ import android.util.Log; | |||||||
| import org.fdroid.fdroid.data.Apk; | import org.fdroid.fdroid.data.Apk; | ||||||
| import org.fdroid.fdroid.data.App; | import org.fdroid.fdroid.data.App; | ||||||
| import org.fdroid.fdroid.data.Repo; | import org.fdroid.fdroid.data.Repo; | ||||||
|  | import org.fdroid.fdroid.data.RepoPushRequest; | ||||||
| import org.fdroid.fdroid.mock.MockRepo; | import org.fdroid.fdroid.mock.MockRepo; | ||||||
| import org.junit.Test; | import org.junit.Test; | ||||||
| import org.junit.runner.RunWith; | 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 |     @Test | ||||||
|     public void testMediumRepo() { |     public void testMediumRepo() { | ||||||
|         Repo expectedRepo = new Repo(); |         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) { |     private void handlerTestSuite(Repo expectedRepo, RepoDetails actualDetails, int appCount, int apkCount, int maxAge, int version) { | ||||||
|         assertNotNull(actualDetails); |         assertNotNull(actualDetails); | ||||||
|         assertFalse(TextUtils.isEmpty(actualDetails.signingCert)); |         assertFalse(TextUtils.isEmpty(actualDetails.signingCert)); | ||||||
| @ -736,6 +814,7 @@ public class RepoXMLHandlerTest { | |||||||
| 
 | 
 | ||||||
|         public List<Apk> apks = new ArrayList<>(); |         public List<Apk> apks = new ArrayList<>(); | ||||||
|         public List<App> apps = new ArrayList<>(); |         public List<App> apps = new ArrayList<>(); | ||||||
|  |         public List<RepoPushRequest> repoPushRequestList = new ArrayList<>(); | ||||||
| 
 | 
 | ||||||
|         @Override |         @Override | ||||||
|         public void receiveRepo(String name, String description, String signingCert, int maxage, int version, long timestamp) { |         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); |             apps.add(app); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|  |         @Override | ||||||
|  |         public void receiveRepoPushRequest(RepoPushRequest repoPushRequest) { | ||||||
|  |             repoPushRequestList.add(repoPushRequest); | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     @NonNull |     @NonNull | ||||||
|     private RepoDetails getFromFile(String indexFilename) { |     private RepoDetails getFromFile(String indexFilename) { | ||||||
|  |         return getFromFile(indexFilename, Repo.PUSH_REQUEST_IGNORE); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     @NonNull | ||||||
|  |     private RepoDetails getFromFile(String indexFilename, int pushRequests) { | ||||||
|         try { |         try { | ||||||
|             SAXParserFactory factory = SAXParserFactory.newInstance(); |             SAXParserFactory factory = SAXParserFactory.newInstance(); | ||||||
|             factory.setNamespaceAware(true); |             factory.setNamespaceAware(true); | ||||||
|             SAXParser parser = factory.newSAXParser(); |             SAXParser parser = factory.newSAXParser(); | ||||||
|             XMLReader reader = parser.getXMLReader(); |             XMLReader reader = parser.getXMLReader(); | ||||||
|             RepoDetails repoDetails = new RepoDetails(); |             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); |             reader.setContentHandler(handler); | ||||||
|             Log.i(TAG, "test file: " + getClass().getClassLoader().getResource(indexFilename)); |             Log.i(TAG, "test file: " + getClass().getClassLoader().getResource(indexFilename)); | ||||||
|             InputStream input = getClass().getClassLoader().getResourceAsStream(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; | package org.fdroid.fdroid.data; | ||||||
| 
 | 
 | ||||||
| import android.app.Application; | import android.app.Application; | ||||||
| @ -93,7 +114,7 @@ public class RepoProviderTest extends FDroidProviderTest { | |||||||
|                     defaultRepos.get(i), |                     defaultRepos.get(i), | ||||||
|                     reposFromXml[offset + 1], // address |                     reposFromXml[offset + 1], // address | ||||||
|                     reposFromXml[offset + 2], // description |                     reposFromXml[offset + 2], // description | ||||||
|                     Utils.calcFingerprint(reposFromXml[offset + 6]), // pubkey |                     Utils.calcFingerprint(reposFromXml[offset + 7]), // pubkey | ||||||
|                     reposFromXml[offset]      // name |                     reposFromXml[offset]      // name | ||||||
|             ); |             ); | ||||||
|         } |         } | ||||||
|  | |||||||
| @ -4,8 +4,13 @@ import org.fdroid.fdroid.data.Repo; | |||||||
| 
 | 
 | ||||||
| public class MockRepo extends Repo { | public class MockRepo extends Repo { | ||||||
| 
 | 
 | ||||||
|     public MockRepo(long repoId) { |     public MockRepo(long id) { | ||||||
|         id = repoId; |         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
	 Hans-Christoph Steiner
						Hans-Christoph Steiner