From 0551b0d1fc6b2f0d23f63f8e939bb7e5d726caec Mon Sep 17 00:00:00 2001 From: Peter Serwylo Date: Thu, 6 Jul 2017 16:03:27 +1000 Subject: [PATCH] Allow user to ignore messages about vulnerable apps --- .../org/fdroid/fdroid/data/AppProvider.java | 19 ++++++++--- .../views/apps/AppListItemController.java | 32 +++++++++++++++++++ .../fdroid/views/apps/AppListItemState.java | 14 ++++++++ .../items/KnownVulnAppListItemController.java | 29 +++++++++++++---- .../res/layout/known_vuln_app_list_item.xml | 12 +++++++ app/src/main/res/values/strings.xml | 5 +-- app/src/main/res/values/styles_detail.xml | 4 +++ .../org/fdroid/fdroid/AntiFeaturesTest.java | 17 ++++++++++ 8 files changed, 119 insertions(+), 13 deletions(-) diff --git a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java index d552647d2..30e77857b 100644 --- a/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java +++ b/app/src/main/java/org/fdroid/fdroid/data/AppProvider.java @@ -708,11 +708,20 @@ public class AppProvider extends FDroidProvider { } private AppQuerySelection queryInstalledWithKnownVulns() { - // Include the hash in this check because otherwise any app with any vulnerable version will - // get returned. - String selection = " antiFeature." + Schema.AntiFeatureTable.Cols.NAME + " = 'KnownVuln' AND " + - getApkTableName() + "." + ApkTable.Cols.HASH + " = installed." + InstalledAppTable.Cols.HASH; - return new AppQuerySelection(selection).requireNaturalInstalledTable().requireNatrualJoinAntiFeatures(); + String apk = getApkTableName(); + + // Include the hash in this check because otherwise apps with any vulnerable version will + // get returned, rather than just the installed version. + String compareHash = apk + "." + ApkTable.Cols.HASH + " = installed." + InstalledAppTable.Cols.HASH; + String knownVuln = " antiFeature." + Schema.AntiFeatureTable.Cols.NAME + " = 'KnownVuln' "; + String notIgnored = " COALESCE(prefs." + AppPrefsTable.Cols.IGNORE_VULNERABILITIES + ", 0) = 0 "; + + String selection = knownVuln + " AND " + compareHash + " AND " + notIgnored; + + return new AppQuerySelection(selection) + .requireNaturalInstalledTable() + .requireNatrualJoinAntiFeatures() + .requireLeftJoinPrefs(); } static AppQuerySelection queryPackageNames(String packageNames, String packageNameField) { diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java index 8476e04ad..b9a0b1168 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemController.java @@ -93,6 +93,9 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { @Nullable private final Button actionButton; + @Nullable + private final Button secondaryButton; + private final DisplayImageOptions displayImageOptions; @Nullable @@ -137,11 +140,16 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar); cancelButton = (ImageButton) itemView.findViewById(R.id.cancel_button); actionButton = (Button) itemView.findViewById(R.id.action_button); + secondaryButton = (Button) itemView.findViewById(R.id.secondary_button); if (actionButton != null) { actionButton.setOnClickListener(onActionClicked); } + if (secondaryButton != null) { + secondaryButton.setOnClickListener(onSecondaryButtonClicked); + } + if (cancelButton != null) { cancelButton.setOnClickListener(onCancelDownload); } @@ -213,6 +221,15 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { } } + if (secondaryButton != null) { + if (viewState.shouldShowSecondaryButton()) { + secondaryButton.setVisibility(View.VISIBLE); + secondaryButton.setText(viewState.getSecondaryButtonText()); + } else { + secondaryButton.setVisibility(View.GONE); + } + } + if (progressBar != null) { if (viewState.showProgress()) { progressBar.setVisibility(View.VISIBLE); @@ -392,6 +409,18 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { } }; + @SuppressWarnings("FieldCanBeLocal") + private final View.OnClickListener onSecondaryButtonClicked = new View.OnClickListener() { + @Override + public void onClick(View v) { + if (currentApp == null) { + return; + } + + onSecondaryButtonPressed(currentApp); + } + }; + protected void onActionButtonPressed(@NonNull App app) { // When the button says "Run", then launch the app. if (currentStatus != null && currentStatus.status == AppUpdateStatusManager.Status.Installed) { @@ -441,6 +470,9 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder { } } + /** To be overridden by subclasses if desired */ + protected void onSecondaryButtonPressed(@NonNull App app) { } + @SuppressWarnings("FieldCanBeLocal") private final View.OnClickListener onCancelDownload = new View.OnClickListener() { @Override diff --git a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java index 2a1e31fe8..2fef4de81 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java +++ b/app/src/main/java/org/fdroid/fdroid/views/apps/AppListItemState.java @@ -14,6 +14,7 @@ public class AppListItemState { private final App app; private CharSequence mainText = null; private CharSequence actionButtonText = null; + private CharSequence secondaryButtonText = null; private CharSequence statusText = null; private CharSequence secondaryStatusText = null; private int progressCurrent = -1; @@ -34,6 +35,11 @@ public class AppListItemState { return this; } + public AppListItemState showSecondaryButton(CharSequence label) { + secondaryButtonText = label; + return this; + } + public AppListItemState setStatusText(CharSequence text) { this.statusText = text; return this; @@ -74,6 +80,14 @@ public class AppListItemState { return actionButtonText; } + public boolean shouldShowSecondaryButton() { + return secondaryButtonText != null; + } + + public CharSequence getSecondaryButtonText() { + return secondaryButtonText; + } + public boolean showProgress() { return progressCurrent >= 0; } diff --git a/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java b/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java index a466ae98e..69f744aca 100644 --- a/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java +++ b/app/src/main/java/org/fdroid/fdroid/views/updates/items/KnownVulnAppListItemController.java @@ -14,6 +14,8 @@ import org.fdroid.fdroid.AppUpdateStatusManager; import org.fdroid.fdroid.R; import org.fdroid.fdroid.data.Apk; import org.fdroid.fdroid.data.App; +import org.fdroid.fdroid.data.AppPrefs; +import org.fdroid.fdroid.data.AppPrefsProvider; import org.fdroid.fdroid.data.AppProvider; import org.fdroid.fdroid.installer.Installer; import org.fdroid.fdroid.installer.InstallerService; @@ -39,16 +41,17 @@ public class KnownVulnAppListItemController extends AppListItemController { // TODO: Take into account signature when multi-sig stuff is merged. if (app.installedVersionCode < app.suggestedVersionCode) { - mainText = activity.getString(R.string.updates__app_with_known_vulnerability__upgrade, app.name); + mainText = activity.getString(R.string.updates__app_with_known_vulnerability__prompt_upgrade, app.name); actionButtonText = activity.getString(R.string.menu_upgrade); } else { - mainText = activity.getString(R.string.updates__app_with_known_vulnerability__uninstall, app.name); + mainText = activity.getString(R.string.updates__app_with_known_vulnerability__prompt_uninstall, app.name); actionButtonText = activity.getString(R.string.menu_uninstall); } return new AppListItemState(app) .setMainText(mainText) - .showActionButton(actionButtonText); + .showActionButton(actionButtonText) + .showSecondaryButton(activity.getString(R.string.updates__app_with_known_vulnerability__ignore)); } @Override @@ -69,18 +72,32 @@ public class KnownVulnAppListItemController extends AppListItemController { } } + @Override + protected void onSecondaryButtonPressed(@NonNull App app) { + AppPrefs prefs = app.getPrefs(activity); + prefs.ignoreVulnerabilities = true; + AppPrefsProvider.Helper.update(activity, app, prefs); + refreshUpdatesList(); + } + private void unregisterUninstallReceiver() { LocalBroadcastManager.getInstance(activity).unregisterReceiver(installReceiver); } + /** + * Trigger the LoaderManager in UpdatesAdapter to automatically requery for the list of + * apps with known vulnerabilities (i.e. this app should no longer be in that list). + */ + private void refreshUpdatesList() { + activity.getContentResolver().notifyChange(AppProvider.getInstalledWithKnownVulnsUri(), null); + } + private final BroadcastReceiver installReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { switch (intent.getAction()) { case Installer.ACTION_UNINSTALL_COMPLETE: - // This will cause the LoaderManager in UpdatesAdapter to automatically requery for the list of - // apps with known vulnerabilities (i.e. this app should no longer be in that list). - activity.getContentResolver().notifyChange(AppProvider.getInstalledWithKnownVulnsUri(), null); + refreshUpdatesList(); unregisterUninstallReceiver(); break; diff --git a/app/src/main/res/layout/known_vuln_app_list_item.xml b/app/src/main/res/layout/known_vuln_app_list_item.xml index 6420162fd..80a4ff265 100644 --- a/app/src/main/res/layout/known_vuln_app_list_item.xml +++ b/app/src/main/res/layout/known_vuln_app_list_item.xml @@ -63,4 +63,16 @@ app:layout_constraintTop_toBottomOf="@+id/app_name" tools:text="Uninstall"/> +