Browse Source

Optional proxy support

Signed-off-by: tobiasKaminsky <tobias@kaminsky.me>
tobiasKaminsky 5 years ago
parent
commit
3d1265d6aa

+ 8 - 0
app/src/main/java/com/owncloud/android/MainApp.java

@@ -35,6 +35,7 @@ import android.content.Intent;
 import android.content.pm.ActivityInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Environment;
@@ -316,6 +317,13 @@ public class MainApp extends MultiDexApplication implements HasAndroidInjector {
 
         OwnCloudClientManagerFactory.setUserAgent(getUserAgent());
 
+        try {
+            OwnCloudClientManagerFactory.setProxyHost(getResources().getString(R.string.proxy_host));
+            OwnCloudClientManagerFactory.setProxyPort(getResources().getInteger(R.integer.proxy_port));
+        } catch (Resources.NotFoundException e) {
+            // no proxy set
+        }
+
         // initialise thumbnails cache on background thread
         new ThumbnailsCacheManager.InitDiskCacheTask().execute();
 

+ 2 - 0
app/src/main/java/com/owncloud/android/authentication/AuthenticatorActivity.java

@@ -366,6 +366,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
     private void initWebViewLogin(String baseURL, boolean useGenericUserAgent) {
         viewThemeUtils.platform.colorCircularProgressBar(accountSetupWebviewBinding.loginWebviewProgressBar, ColorRole.ON_PRIMARY_CONTAINER);
         accountSetupWebviewBinding.loginWebview.setVisibility(View.GONE);
+        new WebViewUtil(this).setProxyKKPlus(accountSetupWebviewBinding.loginWebview);
 
         accountSetupWebviewBinding.loginWebview.getSettings().setAllowFileAccess(false);
         accountSetupWebviewBinding.loginWebview.getSettings().setJavaScriptEnabled(true);
@@ -402,6 +403,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
             url = getResources().getString(R.string.webview_login_url);
         }
 
+        new WebViewUtil(this).setProxyKKPlus(accountSetupWebviewBinding.loginWebview);
         if (url.startsWith(HTTPS_PROTOCOL)) {
             strictMode = true;
         }

+ 6 - 0
app/src/main/java/com/owncloud/android/ui/activity/EditorWebView.java

@@ -49,6 +49,7 @@ import com.owncloud.android.datamodel.SyncedFolderProvider;
 import com.owncloud.android.datamodel.ThumbnailsCacheManager;
 import com.owncloud.android.utils.DisplayUtils;
 import com.owncloud.android.utils.MimeTypeUtil;
+import com.owncloud.android.utils.WebViewUtil;
 
 import javax.inject.Inject;
 
@@ -82,6 +83,11 @@ public abstract class EditorWebView extends ExternalSiteWebView {
         this.url = loadedUrl;
 
         if (!url.isEmpty()) {
+            new WebViewUtil(getApplicationContext()).setProxyKKPlus(this.getWebView());
+            try {
+                Thread.sleep(1000);
+            } catch (InterruptedException e) {
+            }
             this.getWebView().loadUrl(url);
 
             new Handler().postDelayed(() -> {

+ 2 - 0
app/src/main/java/com/owncloud/android/ui/activity/ExternalSiteWebView.java

@@ -41,6 +41,7 @@ import com.owncloud.android.databinding.ExternalsiteWebviewBinding;
 import com.owncloud.android.lib.common.utils.Log_OC;
 import com.owncloud.android.ui.NextcloudWebViewClient;
 import com.owncloud.android.utils.DisplayUtils;
+import com.owncloud.android.utils.WebViewUtil;
 
 import java.io.InputStream;
 
@@ -160,6 +161,7 @@ public class ExternalSiteWebView extends FileActivity {
             }
         });
 
+        new WebViewUtil(getApplicationContext()).setProxyKKPlus(getWebView());
         getWebView().loadUrl(url);
     }
 

+ 69 - 0
app/src/main/java/com/owncloud/android/utils/WebViewUtil.kt

@@ -21,12 +21,21 @@
 
 package com.owncloud.android.utils
 
+import android.annotation.SuppressLint
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
+import android.net.Proxy
 import android.net.Uri
+import android.text.TextUtils
+import android.util.ArrayMap
+import android.util.Log
+import android.webkit.WebView
 import com.google.android.material.dialog.MaterialAlertDialogBuilder
 import com.owncloud.android.R
+import com.owncloud.android.lib.common.OwnCloudClientManagerFactory
+import java.io.PrintWriter
+import java.io.StringWriter
 
 class WebViewUtil(private val context: Context) {
 
@@ -107,4 +116,64 @@ class WebViewUtil(private val context: Context) {
     private fun getMinimumSupportedMajorWebViewVersion(): String {
         return "118"
     }
+
+    /**
+     * From https://stackoverflow.com/a/18453384
+     *
+     * @return
+     */
+    @SuppressLint("PrivateApi", "DiscouragedPrivateApi")
+    fun setProxyKKPlus(webView: WebView) {
+        val proxyHost = OwnCloudClientManagerFactory.getProxyHost()
+        val proxyPort = OwnCloudClientManagerFactory.getProxyPort()
+
+        if (TextUtils.isEmpty(proxyHost) || proxyPort <= 0) {
+            return
+        }
+
+        val applicationClassName = "android.app.Application"
+        Log.d(PROXY_TAG, "Setting proxy with >= 4.4 API.")
+
+        val appContext = webView.context.applicationContext
+
+        System.setProperty("http.proxyHost", proxyHost)
+        System.setProperty("http.proxyPort", proxyPort.toString())
+        System.setProperty("https.proxyHost", proxyHost)
+        System.setProperty("https.proxyPort", proxyPort.toString())
+        try {
+            val applicationClass = Class.forName(applicationClassName)
+            val loadedApkField = applicationClass.getField("mLoadedApk")
+            loadedApkField.isAccessible = true
+            val loadedApk = loadedApkField[appContext]
+            val loadedApkCls = Class.forName("android.app.LoadedApk")
+            val receiversField = loadedApkCls.getDeclaredField("mReceivers")
+            receiversField.isAccessible = true
+            val receivers = receiversField[loadedApk] as ArrayMap<*, *>
+            for (receiverMap in receivers.values) {
+                for (rec in (receiverMap as ArrayMap<*, *>).keys) {
+                    val clazz: Class<*> = rec.javaClass
+                    if (clazz.name.contains("ProxyChangeListener")) {
+                        val onReceiveMethod = clazz.getDeclaredMethod(
+                            "onReceive",
+                            Context::class.java,
+                            Intent::class.java
+                        )
+                        val intent = Intent(Proxy.PROXY_CHANGE_ACTION)
+                        onReceiveMethod.invoke(rec, appContext, intent)
+                    }
+                }
+            }
+            Log.d(PROXY_TAG, "Setting proxy with >= 4.4 API successful!")
+        } catch (e: Exception) {
+            val sw = StringWriter()
+            e.printStackTrace(PrintWriter(sw))
+            val exceptionAsString = sw.toString()
+            e.message?.let { Log.v(PROXY_TAG, it) }
+            Log.v(PROXY_TAG, exceptionAsString)
+        }
+    }
+
+    companion object {
+        private const val PROXY_TAG = "PROXY"
+    }
 }

+ 4 - 0
app/src/main/res/values/setup.xml

@@ -25,6 +25,10 @@
     <bool name="show_provider_or_own_installation">true</bool>
     <string name="provider_registration_server">https://www.nextcloud.com/register</string>
 
+    <!-- specify built in proxy -->
+    <string name="proxy_host"></string>
+    <integer name="proxy_port">-1</integer>
+
     <!-- Flags to enable/disable some features -->
     <string name="send_files_to_other_apps">on</string>
     <bool name="share_via_link_feature">true</bool>