diff --git a/app/build.gradle b/app/build.gradle
index a2e167e4..f8aee685 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/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d89beb83..53d03bd7 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -70,6 +70,12 @@
android:exported="false" >
+
+
+
+
+
+
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 95eea1d8..10ccd55e 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.OrbotStatusReceiver;
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 {
@@ -176,6 +178,19 @@ public class MainActivity extends AppCompatActivity
podUserProfile.setCallbackHandler(uiHandler);
podUserProfile.setListener(this);
+ //Orbot integration
+ OrbotStatusReceiver.setMainActivity(this);
+ OrbotHelper.requestStartTor(getApplicationContext());
+ if(appSettings.isProxyOrbot()) {
+ if(!OrbotHelper.isOrbotInstalled(getApplicationContext())) {
+ appSettings.setProxyOrbot(false);
+ promptInstallOrbot();
+ } else {
+ //precautionary set Proxy
+ OrbotStatusReceiver.setProxy(getApplicationContext(), OrbotStatusReceiver.DEFAULT_HOST, OrbotStatusReceiver.DEFAULT_PORT);
+ }
+ }
+
this.registerForContextMenu(webView);
webView.setParentActivity(this);
webView.setOverScrollMode(WebView.OVER_SCROLL_ALWAYS);
@@ -308,9 +323,9 @@ public class MainActivity extends AppCompatActivity
}
});
-
+ OrbotHelper.requestStartTor(getApplicationContext());
if (savedInstanceState == null) {
- if (Helpers.isOnline(MainActivity.this)) {
+ if (Helpers.isOnline(this)) {
webView.loadData("", "text/html", null);
webView.loadUrl("https://" + podDomain);
} else {
@@ -929,7 +944,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)
@@ -962,6 +978,17 @@ public class MainActivity extends AppCompatActivity
})
.show();
break;
+ case 4:
+ boolean before = appSettings.isProxyOrbot();
+ appSettings.setProxyOrbot(!before);
+ if(before) {
+ OrbotStatusReceiver.resetProxy(getApplicationContext());
+ } else {
+ OrbotHelper.requestStartTor(getApplicationContext());
+ webView.reload();
+ }
+ break;
+
}
}
}).show();
@@ -1032,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;
}
@@ -1052,4 +1079,34 @@ 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() {
+ final Intent intent = OrbotHelper.getOrbotInstallIntent(MainActivity.this);
+ String message = this.getString(R.string.you_must_have_orbot) + " "
+ + (intent.getPackage() == null ? getString(R.string.download_orbot_from_fdroid)
+ : getString(R.string.get_orbot_from_fdroid));
+ new AlertDialog.Builder(this).setTitle(R.string.install_orbot_).setMessage(message).setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
+ @Override
+ public void onClick(DialogInterface dialogInterface, int i) {
+ MainActivity.this.startActivity(intent);
+ }
+ }).setNegativeButton(android.R.string.no, null).show();
+ }
+
+ public void requestOrbotStart(boolean backgroundStartsDisabled) {
+ AlertDialog.Builder startDialog = new AlertDialog.Builder(this).setTitle(R.string.start_orbot_)
+ .setMessage((backgroundStartsDisabled ? R.string.orbot_starts_disabled_message
+ : 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);
+ }
+ }).setNegativeButton(android.R.string.no, null).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 5b11799f..d10ea43f 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
@@ -74,6 +74,7 @@ public class AppSettings {
private static final String PODUSERPROFILE_ID = "podUserProfile_guid";
private static final String PODDOMAIN = "podDomain";
private static final String PODUSERPROFILE_ASPECTS = "podUserProfile_aspects";
+ private static final String IS_PROXY_ORBOT = "proxyViaOrbot";
}
@@ -142,6 +143,13 @@ public class AppSettings {
setStringArray(prefApp, PREF.PREVIOUS_PODLIST, pods);
}
+ public boolean isProxyOrbot() {
+ return prefApp.getBoolean(PREF.IS_PROXY_ORBOT, false);
+ }
+
+ public void setProxyOrbot(boolean active) {
+ prefApp.edit().putBoolean(PREF.IS_PROXY_ORBOT, active).commit();
+ }
public void setPodAspects(PodAspect[] aspects) {
setStringArray(prefPod, PREF.PODUSERPROFILE_ASPECTS, aspects);
}
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/task/GetPodsService.java b/app/src/main/java/com/github/dfa/diaspora_android/task/GetPodsService.java
index 8791ac00..2f643a83 100644
--- a/app/src/main/java/com/github/dfa/diaspora_android/task/GetPodsService.java
+++ b/app/src/main/java/com/github/dfa/diaspora_android/task/GetPodsService.java
@@ -28,12 +28,6 @@ import android.util.Log;
import com.github.dfa.diaspora_android.App;
-import org.apache.http.HttpEntity;
-import org.apache.http.HttpResponse;
-import org.apache.http.StatusLine;
-import org.apache.http.client.HttpClient;
-import org.apache.http.client.methods.HttpGet;
-import org.apache.http.impl.client.DefaultHttpClient;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -44,6 +38,10 @@ import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
+import javax.net.ssl.HttpsURLConnection;
+
+import info.guardianproject.netcipher.NetCipher;
+
public class GetPodsService extends Service {
public static final String MESSAGE_PODS_RECEIVED = "com.github.dfa.diaspora.podsreceived";
private static final String TAG = App.TAG;
@@ -73,24 +71,28 @@ public class GetPodsService extends Service {
// TODO: Update deprecated code
StringBuilder builder = new StringBuilder();
- HttpClient client = new DefaultHttpClient();
+ //HttpClient client = new DefaultHttpClient();
List list = null;
+ HttpsURLConnection connection;
+ InputStream inStream;
try {
- HttpGet httpGet = new HttpGet("http://podupti.me/api.php?key=4r45tg&format=json");
- HttpResponse response = client.execute(httpGet);
- StatusLine statusLine = response.getStatusLine();
- int statusCode = statusLine.getStatusCode();
+ connection = NetCipher.getHttpsURLConnection("https://podupti.me/api.php?key=4r45tg&format=json");
+ int statusCode = connection.getResponseCode();
if (statusCode == 200) {
- HttpEntity entity = response.getEntity();
- InputStream content = entity.getContent();
+ inStream = connection.getInputStream();
BufferedReader reader = new BufferedReader(
- new InputStreamReader(content));
+ new InputStreamReader(inStream));
String line;
while ((line = reader.readLine()) != null) {
builder.append(line);
}
+
+ try {
+ inStream.close();
+ } catch (IOException e) {}
+
+ connection.disconnect();
} else {
- //TODO Notify User about failure
Log.e(TAG, "Failed to download list of pods");
}
} catch (IOException e) {
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/task/ImageDownloadTask.java b/app/src/main/java/com/github/dfa/diaspora_android/task/ImageDownloadTask.java
index 2b5a3d23..31cec3c8 100644
--- a/app/src/main/java/com/github/dfa/diaspora_android/task/ImageDownloadTask.java
+++ b/app/src/main/java/com/github/dfa/diaspora_android/task/ImageDownloadTask.java
@@ -13,6 +13,10 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
+import javax.net.ssl.HttpsURLConnection;
+
+import info.guardianproject.netcipher.NetCipher;
+
/**
* Created by Gregor Santner (gsantner) on 24.03.16.
*/
@@ -35,9 +39,12 @@ public class ImageDownloadTask extends AsyncTask {
String url = urls[0];
Bitmap bitmap = null;
FileOutputStream out = null;
+ InputStream inStream;
+ HttpsURLConnection connection;
try {
- InputStream in = new java.net.URL(url).openStream();
- bitmap = BitmapFactory.decodeStream(in);
+ connection = NetCipher.getHttpsURLConnection(url);
+ inStream = connection.getInputStream();
+ bitmap = BitmapFactory.decodeStream(inStream);
// Save to file if not null
if (savePath != null) {
@@ -45,6 +52,12 @@ public class ImageDownloadTask extends AsyncTask {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
}
+ try {
+ inStream.close();
+ } catch (IOException e) {}
+
+ connection.disconnect();
+
} catch (Exception e) {
Log.e(App.TAG, e.getMessage());
} finally {
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/task/ProfileFetchTask.java b/app/src/main/java/com/github/dfa/diaspora_android/task/ProfileFetchTask.java
index f54774f0..beab5eff 100644
--- a/app/src/main/java/com/github/dfa/diaspora_android/task/ProfileFetchTask.java
+++ b/app/src/main/java/com/github/dfa/diaspora_android/task/ProfileFetchTask.java
@@ -10,10 +10,14 @@ import com.github.dfa.diaspora_android.data.PodUserProfile;
import java.io.BufferedReader;
import java.io.IOException;
+import java.io.InputStream;
import java.io.InputStreamReader;
-import java.net.HttpURLConnection;
import java.net.URL;
+import javax.net.ssl.HttpsURLConnection;
+
+import info.guardianproject.netcipher.NetCipher;
+
/**
* Created by Gregor Santner (gsantner) on 30.03.16.
*/
@@ -37,18 +41,21 @@ public class ProfileFetchTask extends AsyncTask {
String cookies = cookieManager.getCookie("https://" + app.getSettings().getPodDomain());
Log.d(App.TAG, cookies);
+ HttpsURLConnection connection;
+ InputStream inStream;
try {
URL url = new URL("https://" + app.getSettings().getPodDomain() + "/stream");
- HttpURLConnection conn = (HttpURLConnection) url.openConnection();
- conn.setReadTimeout(10000);
- conn.setConnectTimeout(15000);
- conn.setRequestMethod("GET");
+ connection = NetCipher.getHttpsURLConnection(url);
+ connection.setReadTimeout(10000);
+ connection.setConnectTimeout(15000);
+ connection.setRequestMethod("GET");
if (cookies != null) {
- conn.setRequestProperty("Cookie", cookies);
+ connection.setRequestProperty("Cookie", cookies);
}
- conn.connect();
+ connection.connect();
- BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
+ inStream = connection.getInputStream();
+ BufferedReader br = new BufferedReader(new InputStreamReader(inStream));
String line;
final String TARGET_TAG = "window.gon={};gon.user=";
while ((line = br.readLine()) != null && !line.startsWith(" {
break;
}
}
+
+ try{
+ br.close();
+ inStream.close();
+ } catch (IOException e){}
+
+ connection.disconnect();
+
} catch (IOException e) {
e.printStackTrace();
}
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java b/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java
index 6b42b313..b7841ab7 100644
--- a/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java
+++ b/app/src/main/java/com/github/dfa/diaspora_android/ui/ContextMenuWebView.java
@@ -20,9 +20,13 @@ import android.widget.Toast;
import com.github.dfa.diaspora_android.R;
import com.github.dfa.diaspora_android.activity.MainActivity;
+import com.github.dfa.diaspora_android.util.OrbotStatusReceiver;
import java.io.File;
+import info.guardianproject.netcipher.NetCipher;
+import info.guardianproject.netcipher.proxy.OrbotHelper;
+
/**
* Subclass of WebView which adds a context menu for long clicks on images or links to share, save
* or open with another browser
@@ -149,4 +153,17 @@ public class ContextMenuWebView extends NestedWebView {
public void setParentActivity(Activity activity) {
this.parentActivity = activity;
}
+
+ @Override
+ public void reload() {
+ OrbotHelper.requestStartTor(context.getApplicationContext());
+ super.reload();
+ }
+
+ @Override
+ public void loadUrl(String url) {
+ if(!OrbotStatusReceiver.isProxySet())
+ OrbotHelper.requestStartTor(context.getApplicationContext());
+ super.loadUrl(url);
+ }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/github/dfa/diaspora_android/util/OrbotStatusReceiver.java b/app/src/main/java/com/github/dfa/diaspora_android/util/OrbotStatusReceiver.java
new file mode 100644
index 00000000..d7073f58
--- /dev/null
+++ b/app/src/main/java/com/github/dfa/diaspora_android/util/OrbotStatusReceiver.java
@@ -0,0 +1,141 @@
+/*
+ This file is part of the Diaspora for Android.
+
+ Diaspora for Android 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.
+
+ Diaspora for Android 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 the Diaspora for Android.
+
+ If not, see .
+ */
+
+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.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;
+
+/**
+ * BroadcastReceiver that handles Orbot status intents and sets the proxy.
+ * Created by vanitas on 06.06.16.
+ */
+public class OrbotStatusReceiver extends BroadcastReceiver {
+
+ public static final String EXTRA_HTTP_HOST = "org.torproject.android.intent.extra.HTTP_PROXY_HOST";
+ public static final String EXTRA_HTTP_PORT = "org.torproject.android.intent.extra.HTTP_PROXY_PORT";
+ public static final String DEFAULT_HOST = "127.0.0.1";
+ public static final int DEFAULT_PORT = 8118;
+
+ private static String host = "";
+ private static int port = 0;
+ private Intent lastStatus;
+ private Context lastContext;
+ private static MainActivity mainActivity;
+ private AppSettings appSettings;
+ private static boolean proxySet = false;
+
+ public OrbotStatusReceiver() {
+ }
+
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ if(OrbotHelper.ACTION_STATUS.equals(intent.getAction())) {
+ lastStatus = intent;
+ lastContext = context;
+ if(appSettings == null) appSettings = new AppSettings(context.getApplicationContext());
+ String orbotStatus = intent.getExtras().getString(OrbotHelper.EXTRA_STATUS);
+ if(appSettings.isProxyOrbot()) {
+ if (orbotStatus.equals(OrbotHelper.STATUS_ON)) {
+ setProxy(lastContext, lastStatus);
+ } else if(orbotStatus.equals(OrbotHelper.STATUS_OFF)) {
+ Log.d(App.TAG, "Warning: Orbot reports status off.");
+ OrbotHelper.requestStartTor(context.getApplicationContext());
+ } else if(orbotStatus.equals(OrbotHelper.STATUS_STARTS_DISABLED)) {
+ Log.d(App.TAG, "Warning: Orbot has background starts disabled.");
+ if(mainActivity != null) mainActivity.requestOrbotStart(true);
+ }
+ }
+ } else {
+ Log.e(App.TAG, "Warning: Intents action "+intent.getAction()+ " does not equal "+OrbotHelper.ACTION_STATUS);
+ }
+ }
+
+ public static void setProxy(Context context, Intent intent) {
+ if(intent != null) {
+ String status = intent.getStringExtra(OrbotHelper.EXTRA_STATUS);
+ if(status.equals(OrbotHelper.STATUS_ON)) {
+ String nHost = intent.getExtras().getString(EXTRA_HTTP_HOST, null);
+ int nPort = intent.getIntExtra(EXTRA_HTTP_PORT, -1);
+ //Got no values from intent
+ if((nHost == null || nPort == -1)) {
+ if(host.equals("") || port == 0) {
+ setProxy(context, DEFAULT_HOST, DEFAULT_PORT);
+ }
+ } else {
+ setProxy(context, nHost, nPort);
+ }
+ }
+ } else {
+ Log.e(App.TAG, "OrbotStatusReceiver: lastStatus intent is null. Cannot set Proxy.");
+ }
+ }
+
+ public static void setProxy(Context context, String host, int port) {
+ try {
+ OrbotStatusReceiver.host = host;
+ OrbotStatusReceiver.port = port;
+ NetCipher.setProxy(host, port);
+ WebkitProxy.setProxy(MainActivity.class.getName(), context.getApplicationContext(), null, host, port);
+ Log.d(App.TAG, "Proxy successfully set.");
+ proxySet = true;
+ } catch(Exception e) {
+ Log.e(App.TAG, "setProxy failed: ");
+ e.printStackTrace();
+ }
+ }
+
+ public static void resetProxy(Context context) {
+ try {
+ OrbotStatusReceiver.host = "";
+ OrbotStatusReceiver.port = 0;
+ NetCipher.clearProxy();
+ WebkitProxy.resetProxy(MainActivity.class.getName(), context.getApplicationContext());
+ } catch (Exception e) {
+ //Fails in any case on android 6. Ignore it and restart application.
+ }
+ proxySet = false;
+ //Restart application
+ Intent restartActivity = new Intent(context, MainActivity.class);
+ PendingIntent pendingIntent = PendingIntent.getActivity(context, 12374, restartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
+ AlarmManager mgr = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
+ System.exit(0);
+ }
+
+ public static boolean isProxySet() {
+ return proxySet;
+ }
+
+ public static void setMainActivity(MainActivity main) {
+ mainActivity = main;
+ }
+}
diff --git a/app/src/main/res/values-de/strings.xml b/app/src/main/res/values-de/strings.xml
index 977b8857..fc3c09c6 100644
--- a/app/src/main/res/values-de/strings.xml
+++ b/app/src/main/res/values-de/strings.xml
@@ -166,5 +166,14 @@ along with this program. If not, see http://www.gnu.org/licenses.<br> <br
Speichere Bild als
Linkadresse kopiert …
Teilen…
+ Möchten Sie Orbot nun von f-droid.org herunterladen?
+ Möchten Sie Orbot nun über F-Droid installieren?
+ Orbot installieren?
+ Orbot scheint nicht aktiv zu sein. Möchten Sie es nun starten um sich mit dem Tor-Netzwerk zu verbinden?
+ Orbot-Proxy: Deaktiviert
+ Orbot-Proxy: Aktiviert
+ Orbot scheint Hintergrund-Starts deaktiviert zu haben. Möchten Sie Orbot jetzt öffnen?
+ Orbot starten?
+ Um das Tor-Netzwerk als Proxy nutzen zu können, müssen Sie Orbot installieren.
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
+