Allow user to ignore messages about vulnerable apps
This commit is contained in:
parent
5f64985b34
commit
0551b0d1fc
@ -708,11 +708,20 @@ public class AppProvider extends FDroidProvider {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private AppQuerySelection queryInstalledWithKnownVulns() {
|
private AppQuerySelection queryInstalledWithKnownVulns() {
|
||||||
// Include the hash in this check because otherwise any app with any vulnerable version will
|
String apk = getApkTableName();
|
||||||
// get returned.
|
|
||||||
String selection = " antiFeature." + Schema.AntiFeatureTable.Cols.NAME + " = 'KnownVuln' AND " +
|
// Include the hash in this check because otherwise apps with any vulnerable version will
|
||||||
getApkTableName() + "." + ApkTable.Cols.HASH + " = installed." + InstalledAppTable.Cols.HASH;
|
// get returned, rather than just the installed version.
|
||||||
return new AppQuerySelection(selection).requireNaturalInstalledTable().requireNatrualJoinAntiFeatures();
|
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) {
|
static AppQuerySelection queryPackageNames(String packageNames, String packageNameField) {
|
||||||
|
@ -93,6 +93,9 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
|
|||||||
@Nullable
|
@Nullable
|
||||||
private final Button actionButton;
|
private final Button actionButton;
|
||||||
|
|
||||||
|
@Nullable
|
||||||
|
private final Button secondaryButton;
|
||||||
|
|
||||||
private final DisplayImageOptions displayImageOptions;
|
private final DisplayImageOptions displayImageOptions;
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -137,11 +140,16 @@ public abstract class AppListItemController extends RecyclerView.ViewHolder {
|
|||||||
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
|
progressBar = (ProgressBar) itemView.findViewById(R.id.progress_bar);
|
||||||
cancelButton = (ImageButton) itemView.findViewById(R.id.cancel_button);
|
cancelButton = (ImageButton) itemView.findViewById(R.id.cancel_button);
|
||||||
actionButton = (Button) itemView.findViewById(R.id.action_button);
|
actionButton = (Button) itemView.findViewById(R.id.action_button);
|
||||||
|
secondaryButton = (Button) itemView.findViewById(R.id.secondary_button);
|
||||||
|
|
||||||
if (actionButton != null) {
|
if (actionButton != null) {
|
||||||
actionButton.setOnClickListener(onActionClicked);
|
actionButton.setOnClickListener(onActionClicked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (secondaryButton != null) {
|
||||||
|
secondaryButton.setOnClickListener(onSecondaryButtonClicked);
|
||||||
|
}
|
||||||
|
|
||||||
if (cancelButton != null) {
|
if (cancelButton != null) {
|
||||||
cancelButton.setOnClickListener(onCancelDownload);
|
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 (progressBar != null) {
|
||||||
if (viewState.showProgress()) {
|
if (viewState.showProgress()) {
|
||||||
progressBar.setVisibility(View.VISIBLE);
|
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) {
|
protected void onActionButtonPressed(@NonNull App app) {
|
||||||
// When the button says "Run", then launch the app.
|
// When the button says "Run", then launch the app.
|
||||||
if (currentStatus != null && currentStatus.status == AppUpdateStatusManager.Status.Installed) {
|
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")
|
@SuppressWarnings("FieldCanBeLocal")
|
||||||
private final View.OnClickListener onCancelDownload = new View.OnClickListener() {
|
private final View.OnClickListener onCancelDownload = new View.OnClickListener() {
|
||||||
@Override
|
@Override
|
||||||
|
@ -14,6 +14,7 @@ public class AppListItemState {
|
|||||||
private final App app;
|
private final App app;
|
||||||
private CharSequence mainText = null;
|
private CharSequence mainText = null;
|
||||||
private CharSequence actionButtonText = null;
|
private CharSequence actionButtonText = null;
|
||||||
|
private CharSequence secondaryButtonText = null;
|
||||||
private CharSequence statusText = null;
|
private CharSequence statusText = null;
|
||||||
private CharSequence secondaryStatusText = null;
|
private CharSequence secondaryStatusText = null;
|
||||||
private int progressCurrent = -1;
|
private int progressCurrent = -1;
|
||||||
@ -34,6 +35,11 @@ public class AppListItemState {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public AppListItemState showSecondaryButton(CharSequence label) {
|
||||||
|
secondaryButtonText = label;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
public AppListItemState setStatusText(CharSequence text) {
|
public AppListItemState setStatusText(CharSequence text) {
|
||||||
this.statusText = text;
|
this.statusText = text;
|
||||||
return this;
|
return this;
|
||||||
@ -74,6 +80,14 @@ public class AppListItemState {
|
|||||||
return actionButtonText;
|
return actionButtonText;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean shouldShowSecondaryButton() {
|
||||||
|
return secondaryButtonText != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public CharSequence getSecondaryButtonText() {
|
||||||
|
return secondaryButtonText;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean showProgress() {
|
public boolean showProgress() {
|
||||||
return progressCurrent >= 0;
|
return progressCurrent >= 0;
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,8 @@ import org.fdroid.fdroid.AppUpdateStatusManager;
|
|||||||
import org.fdroid.fdroid.R;
|
import org.fdroid.fdroid.R;
|
||||||
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.AppPrefs;
|
||||||
|
import org.fdroid.fdroid.data.AppPrefsProvider;
|
||||||
import org.fdroid.fdroid.data.AppProvider;
|
import org.fdroid.fdroid.data.AppProvider;
|
||||||
import org.fdroid.fdroid.installer.Installer;
|
import org.fdroid.fdroid.installer.Installer;
|
||||||
import org.fdroid.fdroid.installer.InstallerService;
|
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.
|
// TODO: Take into account signature when multi-sig stuff is merged.
|
||||||
if (app.installedVersionCode < app.suggestedVersionCode) {
|
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);
|
actionButtonText = activity.getString(R.string.menu_upgrade);
|
||||||
} else {
|
} 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);
|
actionButtonText = activity.getString(R.string.menu_uninstall);
|
||||||
}
|
}
|
||||||
|
|
||||||
return new AppListItemState(app)
|
return new AppListItemState(app)
|
||||||
.setMainText(mainText)
|
.setMainText(mainText)
|
||||||
.showActionButton(actionButtonText);
|
.showActionButton(actionButtonText)
|
||||||
|
.showSecondaryButton(activity.getString(R.string.updates__app_with_known_vulnerability__ignore));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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() {
|
private void unregisterUninstallReceiver() {
|
||||||
LocalBroadcastManager.getInstance(activity).unregisterReceiver(installReceiver);
|
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() {
|
private final BroadcastReceiver installReceiver = new BroadcastReceiver() {
|
||||||
@Override
|
@Override
|
||||||
public void onReceive(Context context, Intent intent) {
|
public void onReceive(Context context, Intent intent) {
|
||||||
switch (intent.getAction()) {
|
switch (intent.getAction()) {
|
||||||
case Installer.ACTION_UNINSTALL_COMPLETE:
|
case Installer.ACTION_UNINSTALL_COMPLETE:
|
||||||
// This will cause the LoaderManager in UpdatesAdapter to automatically requery for the list of
|
refreshUpdatesList();
|
||||||
// apps with known vulnerabilities (i.e. this app should no longer be in that list).
|
|
||||||
activity.getContentResolver().notifyChange(AppProvider.getInstalledWithKnownVulnsUri(), null);
|
|
||||||
unregisterUninstallReceiver();
|
unregisterUninstallReceiver();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -63,4 +63,16 @@
|
|||||||
app:layout_constraintTop_toBottomOf="@+id/app_name"
|
app:layout_constraintTop_toBottomOf="@+id/app_name"
|
||||||
tools:text="Uninstall"/>
|
tools:text="Uninstall"/>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
android:id="@+id/secondary_button"
|
||||||
|
style="@style/DetailsSecondaryButtonStyleSmall"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginEnd="16dp"
|
||||||
|
android:layout_marginRight="16dp"
|
||||||
|
android:layout_marginTop="8dp"
|
||||||
|
app:layout_constraintEnd_toStartOf="@+id/action_button"
|
||||||
|
app:layout_constraintTop_toBottomOf="@+id/app_name"
|
||||||
|
tools:text="Ignore"/>
|
||||||
|
|
||||||
</android.support.constraint.ConstraintLayout>
|
</android.support.constraint.ConstraintLayout>
|
@ -97,8 +97,9 @@ This often occurs with apps installed via Google Play or other sources, if they
|
|||||||
<string name="updates__tts__download_app">Download</string>
|
<string name="updates__tts__download_app">Download</string>
|
||||||
<string name="updates__tts__download_updates_for_all_apps">Download all updates</string>
|
<string name="updates__tts__download_updates_for_all_apps">Download all updates</string>
|
||||||
|
|
||||||
<string name="updates__app_with_known_vulnerability__uninstall">We found a vulnerability with %1$s. We recommend uninstalling this app immediately.</string>
|
<string name="updates__app_with_known_vulnerability__prompt_uninstall">We found a vulnerability with %1$s. We recommend uninstalling this app immediately.</string>
|
||||||
<string name="updates__app_with_known_vulnerability__upgrade">We found a vulnerability with %1$s. We recommend upgrading to the newest version immediately.</string>
|
<string name="updates__app_with_known_vulnerability__prompt_upgrade">We found a vulnerability with %1$s. We recommend upgrading to the newest version immediately.</string>
|
||||||
|
<string name="updates__app_with_known_vulnerability__ignore">Ignore</string>
|
||||||
|
|
||||||
<string name="updates__hide_updateable_apps">Hide apps</string>
|
<string name="updates__hide_updateable_apps">Hide apps</string>
|
||||||
<string name="updates__show_updateable_apps">Show apps</string>
|
<string name="updates__show_updateable_apps">Show apps</string>
|
||||||
|
@ -24,6 +24,10 @@
|
|||||||
<item name="android:background">@drawable/button_secondary_background_selector</item>
|
<item name="android:background">@drawable/button_secondary_background_selector</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="DetailsSecondaryButtonStyleSmall" parent="DetailsSecondaryButtonStyle">
|
||||||
|
<item name="android:padding">8dp</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
<style name="DetailsMoreButtonStyle">
|
<style name="DetailsMoreButtonStyle">
|
||||||
<item name="android:padding">5dp</item>
|
<item name="android:padding">5dp</item>
|
||||||
<item name="android:textSize">15sp</item>
|
<item name="android:textSize">15sp</item>
|
||||||
|
@ -6,6 +6,8 @@ import android.content.ContentValues;
|
|||||||
import org.fdroid.fdroid.data.Apk;
|
import org.fdroid.fdroid.data.Apk;
|
||||||
import org.fdroid.fdroid.data.ApkProvider;
|
import org.fdroid.fdroid.data.ApkProvider;
|
||||||
import org.fdroid.fdroid.data.App;
|
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.data.AppProvider;
|
||||||
import org.fdroid.fdroid.data.FDroidProviderTest;
|
import org.fdroid.fdroid.data.FDroidProviderTest;
|
||||||
import org.fdroid.fdroid.data.InstalledAppTestUtils;
|
import org.fdroid.fdroid.data.InstalledAppTestUtils;
|
||||||
@ -107,6 +109,21 @@ public class AntiFeaturesTest extends FDroidProviderTest {
|
|||||||
assertEquals(0, installed.size());
|
assertEquals(0, installed.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void allVulnerableButIgnored() {
|
||||||
|
install(allVuln, 101);
|
||||||
|
List<App> installed = AppProvider.Helper.findInstalledAppsWithKnownVulns(context);
|
||||||
|
assertEquals(1, installed.size());
|
||||||
|
|
||||||
|
App app = installed.get(0);
|
||||||
|
AppPrefs prefs = app.getPrefs(context);
|
||||||
|
prefs.ignoreVulnerabilities = true;
|
||||||
|
AppPrefsProvider.Helper.update(context, app, prefs);
|
||||||
|
|
||||||
|
List<App> installedButIgnored = AppProvider.Helper.findInstalledAppsWithKnownVulns(context);
|
||||||
|
assertEquals(0, installedButIgnored.size());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void antiFeaturesSaveCorrectly() {
|
public void antiFeaturesSaveCorrectly() {
|
||||||
List<Apk> notVulnApks = ApkProvider.Helper.findByPackageName(context, notVuln.packageName);
|
List<Apk> notVulnApks = ApkProvider.Helper.findByPackageName(context, notVuln.packageName);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user