1
0
Fork 0
mirror of https://github.com/gsantner/dandelion synced 2024-11-24 21:32:07 +01:00

Merge pull request #26 from vanitasvitae/feature_proxy

Feature: Allow configuring proxy server
This commit is contained in:
vanitasvitae 2016-06-16 21:10:13 +02:00 committed by GitHub
commit e48edbf652
9 changed files with 269 additions and 30 deletions

View file

@ -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'
}

View file

@ -23,7 +23,9 @@ import android.Manifest;
import android.animation.ObjectAnimator;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
@ -32,9 +34,11 @@ import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.graphics.Bitmap;
import android.net.Uri;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.os.StrictMode;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.design.widget.CollapsingToolbarLayout;
@ -46,6 +50,7 @@ import android.support.v4.widget.SwipeRefreshLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.ActionMenuView;
import android.support.v7.widget.SwitchCompat;
import android.support.v7.widget.Toolbar;
import android.text.Html;
import android.text.SpannableString;
@ -66,6 +71,7 @@ import android.webkit.WebChromeClient;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.EditText;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
@ -97,6 +103,8 @@ import java.util.Locale;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
import info.guardianproject.netcipher.NetCipher;
import info.guardianproject.netcipher.web.WebkitProxy;
public class MainActivity extends AppCompatActivity
implements NavigationView.OnNavigationItemSelectedListener, WebUserProfileChangedListener {
@ -216,6 +224,11 @@ public class MainActivity extends AppCompatActivity
if (android.os.Build.VERSION.SDK_INT >= 21)
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
//Set proxy
if(appSettings.isProxyEnabled()) {
if(!setProxy()) Toast.makeText(this, R.string.toast_set_proxy_failed, Toast.LENGTH_LONG).show();
}
/*
* WebViewClient
*/
@ -885,7 +898,7 @@ public class MainActivity extends AppCompatActivity
case R.id.nav_aspects: {
if (Helpers.isOnline(MainActivity.this)) {
// webView.loadUrl("https://" + podDomain + "/aspects");
// webView.loadUrl("https://" + podDomain + "/aspects");
Helpers.showAspectList(webView, app);
setTitle(R.string.title_aspects);
} else {
@ -946,7 +959,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),
getString(R.string.settings_proxy)};
if (Helpers.isOnline(MainActivity.this)) {
new AlertDialog.Builder(MainActivity.this)
@ -979,6 +993,33 @@ public class MainActivity extends AppCompatActivity
})
.show();
break;
case 4:
final AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(MainActivity.this);
final View dialogLayout = getLayoutInflater().inflate(R.layout.proxy_configuration_dialog, null);
final SwitchCompat enabled_toggle = (SwitchCompat) dialogLayout.findViewById(R.id.proxy_toggle);
final EditText host_edit = (EditText) dialogLayout.findViewById(R.id.proxy_host_edit);
final EditText port_edit = (EditText) dialogLayout.findViewById(R.id.proxy_port_edit);
enabled_toggle.setChecked(appSettings.isProxyEnabled());
host_edit.setText(appSettings.getProxyHost());
port_edit.setText(""+appSettings.getProxyPort());
dialogBuilder.setView(dialogLayout).setTitle(R.string.settings_proxy)
.setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
boolean proxyEnabled = enabled_toggle.isChecked();
String host = host_edit.getText().toString();
int port = Integer.parseInt(port_edit.getText().toString());
if(proxyEnabled) {
if(!setProxy(host, port)) {
Toast.makeText(MainActivity.this, R.string.toast_set_proxy_failed,Toast.LENGTH_SHORT).show();
}
}
else resetProxy();
}
}).setNegativeButton(android.R.string.cancel, null).show();
break;
}
}
}).show();
@ -1069,4 +1110,66 @@ public class MainActivity extends AppCompatActivity
grantResults);
}
}
/**
* Set proxy according to arguments. host must not be "" or null, port must be positive.
* Return true on success and update appSettings' proxy related values.
* @param host proxy host (eg. localhost or 127.0.0.1)
* @param port proxy port (eg. 8118)
* @return success
* @throws IllegalArgumentException if arguments do not fit specifications above
*/
private boolean setProxy(final String host, final int port) {
if(host != null && !host.equals("") && port >=0) {
//Temporary change thread policy
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(tmp);
NetCipher.setProxy(host, port); //Proxy for HttpsUrlConnections
try {
//Proxy for the webview
WebkitProxy.setProxy(MainActivity.class.getName(), getApplicationContext(), null, host, port);
} catch (Exception e) { /*Nothing we can do*/ }
appSettings.setProxyEnabled(true);
appSettings.setProxyHost(host);
appSettings.setProxyPort(port);
StrictMode.setThreadPolicy(old);
webView.reload();
return true;
} else {
return false;
}
}
private boolean setProxy() {
return setProxy(appSettings.getProxyHost(), appSettings.getProxyPort());
}
private void resetProxy() {
appSettings.setProxyEnabled(false);
//Temporary change thread policy
StrictMode.ThreadPolicy old = StrictMode.getThreadPolicy();
StrictMode.ThreadPolicy tmp = new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(tmp);
NetCipher.clearProxy();
try{
WebkitProxy.resetProxy(MainActivity.class.getName(), this);
} catch (Exception e) {
//Nothing we can do.
}
StrictMode.setThreadPolicy(old);
//Restart app
Intent restartActivity = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 12374, restartActivity, PendingIntent.FLAG_CANCEL_CURRENT);
AlarmManager mgr = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
mgr.set(AlarmManager.RTC, System.currentTimeMillis() + 100, pendingIntent);
System.exit(0);
}
}

