From a7aa554f66ee57a1dac0d5af422dd8f87adc3961 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Dominik=20Sch=C3=BCrmann?= Date: Mon, 18 May 2015 11:47:33 +0200 Subject: [PATCH] Remove root installer --- F-Droid/res/values/strings.xml | 2 - F-Droid/res/xml/preferences.xml | 4 - .../src/org/fdroid/fdroid/Preferences.java | 6 - .../fdroid/installer/CheckRootAsyncTask.java | 76 ----- .../fdroid/fdroid/installer/Installer.java | 28 -- .../fdroid/installer/RootInstaller.java | 266 ------------------ .../views/fragments/PreferencesFragment.java | 62 ---- 7 files changed, 444 deletions(-) delete mode 100644 F-Droid/src/org/fdroid/fdroid/installer/CheckRootAsyncTask.java delete mode 100644 F-Droid/src/org/fdroid/fdroid/installer/RootInstaller.java diff --git a/F-Droid/res/values/strings.xml b/F-Droid/res/values/strings.xml index 31d985aad..ce6e74710 100644 --- a/F-Droid/res/values/strings.xml +++ b/F-Droid/res/values/strings.xml @@ -25,8 +25,6 @@ Notify when updates are available Update history Days to consider apps new or recent: %s - Install using root access - Request root access to install, update, and remove packages Install using system-permissions Use system permissions to install, update, and remove packages Uninstall F-Droid diff --git a/F-Droid/res/xml/preferences.xml b/F-Droid/res/xml/preferences.xml index f89fb09bd..ac9a9f29b 100644 --- a/F-Droid/res/xml/preferences.xml +++ b/F-Droid/res/xml/preferences.xml @@ -84,10 +84,6 @@ - - * - * 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.installer; - -import android.app.ProgressDialog; -import android.content.Context; -import android.os.AsyncTask; -import android.view.ContextThemeWrapper; - -import org.fdroid.fdroid.FDroidApp; -import org.fdroid.fdroid.R; - -import eu.chainfire.libsuperuser.Shell; - -public class CheckRootAsyncTask extends AsyncTask { - ProgressDialog mDialog; - final Context mContext; - final CheckRootCallback mCallback; - - public interface CheckRootCallback { - void onRootCheck(boolean rootGranted); - } - - public CheckRootAsyncTask(Context context, CheckRootCallback callback) { - super(); - this.mContext = context; - this.mCallback = callback; - } - - @Override - protected void onPreExecute() { - super.onPreExecute(); - - // if the dialog is displayed from the application class, design is missing - // hack to get holo design (which is not automatically applied due to activity's Theme.NoDisplay - ContextThemeWrapper theme = new ContextThemeWrapper(mContext, FDroidApp.getCurThemeResId()); - - mDialog = new ProgressDialog(theme); - mDialog.setMessage(mContext.getString(R.string.requesting_root_access_body)); - mDialog.setIndeterminate(true); - mDialog.setCancelable(false); - mDialog.show(); - } - - @Override - protected Boolean doInBackground(Void... params) { - return Shell.SU.available(); - } - - @Override - protected void onPostExecute(Boolean result) { - super.onPostExecute(result); - - mDialog.dismiss(); - - mCallback.onRootCheck(result); - } - -} diff --git a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java index 30e110ba1..0d42f1a19 100644 --- a/F-Droid/src/org/fdroid/fdroid/installer/Installer.java +++ b/F-Droid/src/org/fdroid/fdroid/installer/Installer.java @@ -95,28 +95,10 @@ abstract public class Installer { /** * Creates a new Installer for installing/deleting processes starting from * an Activity - * - * @param activity - * @param pm - * @param callback - * @return - * @throws AndroidNotCompatibleException */ public static Installer getActivityInstaller(Activity activity, PackageManager pm, InstallerCallback callback) { - // if root installer has been activated in preferences -> RootInstaller - boolean isRootInstallerEnabled = Preferences.get().isRootInstallerEnabled(); - if (isRootInstallerEnabled) { - Log.d(TAG, "root installer preference enabled -> RootInstaller"); - - try { - return new RootInstaller(activity, pm, callback); - } catch (AndroidNotCompatibleException e) { - Log.e(TAG, "Android not compatible with RootInstaller!", e); - } - } - // system permissions and pref enabled -> SystemInstaller boolean isSystemInstallerEnabled = Preferences.get().isSystemInstallerEnabled(); if (isSystemInstallerEnabled) { @@ -161,16 +143,6 @@ abstract public class Installer { public static Installer getUnattendedInstaller(Context context, PackageManager pm, InstallerCallback callback) throws AndroidNotCompatibleException { - // if root installer has been activated in preferences -> RootInstaller - boolean useRootInstaller = Preferences.get().isRootInstallerEnabled(); - if (useRootInstaller) { - try { - return new RootInstaller(context, pm, callback); - } catch (AndroidNotCompatibleException e) { - Log.e(TAG, "Android not compatible with RootInstaller!", e); - } - } - if (hasSystemPermissions(context, pm)) { // we have system permissions! return new SystemInstaller(context, pm, callback); diff --git a/F-Droid/src/org/fdroid/fdroid/installer/RootInstaller.java b/F-Droid/src/org/fdroid/fdroid/installer/RootInstaller.java deleted file mode 100644 index 53d3627cd..000000000 --- a/F-Droid/src/org/fdroid/fdroid/installer/RootInstaller.java +++ /dev/null @@ -1,266 +0,0 @@ -/* - * Copyright (C) 2014 Dominik Schürmann - * - * 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.installer; - -import android.content.Context; -import android.content.Intent; -import android.content.pm.PackageManager; -import android.util.Log; - -import java.io.File; -import java.util.ArrayList; -import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import eu.chainfire.libsuperuser.Shell; - -/** - * Installer using a root shell and "pm install", "pm uninstall" commands - */ -public class RootInstaller extends Installer { - - private static final String TAG = "RootInstaller"; - - Shell.Interactive rootSession; - - public RootInstaller(Context context, PackageManager pm, InstallerCallback callback) - throws AndroidNotCompatibleException { - super(context, pm, callback); - } - - private Shell.Builder createShellBuilder() { - return new Shell.Builder() - .useSU() - .setWantSTDERR(true) - .setWatchdogTimeout(30) - .setMinimalLogging(false); - } - - @Override - protected void installPackageInternal(final File apkFile) throws AndroidNotCompatibleException { - rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() { - - // Callback to report whether the shell was successfully - // started up - @Override - public void onCommandResult(int commandCode, int exitCode, List output) { - if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) { - // NOTE: Additional exit codes: - // Shell.OnCommandResultListener.SHELL_WRONG_UID - // Shell.OnCommandResultListener.SHELL_EXEC_FAILED - - Log.e(TAG, "Error opening root shell with exitCode " + exitCode); - mCallback.onError(InstallerCallback.OPERATION_INSTALL, - InstallerCallback.ERROR_CODE_OTHER); - } else { - addInstallCommand(apkFile); - } - } - }); - } - - @Override - protected void installPackageInternal(final List apkFiles) - throws AndroidNotCompatibleException { - rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() { - - // Callback to report whether the shell was successfully - // started up - @Override - public void onCommandResult(int commandCode, int exitCode, List output) { - if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) { - // NOTE: Additional exit codes: - // Shell.OnCommandResultListener.SHELL_WRONG_UID - // Shell.OnCommandResultListener.SHELL_EXEC_FAILED - - Log.e(TAG, "Error opening root shell with exitCode " + exitCode); - mCallback.onError(InstallerCallback.OPERATION_INSTALL, - InstallerCallback.ERROR_CODE_OTHER); - } else { - addInstallCommand(apkFiles); - } - } - }); - } - - @Override - protected void deletePackageInternal(final String packageName) - throws AndroidNotCompatibleException { - rootSession = createShellBuilder().open(new Shell.OnCommandResultListener() { - - // Callback to report whether the shell was successfully - // started up - @Override - public void onCommandResult(int commandCode, int exitCode, List output) { - if (exitCode != Shell.OnCommandResultListener.SHELL_RUNNING) { - // NOTE: Additional exit codes: - // Shell.OnCommandResultListener.SHELL_WRONG_UID - // Shell.OnCommandResultListener.SHELL_EXEC_FAILED - - Log.e(TAG, "Error opening root shell with exitCode " + exitCode); - mCallback.onError(InstallerCallback.OPERATION_DELETE, - InstallerCallback.ERROR_CODE_OTHER); - } else { - addDeleteCommand(packageName); - } - } - }); - - } - - @Override - public boolean handleOnActivityResult(int requestCode, int resultCode, Intent data) { - // no need to handle onActivityResult - return false; - } - - private void addInstallCommand(File apkFile) { - // Like package names, apk files should also only contain letters, numbers, dots, or underscore, - // e.g., org.fdroid.fdroid_9.apk - if (!isValidPackageName(apkFile.getName())) { - Log.e(TAG, "File name is not valid (contains characters other than letters, numbers, dots, or underscore): " - + apkFile.getName()); - mCallback.onError(InstallerCallback.OPERATION_DELETE, - InstallerCallback.ERROR_CODE_OTHER); - return; - } - - rootSession.addCommand("pm install -dr \"" + apkFile.getAbsolutePath() + "\"", 0, - new Shell.OnCommandResultListener() { - public void onCommandResult(int commandCode, int exitCode, List output) { - // close su shell - rootSession.close(); - - if (exitCode < 0) { - Log.e(TAG, "Install failed with exit code " + exitCode); - mCallback.onError(InstallerCallback.OPERATION_INSTALL, - InstallerCallback.ERROR_CODE_OTHER); - } else { - mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); - } - } - }); - } - - private void addInstallCommand(List apkFiles) { - List commands = new ArrayList<>(); - String pm = "pm install -dr "; - for (File apkFile : apkFiles) { - // see addInstallCommand() - if (!isValidPackageName(apkFile.getName())) { - Log.e(TAG, "File name is not valid (contains characters other than letters, numbers, dots, or underscore): " - + apkFile.getName()); - mCallback.onError(InstallerCallback.OPERATION_DELETE, - InstallerCallback.ERROR_CODE_OTHER); - return; - } - commands.add(pm + "\"" + apkFile.getAbsolutePath() + "\""); - } - - rootSession.addCommand(commands, 0, - new Shell.OnCommandResultListener() { - public void onCommandResult(int commandCode, int exitCode, - List output) { - // close su shell - rootSession.close(); - - if (exitCode < 0) { - Log.e(TAG, "Install failed with exit code " + exitCode); - mCallback.onError(InstallerCallback.OPERATION_INSTALL, - InstallerCallback.ERROR_CODE_OTHER); - } else { - mCallback.onSuccess(InstallerCallback.OPERATION_INSTALL); - } - } - }); - - } - - private void addDeleteCommand(String packageName) { - if (!isValidPackageName(packageName)) { - Log.e(TAG, "Package name is not valid (contains characters other than letters, numbers, dots, or underscore): " - + packageName); - mCallback.onError(InstallerCallback.OPERATION_DELETE, - InstallerCallback.ERROR_CODE_OTHER); - return; - } - - rootSession.addCommand("pm uninstall \"" + packageName + "\"", 0, - new Shell.OnCommandResultListener() { - public void onCommandResult(int commandCode, int exitCode, List output) { - // close su shell - rootSession.close(); - - if (exitCode < 0) { - Log.e(TAG, "Delete failed with exit code " + exitCode); - mCallback.onError(InstallerCallback.OPERATION_DELETE, - InstallerCallback.ERROR_CODE_OTHER); - } else { - mCallback.onSuccess(InstallerCallback.OPERATION_DELETE); - } - } - }); - } - - @Override - public boolean supportsUnattendedOperations() { - return true; - } - - private static final Pattern PACKAGE_NAME_BLACKLIST = Pattern.compile("[^a-zA-Z0-9\\.\\_]"); - - /** - * Package names should only contain letters, numbers, dots, and underscores! - * Prevent injection attacks with app names like ";touch $'\057data\057injected'" - * - * @param packageName - * @return - */ - private boolean isValidPackageName(String packageName) { - Matcher matcher = PACKAGE_NAME_BLACKLIST.matcher(packageName); - return !matcher.find(); - } - - /** - * pm install [-l] [-r] [-t] [-i INSTALLER_PACKAGE_NAME] [-s] [-f] [--algo - * --key --iv ] [--originating-uri - * ] [--referrer ] PATH - *

- * pm install: installs a package to the system. - *

- * Options:
- * -l: install the package with FORWARD_LOCK.
- * -r: reinstall an existing app, keeping its data.
- * -t: allow test .apks to be installed.
- * -i: specify the installer package name.
- * -s: install package on sdcard.
- * -f: install package on internal flash.
- * -d: allow version code downgrade.
- *

- * pm uninstall [-k] PACKAGE - *

- * pm uninstall: removes a package from the system. - *

- * Options:
- * -k: keep the data and cache directories around after package removal. - */ - -} diff --git a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java index e0fd1098d..b12fee0d4 100644 --- a/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java +++ b/F-Droid/src/org/fdroid/fdroid/views/fragments/PreferencesFragment.java @@ -19,7 +19,6 @@ import org.fdroid.fdroid.Preferences; import org.fdroid.fdroid.PreferencesActivity; import org.fdroid.fdroid.R; import org.fdroid.fdroid.Utils; -import org.fdroid.fdroid.installer.CheckRootAsyncTask; import org.fdroid.fdroid.installer.InstallIntoSystemDialogActivity; import org.fdroid.fdroid.installer.Installer; @@ -45,7 +44,6 @@ public class PreferencesFragment extends PreferenceFragment Preferences.PREF_LANGUAGE, Preferences.PREF_CACHE_APK, Preferences.PREF_EXPERT, - Preferences.PREF_ROOT_INSTALLER, Preferences.PREF_SYSTEM_INSTALLER, Preferences.PREF_ENABLE_PROXY, Preferences.PREF_PROXY_HOST, @@ -162,10 +160,6 @@ public class PreferencesFragment extends PreferenceFragment checkSummary(key, R.string.expert_on); break; - case Preferences.PREF_ROOT_INSTALLER: - checkSummary(key, R.string.root_installer_on); - break; - case Preferences.PREF_SYSTEM_INSTALLER: checkSummary(key, R.string.system_installer_on); break; @@ -196,61 +190,6 @@ public class PreferencesFragment extends PreferenceFragment } } - /** - * Initializes RootInstaller preference. This method ensures that the preference can only be checked and persisted - * when the user grants root access for F-Droid. - */ - protected void initRootInstallerPreference() { - CheckBoxPreference pref = (CheckBoxPreference) findPreference(Preferences.PREF_ROOT_INSTALLER); - - // we are handling persistence ourself! - pref.setPersistent(false); - - pref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() { - - @Override - public boolean onPreferenceClick(Preference preference) { - final CheckBoxPreference pref = (CheckBoxPreference) preference; - - if (pref.isChecked()) { - CheckRootAsyncTask checkTask = new CheckRootAsyncTask(getActivity(), new CheckRootAsyncTask.CheckRootCallback() { - - @Override - public void onRootCheck(boolean rootGranted) { - if (rootGranted) { - // root access granted - SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); - editor.putBoolean(Preferences.PREF_ROOT_INSTALLER, true); - editor.commit(); - pref.setChecked(true); - } else { - // root access denied - SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); - editor.putBoolean(Preferences.PREF_ROOT_INSTALLER, false); - editor.commit(); - pref.setChecked(false); - - AlertDialog.Builder alertBuilder = new AlertDialog.Builder(getActivity()); - alertBuilder.setTitle(R.string.root_access_denied_title); - alertBuilder.setMessage(getActivity().getString(R.string.root_access_denied_body)); - alertBuilder.setNeutralButton(android.R.string.ok, null); - alertBuilder.create().show(); - } - } - }); - checkTask.execute(); - } else { - SharedPreferences.Editor editor = pref.getSharedPreferences().edit(); - editor.putBoolean(Preferences.PREF_ROOT_INSTALLER, false); - editor.commit(); - pref.setChecked(false); - } - - return true; - } - }); - } - /** * Initializes SystemInstaller preference, which can only be enabled when F-Droid is installed as a system-app */ @@ -352,7 +291,6 @@ public class PreferencesFragment extends PreferenceFragment updateSummary(key, false); } - initRootInstallerPreference(); initSystemInstallerPreference(); initUninstallSystemAppPreference(); }