diff --git a/app/build.gradle b/app/build.gradle
index 3072760b..a7f02870 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -37,6 +37,7 @@ dependencies {
// More libraries
compile 'com.getbase:floatingactionbutton:1.9.1'
compile 'com.jakewharton:butterknife:8.0.1'
+ compile 'info.guardianproject.netcipher:netcipher:1.2.1'
apt 'com.jakewharton:butterknife-compiler:8.0.1'
}
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java
index 4183f68e..708d5fd0 100644
--- a/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java
+++ b/app/src/main/java/com/github/dfa/diaspora_android/activity/MainActivity.java
@@ -82,6 +82,7 @@ import com.github.dfa.diaspora_android.listener.WebUserProfileChangedListener;
import com.github.dfa.diaspora_android.ui.ContextMenuWebView;
import com.github.dfa.diaspora_android.ui.CustomWebViewClient;
import com.github.dfa.diaspora_android.util.Helpers;
+import com.github.dfa.diaspora_android.util.ProxyHandler;
import org.json.JSONException;
@@ -97,6 +98,7 @@ import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, WebUserProfileChangedListener {
@@ -174,6 +176,16 @@ public class MainActivity extends AppCompatActivity
appSettings = app.getSettings();
podUserProfile = new PodUserProfile(app, uiHandler, this);
+ ProxyHandler.getInstance(this, appSettings).registerOrbotReceiver(this);
+ if(appSettings.isProxyOrbot()) {
+ if(!OrbotHelper.isOrbotInstalled(this)) {
+ appSettings.setProxyOrbot(false);
+ promptInstallOrbot();
+ } else {
+ Toast.makeText(this, "Orbot Proxy: "+ProxyHandler.getInstance(null, null).getActiveProxy(), Toast.LENGTH_SHORT).show();
+ }
+ }
+
this.registerForContextMenu(webView);
webView.setParentActivity(this);
webView.setOverScrollMode(WebView.OVER_SCROLL_ALWAYS);
@@ -306,7 +318,13 @@ public class MainActivity extends AppCompatActivity
}
});
+ if(!appSettings.isProxyOrbot()) {
+ ProxyHandler.getInstance(null, null).unregisterOrbotReceiver(this);
+ afterOnCreate(savedInstanceState);
+ }
+ }
+ private void afterOnCreate(Bundle savedInstanceState) {
if (savedInstanceState == null) {
if (Helpers.isOnline(MainActivity.this)) {
webView.loadData("", "text/html", null);
@@ -404,6 +422,9 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onResume() {
super.onResume();
+ try {
+ ProxyHandler.getInstance(null, null).registerOrbotReceiver(this);
+ } catch (IllegalStateException e){}
registerReceiver(brLoadUrl, new IntentFilter(URL_MESSAGE));
}
@@ -441,6 +462,7 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onPause() {
unregisterReceiver(brLoadUrl);
+ ProxyHandler.getInstance(null, null).unregisterOrbotReceiver(this);
super.onPause();
}
@@ -926,7 +948,8 @@ public class MainActivity extends AppCompatActivity
case R.id.nav_settings_app: {
final CharSequence[] options = {getString(R.string.settings_font), getString(R.string.settings_view), appSettings.isLoadImages() ?
- getString(R.string.settings_images_switch_off) : getString(R.string.settings_images_switch_on), getString(R.string.jb_pod)};
+ getString(R.string.settings_images_switch_off) : getString(R.string.settings_images_switch_on), getString(R.string.jb_pod),
+ appSettings.isProxyOrbot() ? getString(R.string.orbot_proxy_enabled) : getString(R.string.orbot_proxy_disabled)};
if (Helpers.isOnline(MainActivity.this)) {
new AlertDialog.Builder(MainActivity.this)
@@ -959,6 +982,13 @@ public class MainActivity extends AppCompatActivity
})
.show();
break;
+ case 4:
+ if(appSettings.isProxyOrbot()) {
+ ProxyHandler.getInstance(null,null).setProxy(MainActivity.this, null, 0, ProxyHandler.NO_PROXY);
+ } else {
+ OrbotHelper.requestStartTor(MainActivity.this);
+ }
+ appSettings.setProxyOrbot(!appSettings.isProxyOrbot());
}
}
}).show();
@@ -1029,7 +1059,7 @@ public class MainActivity extends AppCompatActivity
}
DrawerLayout drawer = (DrawerLayout) findViewById(R.id.main__layout);
- drawer.closeDrawer(GravityCompat.START);
+ if(drawer != null) drawer.closeDrawer(GravityCompat.START);
return true;
}
@@ -1049,4 +1079,50 @@ public class MainActivity extends AppCompatActivity
grantResults);
}
}
+
+ /**
+ * Ask the user whether to install Orbot or not. Check if installing from
+ * F-Droid or Google Play, otherwise take the user to the Orbot download
+ * page on f-droid.org.
+ */
+ void promptInstallOrbot() {
+ String message = this.getString(R.string.you_must_have_orbot) + " ";
+
+ final Intent intent = OrbotHelper.getOrbotInstallIntent(MainActivity.this);
+ if (intent.getPackage() == null) {
+ message += MainActivity.this.getString(R.string.download_orbot_from_fdroid);
+ } else {
+ message += MainActivity.this.getString(R.string.get_orbot_from_fdroid);
+ }
+
+ AlertDialog.Builder builder = new AlertDialog.Builder(this);
+ builder.setTitle(R.string.install_orbot_);
+ builder.setMessage(message);
+ builder.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ MainActivity.this.startActivity(intent);
+ }
+ });
+ builder.setNegativeButton(android.R.string.no, null);
+ builder.show();
+ }
+
+ public void requestOrbotStart(boolean backgroundStartsDisabled) {
+ AlertDialog.Builder startDialog = new AlertDialog.Builder(this);
+ startDialog.setTitle(R.string.start_orbot_);
+ if(backgroundStartsDisabled)
+ startDialog.setMessage(R.string.orbot_starts_disabled_message);
+ else
+ startDialog.setMessage(R.string.orbot_doesn_t_appear_to_be_running_would_you_like_to_start_it_up_and_connect_to_tor_);
+
+ startDialog.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ startActivityForResult(OrbotHelper.getShowOrbotStartIntent(), 1);
+ }
+ });
+ startDialog.setNegativeButton(android.R.string.no, null);
+ startDialog.show();
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java b/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java
index 12b0dd57..5e668386 100644
--- a/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java
+++ b/app/src/main/java/com/github/dfa/diaspora_android/data/AppSettings.java
@@ -65,6 +65,7 @@ public class AppSettings {
private static final String PODUSERPROFILE_NAME = "podUserProfile_name";
private static final String PODUSERPROFILE_ID = "podUserProfile_guid";
private static final String PODDOMAIN = "podDomain";
+ private static final String IS_PROXY_ORBOT = "proxyViaOrbot";
}
@@ -132,4 +133,12 @@ public class AppSettings {
public void setPreviousPodlist(String[] pods){
setStringArray(prefApp, PREF.PREVIOUS_PODLIST, pods);
}
+
+ public boolean isProxyOrbot() {
+ return prefApp.getBoolean(PREF.IS_PROXY_ORBOT, false);
+ }
+
+ public void setProxyOrbot(boolean active) {
+ setBool(prefApp, PREF.IS_PROXY_ORBOT, active);
+ }
}
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/ProxyHandler.java b/app/src/main/java/com/github/dfa/diaspora_android/util/ProxyHandler.java
new file mode 100644
index 00000000..7cbb325d
--- /dev/null
+++ b/app/src/main/java/com/github/dfa/diaspora_android/util/ProxyHandler.java
@@ -0,0 +1,143 @@
+package com.github.dfa.diaspora_android.util;
+
+import android.app.AlarmManager;
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.util.Log;
+
+import com.github.dfa.diaspora_android.App;
+import com.github.dfa.diaspora_android.activity.MainActivity;
+import com.github.dfa.diaspora_android.data.AppSettings;
+
+import info.guardianproject.netcipher.NetCipher;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+import info.guardianproject.netcipher.web.WebkitProxy;
+
+/**
+ * Handle proxy configurations
+ * In this particular case integration of Orbot as a proxy for the tor network has been done,
+ * but other proxies can easily and similarly be added as well.
+ * Created by vanitas on 05.06.16.
+ */
+public class ProxyHandler {
+ //TODO: Remove when NetCipher > 1.2.1 releases
+ public final static String EXTRA_PROXY_PORT_HTTP = "org.torproject.android.intent.extra.HTTP_PROXY_PORT";
+ //Proxy types
+ public static final int NO_PROXY = 0, ORBOT_PROXY = 1;
+ private int activeProxy = NO_PROXY;
+
+ private static ProxyHandler instance;
+ private MainActivity mainActivity;
+ private AppSettings appSettings;
+ private OrbotReceiver orbotReceiver;
+
+
+ private ProxyHandler(MainActivity main, AppSettings settings) {
+ orbotReceiver = new OrbotReceiver();
+ mainActivity = main;
+ appSettings = settings;
+ }
+
+ public static ProxyHandler getInstance(MainActivity main, AppSettings settings) {
+ if(instance == null) instance = new ProxyHandler(main, settings);
+ return instance;
+ }
+
+ public void registerOrbotReceiver(Context context) {
+ if(!orbotReceiver.isRegistered()) {
+ context.registerReceiver(orbotReceiver, new IntentFilter(OrbotHelper.ACTION_STATUS));
+ orbotReceiver.setRegistered(true);
+ }
+ else throw new IllegalStateException("OrbotReceiver is already registered.");
+ }
+
+ public void unregisterOrbotReceiver(Context context) {
+ if(orbotReceiver.isRegistered()) {
+ context.unregisterReceiver(orbotReceiver);
+ orbotReceiver.setRegistered(false);
+ }
+ else throw new IllegalStateException("OrbotReceiver was not registered and can therefore not be unregistered.");
+ }
+
+ public void setProxy(Context context, String host, int port, int proxyType) {
+ if(proxyType == NO_PROXY) {
+ try {
+ NetCipher.clearProxy();
+ WebkitProxy.resetProxy(MainActivity.class.getName(), context);
+ activeProxy = proxyType;
+ }
+ catch (Exception e) {
+ Log.e(App.TAG, "ProxyHandler caught exception "+e.getClass().getName()+" while resetting proxy.");
+ }
+ restartApplication(context);
+ return;
+ }
+
+ if(proxyType == ORBOT_PROXY) {
+ try {
+ NetCipher.setProxy(host, port);
+ WebkitProxy.setProxy(MainActivity.class.getName(), context.getApplicationContext(), null, host, port);
+ activeProxy = proxyType;
+ } catch (Exception e) {
+ Log.d(App.TAG, "ProxyHandler caught exception " + e.getClass().getName() + " while setting proxy.");
+ e.printStackTrace();
+ }
+ }
+
+ //Add further proxies here
+ }
+
+ private static void restartApplication(Context context) {
+ Intent mStartActivity = new Intent(context, MainActivity.class);
+ PendingIntent mPendingIntent = PendingIntent.getActivity(context, 12374, mStartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, mPendingIntent);
+ System.exit(0);
+ }
+
+ private static class OrbotReceiver extends BroadcastReceiver {
+ private boolean registered;
+
+ private boolean orbotRunning = false;
+ private int proxyPort = -1;
+ private String proxyHost = "127.0.0.1";
+
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(OrbotHelper.ACTION_STATUS.equals(intent.getAction())) {
+
+ if(OrbotHelper.STATUS_ON.equals(intent.getStringExtra(OrbotHelper.EXTRA_STATUS))) {
+ proxyPort = intent.getIntExtra(EXTRA_PROXY_PORT_HTTP, -1);
+ if(instance.appSettings.isProxyOrbot()) {
+ instance.setProxy(context, proxyHost, proxyPort, ORBOT_PROXY);
+ }
+ orbotRunning = true;
+ }
+
+ if(OrbotHelper.STATUS_OFF.equals(intent.getStringExtra(OrbotHelper.EXTRA_STATUS))) {
+ instance.mainActivity.requestOrbotStart(false);
+ }
+
+ if(OrbotHelper.STATUS_STARTS_DISABLED.equals(intent.getStringExtra(OrbotHelper.EXTRA_STATUS))) {
+ instance.mainActivity.requestOrbotStart(true);
+ }
+ }
+ }
+
+ public boolean isRegistered() {
+ return registered;
+ }
+
+ public void setRegistered(boolean r) {
+ registered = r;
+ }
+ }
+
+ public int getActiveProxy() {
+ return activeProxy;
+ }
+}
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index ac6920ca..2fca7364 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -211,4 +211,15 @@
https://
Share…
#DiasporaForAndroid
+
+ Install Orbot?
+ You must have Orbot installed and activated to proxy traffic through it.
+ Would you like to install it from F-Droid?
+ Would you like to download it from f-droid.org?
+ Start Orbot?
+ Orbot doesn\'t appear to be running. Would you like to start it up and connect to Tor?
+ Orbot has background starts disabled. Would you like to open Orbot?
+ Orbot Proxy: Enabled
+ Orbot Proxy: Disabled
+