View file

@ -70,6 +70,9 @@ 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 PROXY_ENABLED = "isProxyEnabled";
private static final String PROXY_HOST = "proxyHost";
private static final String PROXY_PORT = "proxyPort";
}
@ -150,4 +153,41 @@ public class AppSettings {
}
return aspects;
}
public void setProxyEnabled(boolean enabled) {
//commit instead of apply because the app is likely to be killed before apply is called.
prefApp.edit().putBoolean(PREF.PROXY_ENABLED, enabled).commit();
}
/**
* Default return value: false
* @return whether proxy is enabled or not
*/
public boolean isProxyEnabled() {
return prefApp.getBoolean(PREF.PROXY_ENABLED, false);
}
public void setProxyHost(String host) {
setString(prefApp, PREF.PROXY_HOST, host);
}
/**
* Default value: ""
* @return proxy host
*/
public String getProxyHost() {
return prefApp.getString(PREF.PROXY_HOST, "");
}
public void setProxyPort(int port) {
setInt(prefApp, PREF.PROXY_PORT, port);
}
/**
* Default value: 0
* @return proxy port
*/
public int getProxyPort() {
return prefApp.getInt(PREF.PROXY_PORT, 0);
}
}

View file

@ -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<String> 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) {/*Nothing to do*/}
connection.disconnect();
} else {
//TODO Notify User about failure
Log.e(TAG, "Failed to download list of pods");
}
} catch (IOException e) {
@ -136,4 +138,4 @@ public class GetPodsService extends Service {
throw new UnsupportedOperationException("Not yet implemented");
}
}
}

View file

@ -13,7 +13,12 @@ import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.net.ssl.HttpsURLConnection;
import info.guardianproject.netcipher.NetCipher;
/**
* Task that can be used to download images from URLs and store them in storage
* Created by Gregor Santner (gsantner) on 24.03.16.
*/
public class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {
@ -35,9 +40,12 @@ public class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {
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 +53,12 @@ public class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out);
}
try {
inStream.close();
} catch (IOException e) {/*Nothing*/}
connection.disconnect();
} catch (Exception e) {
Log.e(App.TAG, e.getMessage());
} finally {
@ -64,4 +78,4 @@ public class ImageDownloadTask extends AsyncTask<String, Void, Bitmap> {
imageView.setImageBitmap(result);
}
}
}
}

View file

@ -10,11 +10,16 @@ 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;
/**
* AsyncTask to fetch a users profile
* Created by Gregor Santner (gsantner) on 30.03.16.
*/
public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
@ -37,18 +42,21 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
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("<body")) {
@ -57,6 +65,14 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
break;
}
}
try{
br.close();
inStream.close();
} catch (IOException e){/*Nothing*/}
connection.disconnect();
} catch (IOException e) {
e.printStackTrace();
}
@ -70,4 +86,4 @@ public class ProfileFetchTask extends AsyncTask<Void, Void, Void> {
return null;
}
}
}

View file

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- Inner layout for margin -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_margin="@dimen/activity_horizontal_margin">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/lay_toggle">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:text="@string/proxy_enabled" />
<android.support.v7.widget.SwitchCompat
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/proxy_toggle"
android:layout_alignParentRight="true"
android:layout_alignParentEnd="true"/>
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/proxy_host"
android:id="@+id/text_host"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/proxy_host_edit"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/proxy_port"
android:id="@+id/text_port"/>
<EditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:inputType="number"
android:id="@+id/proxy_port_edit"/>
</LinearLayout>
</LinearLayout>

View file

@ -172,5 +172,10 @@ along with this program. If not, see http://www.gnu.org/licenses.&lt;br> &lt;br
<string name="toast_saved_image_to_location">Speichere Bild als</string>
<string name="toast_link_address_copied">Linkadresse kopiert …</string>
<string name="share_dotdodot">Teilen…</string>
<string name="proxy_enabled">Aktiviert</string>
<string name="proxy_host">Host</string>
<string name="settings_proxy">Proxy</string>
<string name="proxy_port">Port</string>
<string name="toast_set_proxy_failed">Warnung: Proxy konnte nicht aktiviert werden…</string>
</resources>

View file

@ -78,6 +78,10 @@
<string name="settings_images_switch_on">Do load images</string>
<string name="settings_images_switch_off">Do not load images</string>
<string name="settings_view">Change view</string>
<string name="settings_proxy">Proxy</string>
<string name="proxy_enabled">Enabled</string>
<string name="proxy_host">Host</string>
<string name="proxy_port">Port</string>
<string name="share_link">Share link as text</string>
<string name="share_screenshot">Share screenshot of webpage</string>
<string name="take_screenshot">Take screenshot of webpage</string>
@ -219,4 +223,6 @@
<string name="prefix_https" translatable="false">https://</string>
<string name="share_dotdodot">Share…</string>
<string name="app_hashtag" translatable="false">#DiasporaForAndroid</string>
<string name="toast_set_proxy_failed">Warning: Could not set network proxy…</string>
</resources>