diff --git a/.gitmodules b/.gitmodules index 849508c4b..9d4e0f9dd 100644 --- a/.gitmodules +++ b/.gitmodules @@ -22,6 +22,3 @@ path = extern/safeslinger-exchange url = https://github.com/open-keychain/exchange-android ignore = dirty -[submodule "extern/NetCipher"] - path = extern/NetCipher - url = https://github.com/open-keychain/NetCipher.git diff --git a/OpenKeychain/build.gradle b/OpenKeychain/build.gradle index 5db751bfa..129304b70 100644 --- a/OpenKeychain/build.gradle +++ b/OpenKeychain/build.gradle @@ -61,9 +61,6 @@ dependencies { compile project(':extern:minidns') compile project(':extern:KeybaseLib:Lib') compile project(':extern:safeslinger-exchange') - compile (project( ':extern:NetCipher:libnetcipher')) { - exclude group: 'com.madgag.spongycastle' // we're already adding it above, transitive dependency - } } // Output of ./gradlew -q calculateChecksums diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java new file mode 100644 index 000000000..d9566be4a --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/OrbotHelper.java @@ -0,0 +1,124 @@ + +package info.guardianproject.onionkit.ui; + +import android.app.Activity; +import android.app.AlertDialog; +import android.content.Context; +import android.content.DialogInterface; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.net.Uri; + +import info.guardianproject.onionkit.R; + +public class OrbotHelper { + + private final static int REQUEST_CODE_STATUS = 100; + + public final static String ORBOT_PACKAGE_NAME = "org.torproject.android"; + public final static String TOR_BIN_PATH = "/data/data/org.torproject.android/app_bin/tor"; + + public final static String ACTION_START_TOR = "org.torproject.android.START_TOR"; + public final static String ACTION_REQUEST_HS = "org.torproject.android.REQUEST_HS_PORT"; + public final static int HS_REQUEST_CODE = 9999; + + private Context mContext = null; + + public OrbotHelper(Context context) + { + mContext = context; + } + + public boolean isOrbotRunning() + { + int procId = TorServiceUtils.findProcessId(TOR_BIN_PATH); + + return (procId != -1); + } + + public boolean isOrbotInstalled() + { + return isAppInstalled(ORBOT_PACKAGE_NAME); + } + + private boolean isAppInstalled(String uri) { + PackageManager pm = mContext.getPackageManager(); + boolean installed = false; + try { + pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES); + installed = true; + } catch (PackageManager.NameNotFoundException e) { + installed = false; + } + return installed; + } + + public void promptToInstall(Activity activity) + { + String uriMarket = activity.getString(R.string.market_orbot); + // show dialog - install from market, f-droid or direct APK + showDownloadDialog(activity, activity.getString(R.string.install_orbot_), + activity.getString(R.string.you_must_have_orbot), + activity.getString(R.string.yes), activity.getString(R.string.no), uriMarket); + } + + private static AlertDialog showDownloadDialog(final Activity activity, + CharSequence stringTitle, CharSequence stringMessage, CharSequence stringButtonYes, + CharSequence stringButtonNo, final String uriString) { + AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity); + downloadDialog.setTitle(stringTitle); + downloadDialog.setMessage(stringMessage); + downloadDialog.setPositiveButton(stringButtonYes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + Uri uri = Uri.parse(uriString); + Intent intent = new Intent(Intent.ACTION_VIEW, uri); + activity.startActivity(intent); + } + }); + downloadDialog.setNegativeButton(stringButtonNo, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + } + }); + return downloadDialog.show(); + } + + public void requestOrbotStart(final Activity activity) + { + + AlertDialog.Builder downloadDialog = new AlertDialog.Builder(activity); + downloadDialog.setTitle(R.string.start_orbot_); + downloadDialog + .setMessage(R.string.orbot_doesn_t_appear_to_be_running_would_you_like_to_start_it_up_and_connect_to_tor_); + downloadDialog.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + activity.startActivityForResult(getOrbotStartIntent(), 1); + } + }); + downloadDialog.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialogInterface, int i) { + } + }); + downloadDialog.show(); + + } + + public void requestHiddenServiceOnPort(Activity activity, int port) + { + Intent intent = new Intent(ACTION_REQUEST_HS); + intent.setPackage(ORBOT_PACKAGE_NAME); + intent.putExtra("hs_port", port); + + activity.startActivityForResult(intent, HS_REQUEST_CODE); + } + + public static Intent getOrbotStartIntent() { + Intent intent = new Intent(ACTION_START_TOR); + intent.setPackage(ORBOT_PACKAGE_NAME); + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + return intent; + } +} diff --git a/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java new file mode 100644 index 000000000..80a812344 --- /dev/null +++ b/OpenKeychain/src/main/java/org/sufficientlysecure/keychain/util/orbot/TorServiceUtils.java @@ -0,0 +1,234 @@ +/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */ +/* See LICENSE for licensing information */ + +package info.guardianproject.onionkit.ui; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.net.URLEncoder; +import java.util.StringTokenizer; + +import android.util.Log; + +public class TorServiceUtils { + + private final static String TAG = "TorUtils"; + // various console cmds + public final static String SHELL_CMD_CHMOD = "chmod"; + public final static String SHELL_CMD_KILL = "kill -9"; + public final static String SHELL_CMD_RM = "rm"; + public final static String SHELL_CMD_PS = "ps"; + public final static String SHELL_CMD_PIDOF = "pidof"; + + public final static String CHMOD_EXE_VALUE = "700"; + + public static boolean isRootPossible() + { + + StringBuilder log = new StringBuilder(); + + try { + + // Check if Superuser.apk exists + File fileSU = new File("/system/app/Superuser.apk"); + if (fileSU.exists()) + return true; + + fileSU = new File("/system/app/superuser.apk"); + if (fileSU.exists()) + return true; + + fileSU = new File("/system/bin/su"); + if (fileSU.exists()) + { + String[] cmd = { + "su" + }; + int exitCode = TorServiceUtils.doShellCommand(cmd, log, false, true); + if (exitCode != 0) + return false; + else + return true; + } + + // Check for 'su' binary + String[] cmd = { + "which su" + }; + int exitCode = TorServiceUtils.doShellCommand(cmd, log, false, true); + + if (exitCode == 0) { + Log.d(TAG, "root exists, but not sure about permissions"); + return true; + + } + + } catch (IOException e) { + // this means that there is no root to be had (normally) so we won't + // log anything + Log.e(TAG, "Error checking for root access", e); + + } catch (Exception e) { + Log.e(TAG, "Error checking for root access", e); + // this means that there is no root to be had (normally) + } + + Log.e(TAG, "Could not acquire root permissions"); + + return false; + } + + public static int findProcessId(String command) + { + int procId = -1; + + try + { + procId = findProcessIdWithPidOf(command); + + if (procId == -1) + procId = findProcessIdWithPS(command); + } catch (Exception e) + { + try + { + procId = findProcessIdWithPS(command); + } catch (Exception e2) + { + Log.e(TAG, "Unable to get proc id for command: " + URLEncoder.encode(command), e2); + } + } + + return procId; + } + + // use 'pidof' command + public static int findProcessIdWithPidOf(String command) throws Exception + { + + int procId = -1; + + Runtime r = Runtime.getRuntime(); + + Process procPs = null; + + String baseName = new File(command).getName(); + // fix contributed my mikos on 2010.12.10 + procPs = r.exec(new String[] { + SHELL_CMD_PIDOF, baseName + }); + // procPs = r.exec(SHELL_CMD_PIDOF); + + BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream())); + String line = null; + + while ((line = reader.readLine()) != null) + { + + try + { + // this line should just be the process id + procId = Integer.parseInt(line.trim()); + break; + } catch (NumberFormatException e) + { + Log.e("TorServiceUtils", "unable to parse process pid: " + line, e); + } + } + + return procId; + + } + + // use 'ps' command + public static int findProcessIdWithPS(String command) throws Exception + { + + int procId = -1; + + Runtime r = Runtime.getRuntime(); + + Process procPs = null; + + procPs = r.exec(SHELL_CMD_PS); + + BufferedReader reader = new BufferedReader(new InputStreamReader(procPs.getInputStream())); + String line = null; + + while ((line = reader.readLine()) != null) + { + if (line.indexOf(' ' + command) != -1) + { + + StringTokenizer st = new StringTokenizer(line, " "); + st.nextToken(); // proc owner + + procId = Integer.parseInt(st.nextToken().trim()); + + break; + } + } + + return procId; + + } + + public static int doShellCommand(String[] cmds, StringBuilder log, boolean runAsRoot, + boolean waitFor) throws Exception + { + + Process proc = null; + int exitCode = -1; + + if (runAsRoot) + proc = Runtime.getRuntime().exec("su"); + else + proc = Runtime.getRuntime().exec("sh"); + + OutputStreamWriter out = new OutputStreamWriter(proc.getOutputStream()); + + for (int i = 0; i < cmds.length; i++) + { + // TorService.logMessage("executing shell cmd: " + cmds[i] + + // "; runAsRoot=" + runAsRoot + ";waitFor=" + waitFor); + + out.write(cmds[i]); + out.write("\n"); + } + + out.flush(); + out.write("exit\n"); + out.flush(); + + if (waitFor) + { + + final char buf[] = new char[10]; + + // Consume the "stdout" + InputStreamReader reader = new InputStreamReader(proc.getInputStream()); + int read = 0; + while ((read = reader.read(buf)) != -1) { + if (log != null) + log.append(buf, 0, read); + } + + // Consume the "stderr" + reader = new InputStreamReader(proc.getErrorStream()); + read = 0; + while ((read = reader.read(buf)) != -1) { + if (log != null) + log.append(buf, 0, read); + } + + exitCode = proc.waitFor(); + + } + + return exitCode; + + } +}