[tor-commits] [tor-browser/tor-browser-52.7.2esr-8.0-1] Orfox: NetCipher enabled, checks if orbot is installed
gk at torproject.org
gk at torproject.org
Tue Mar 20 11:26:34 UTC 2018
commit 67aca67cc7b0802f19024ad39f3d70733a47ce49
Author: Amogh Pradeep <amoghbl1 at gmail.com>
Date: Mon Jul 20 21:46:25 2015 -0400
Orfox: NetCipher enabled, checks if orbot is installed
Signed-off-by: Amogh Pradeep <amoghbl1 at gmail.com>
---
.../base/java/org/mozilla/gecko/BrowserApp.java | 32 ++-
mobile/android/base/moz.build | 6 +
mobile/android/base/strings.xml.in | 5 +
.../netcipher/proxy/OrbotHelper.java | 186 ++++++++++++++++
.../netcipher/proxy/TorServiceUtils.java | 233 +++++++++++++++++++++
mobile/android/orfox/strings.xml.in | 5 +
6 files changed, 462 insertions(+), 5 deletions(-)
diff --git a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
index 9023618669ef..a532b454a263 100644
--- a/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
+++ b/mobile/android/base/java/org/mozilla/gecko/BrowserApp.java
@@ -174,6 +174,8 @@ import android.animation.ObjectAnimator;
import org.json.JSONException;
import org.json.JSONObject;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
@@ -1068,6 +1070,30 @@ public class BrowserApp extends GeckoApp
}
}
+ public void checkStartOrbot() {
+ if (!OrbotHelper.isOrbotInstalled(this)) {
+ final Intent intent = OrbotHelper.getOrbotInstallIntent(this);
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.install_orbot);
+ builder.setMessage(R.string.you_must_have_orbot);
+ builder.setPositiveButton(R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ startActivity(intent);
+ }
+ });
+ builder.setNegativeButton(R.string.no, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ }
+ });
+ builder.show();
+ } else {
+ OrbotHelper.requestStartTor(this);
+ }
+ }
+
@Override
public void onResume() {
super.onResume();
@@ -1076,11 +1102,7 @@ public class BrowserApp extends GeckoApp
return;
}
- if (!mHasResumed) {
- EventDispatcher.getInstance().unregisterGeckoThreadListener((GeckoEventListener) this,
- "Prompt:ShowTop");
- mHasResumed = true;
- }
+ checkStartOrbot();
processTabQueue();
diff --git a/mobile/android/base/moz.build b/mobile/android/base/moz.build
index 6c88464ab521..4dbb1c25fdab 100644
--- a/mobile/android/base/moz.build
+++ b/mobile/android/base/moz.build
@@ -12,6 +12,7 @@ include('android-services.mozbuild')
geckoview_source_dir = TOPSRCDIR + '/mobile/android/geckoview/src/main/'
geckoview_thirdparty_source_dir = TOPSRCDIR + '/mobile/android/geckoview/src/thirdparty/'
+geckoview_netcipher_source_dir = TOPSRCDIR + '/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/'
thirdparty_source_dir = TOPSRCDIR + '/mobile/android/thirdparty/'
constants_jar = add_java_jar('constants')
@@ -289,6 +290,11 @@ gvjar.sources += [geckoview_thirdparty_source_dir + f for f in [
'java/com/googlecode/eyesfree/braille/selfbraille/WriteData.java',
]]
+gvjar.sources += [geckoview_netcipher_source_dir + f for f in [
+ 'OrbotHelper.java',
+ 'TorServiceUtils.java',
+]]
+
gvjar.extra_jars += [
CONFIG['ANDROID_SUPPORT_ANNOTATIONS_JAR_LIB'],
CONFIG['ANDROID_SUPPORT_V4_AAR_LIB'],
diff --git a/mobile/android/base/strings.xml.in b/mobile/android/base/strings.xml.in
index 3511a4eca644..ec39107f8f60 100644
--- a/mobile/android/base/strings.xml.in
+++ b/mobile/android/base/strings.xml.in
@@ -28,6 +28,11 @@
#include ../search/strings/search_strings.xml.in
#include ../services/strings.xml.in
+#include ../orfox/strings.xml.in
+
+ <string name="no_space_to_start_error">&no_space_to_start_error;</string>
+ <string name="error_loading_file">&error_loading_file;</string>
+
<string name="firstrun_panel_title_welcome">&firstrun_panel_title_welcome;</string>
diff --git a/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/OrbotHelper.java b/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/OrbotHelper.java
new file mode 100644
index 000000000000..d6a632fda37d
--- /dev/null
+++ b/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/OrbotHelper.java
@@ -0,0 +1,186 @@
+
+package info.guardianproject.netcipher.proxy;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.net.Uri;
+import android.text.TextUtils;
+import android.util.Log;
+
+
+import java.util.List;
+
+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 ORBOT_MARKET_URI = "market://details?id=" + ORBOT_PACKAGE_NAME;
+ public final static String ORBOT_FDROID_URI = "https://f-droid.org/repository/browse/?fdid="
+ + ORBOT_PACKAGE_NAME;
+ public final static String ORBOT_PLAY_URI = "https://play.google.com/store/apps/details?id="
+ + ORBOT_PACKAGE_NAME;
+
+ /**
+ * A request to Orbot to transparently start Tor services
+ */
+ public final static String ACTION_START = "org.torproject.android.intent.action.START";
+ /**
+ * {@link Intent} send by Orbot with {@code ON/OFF/STARTING/STOPPING} status
+ */
+ public final static String ACTION_STATUS = "org.torproject.android.intent.action.STATUS";
+ /**
+ * {@code String} that contains a status constant: {@link #STATUS_ON},
+ * {@link #STATUS_OFF}, {@link #STATUS_STARTING}, or
+ * {@link #STATUS_STOPPING}
+ */
+ public final static String EXTRA_STATUS = "org.torproject.android.intent.extra.STATUS";
+ /**
+ * A {@link String} {@code packageName} for Orbot to direct its status reply
+ * to, used in {@link #ACTION_START} {@link Intent}s sent to Orbot
+ */
+ public final static String EXTRA_PACKAGE_NAME = "org.torproject.android.intent.extra.PACKAGE_NAME";
+
+ /**
+ * All tor-related services and daemons are stopped
+ */
+ public final static String STATUS_OFF = "OFF";
+ /**
+ * All tor-related services and daemons have completed starting
+ */
+ public final static String STATUS_ON = "ON";
+ public final static String STATUS_STARTING = "STARTING";
+ public final static String STATUS_STOPPING = "STOPPING";
+ /**
+ * The user has disabled the ability for background starts triggered by
+ * apps. Fallback to the old Intent that brings up Orbot.
+ */
+ public final static String STATUS_STARTS_DISABLED = "STARTS_DISABLED";
+
+ 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 START_TOR_RESULT = 0x048079234;
+ public final static int HS_REQUEST_CODE = 9999;
+
+ private final static String FDROID_PACKAGE_NAME = "org.fdroid.fdroid";
+ private final static String PLAY_PACKAGE_NAME = "com.android.vending";
+
+ private OrbotHelper() {
+ // only static utility methods, do not instantiate
+ }
+
+ public static boolean isOrbotRunning(Context context) {
+ int procId = TorServiceUtils.findProcessId(context);
+
+ return (procId != -1);
+ }
+
+ public static boolean isOrbotInstalled(Context context) {
+ return isAppInstalled(context, ORBOT_PACKAGE_NAME);
+ }
+
+ private static boolean isAppInstalled(Context context, String uri) {
+ try {
+ PackageManager pm = context.getPackageManager();
+ pm.getPackageInfo(uri, PackageManager.GET_ACTIVITIES);
+ return true;
+ } catch (PackageManager.NameNotFoundException e) {
+ return false;
+ }
+ }
+
+ public static 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);
+ }
+
+ /**
+ * First, checks whether Orbot is installed. If Orbot is installed, then a
+ * broadcast {@link Intent} is sent to request Orbot to start transparently
+ * in the background. When Orbot receives this {@code Intent}, it will
+ * immediately reply to this all with its status via an
+ * {@link #ACTION_STATUS} {@code Intent} that is broadcast to the
+ * {@code packageName} of the provided {@link Context} (i.e.
+ * {@link Context#getPackageName()}.
+ *
+ * @param context the app {@link Context} will receive the reply
+ * @return whether the start request was sent to Orbot
+ */
+ public static boolean requestStartTor(Context context) {
+ if (OrbotHelper.isOrbotInstalled(context)) {
+ Log.i("OrbotHelper", "requestStartTor " + context.getPackageName());
+ Intent intent = getOrbotStartIntent();
+ intent.putExtra(EXTRA_PACKAGE_NAME, context.getPackageName());
+ context.sendBroadcast(intent);
+ return true;
+ }
+ return false;
+ }
+
+ public static Intent getOrbotStartIntent() {
+ Intent intent = new Intent(ACTION_START);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ return intent;
+ }
+
+ /**
+ * First, checks whether Orbot is installed, then checks whether Orbot is
+ * running. If Orbot is installed and not running, then an {@link Intent} is
+ * sent to request Orbot to start, which will show the main Orbot screen.
+ * The result will be returned in
+ * {@link Activity#onActivityResult(int requestCode, int resultCode, Intent data)}
+ * with a {@code requestCode} of {@link START_TOR_RESULT}
+ *
+ * @param activity the {@link Activity} that gets the
+ * {@code START_TOR_RESULT} result
+ * @return whether the start request was sent to Orbot
+ */
+ public static boolean requestShowOrbotStart(Activity activity) {
+ if (OrbotHelper.isOrbotInstalled(activity)) {
+ if (!OrbotHelper.isOrbotRunning(activity)) {
+ Intent intent = getShowOrbotStartIntent();
+ activity.startActivityForResult(intent, START_TOR_RESULT);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ public static Intent getShowOrbotStartIntent() {
+ Intent intent = new Intent(ACTION_START_TOR);
+ intent.setPackage(ORBOT_PACKAGE_NAME);
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ return intent;
+ }
+
+ public static Intent getOrbotInstallIntent(Context context) {
+ final Intent intent = new Intent(Intent.ACTION_VIEW);
+ intent.setData(Uri.parse(ORBOT_MARKET_URI));
+
+ PackageManager pm = context.getPackageManager();
+ List<ResolveInfo> resInfos = pm.queryIntentActivities(intent, 0);
+
+ String foundPackageName = null;
+ for (ResolveInfo r : resInfos) {
+ Log.i("OrbotHelper", "market: " + r.activityInfo.packageName);
+ if (TextUtils.equals(r.activityInfo.packageName, FDROID_PACKAGE_NAME)
+ || TextUtils.equals(r.activityInfo.packageName, PLAY_PACKAGE_NAME)) {
+ foundPackageName = r.activityInfo.packageName;
+ break;
+ }
+ }
+
+ if (foundPackageName == null) {
+ intent.setData(Uri.parse(ORBOT_FDROID_URI));
+ } else {
+ intent.setPackage(foundPackageName);
+ }
+ return intent;
+ }
+}
diff --git a/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/TorServiceUtils.java b/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/TorServiceUtils.java
new file mode 100644
index 000000000000..e553ecac3543
--- /dev/null
+++ b/mobile/android/geckoview/src/thirdparty/java/info/guardianproject/netcipher/proxy/TorServiceUtils.java
@@ -0,0 +1,233 @@
+/* Copyright (c) 2009, Nathan Freitas, Orbot / The Guardian Project - http://openideals.com/guardian */
+/* See LICENSE for licensing information */
+
+package info.guardianproject.netcipher.proxy;
+
+import android.content.Context;
+import android.util.Log;
+
+
+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;
+
+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(Context context) {
+ String dataPath = context.getFilesDir().getParentFile().getParentFile().getAbsolutePath();
+ String command = dataPath + "/" + OrbotHelper.ORBOT_PACKAGE_NAME + "/app_bin/tor";
+ 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;
+
+ }
+}
diff --git a/mobile/android/orfox/strings.xml.in b/mobile/android/orfox/strings.xml.in
new file mode 100644
index 000000000000..e3a22974ed78
--- /dev/null
+++ b/mobile/android/orfox/strings.xml.in
@@ -0,0 +1,5 @@
+<!-- NetCipher Integration Strings, used for dialog -->
+ <string name="install_orbot">Install Orbot?</string>
+ <string name="you_must_have_orbot">You must have Orbot installed and activated to proxy traffic through it. Would you like to download it?</string>
+ <string name="yes">Yes</string>
+ <string name="no">No</string>
More information about the tor-commits
mailing list