From 0e657eed56cf93b7640b904f92390ccec97273f5 Mon Sep 17 00:00:00 2001 From: link2xt Date: Thu, 20 Apr 2023 19:30:19 +0000 Subject: [PATCH] Set WebView proxy to 0.0.0.0 when possible (#2539) * Set WebView proxy to 0.0.0.0 when possible * add DcHttpResponse to wrapper * use new DcHttpResponse to show images in email-html-view * null-encoding is fine for WebResourceResponse() --------- Co-authored-by: B. Petersen --- jni/dc_wrapper.c | 69 +++++++++++++++++++ src/com/b44t/messenger/DcContext.java | 2 + src/com/b44t/messenger/DcHttpResponse.java | 22 ++++++ .../securesms/FullMsgActivity.java | 26 +++++++ .../securesms/WebViewActivity.java | 27 ++++++++ 5 files changed, 146 insertions(+) create mode 100644 src/com/b44t/messenger/DcHttpResponse.java diff --git a/jni/dc_wrapper.c b/jni/dc_wrapper.c index b08a5f2677..5b985bdb49 100644 --- a/jni/dc_wrapper.c +++ b/jni/dc_wrapper.c @@ -1021,6 +1021,15 @@ JNIEXPORT jlong Java_com_b44t_messenger_DcContext_getProviderFromEmailWithDnsCPt } +JNIEXPORT jlong Java_com_b44t_messenger_DcContext_getHttpResponseCPtr(JNIEnv *env, jobject obj, jstring url) +{ + CHAR_REF(url); + jlong ret = (jlong)dc_get_http_response(get_dc_context(env, obj), urlPtr); + CHAR_UNREF(url); + return ret; +} + + /******************************************************************************* * DcEventEmitter ******************************************************************************/ @@ -2068,3 +2077,63 @@ JNIEXPORT jstring Java_com_b44t_messenger_DcProvider_getOverviewPage(JNIEnv *env return ret; } + +/******************************************************************************* + * DcHttpResponse + ******************************************************************************/ + + +static dc_http_response_t* get_dc_http_response(JNIEnv *env, jobject obj) +{ + static jfieldID fid = 0; + if (fid==0) { + jclass cls = (*env)->GetObjectClass(env, obj); + fid = (*env)->GetFieldID(env, cls, "httpResponseCPtr", "J" /*Signature, J=long*/); + } + if (fid) { + return (dc_http_response_t*)(*env)->GetLongField(env, obj, fid); + } + return NULL; +} + + +JNIEXPORT void Java_com_b44t_messenger_DcHttpResponse_unrefHttpResponseCPtr(JNIEnv *env, jobject obj) +{ + dc_http_response_unref(get_dc_http_response(env, obj)); +} + + +JNIEXPORT jstring Java_com_b44t_messenger_DcHttpResponse_getMimetype(JNIEnv *env, jobject obj) +{ + char* temp = dc_http_response_get_mimetype(get_dc_http_response(env, obj)); + jstring ret = NULL; + if (temp) { + ret = JSTRING_NEW(temp); + } + dc_str_unref(temp); + return ret; +} + + +JNIEXPORT jstring Java_com_b44t_messenger_DcHttpResponse_getEncoding(JNIEnv *env, jobject obj) +{ + char* temp = dc_http_response_get_encoding(get_dc_http_response(env, obj)); + jstring ret = NULL; + if (temp) { + ret = JSTRING_NEW(temp); + } + dc_str_unref(temp); + return ret; +} + + +JNIEXPORT jbyteArray Java_com_b44t_messenger_DcHttpResponse_getBlob(JNIEnv *env, jobject obj) +{ + jbyteArray ret = NULL; + dc_http_response_t* http_response = get_dc_http_response(env, obj); + size_t ptr_size = dc_http_response_get_size(http_response); + uint8_t* ptr = dc_http_response_get_blob(http_response); + ret = ptr2jbyteArray(env, ptr, ptr_size); + dc_str_unref((char*)ptr); + return ret; +} diff --git a/src/com/b44t/messenger/DcContext.java b/src/com/b44t/messenger/DcContext.java index caa7ca647b..e0314d584b 100644 --- a/src/com/b44t/messenger/DcContext.java +++ b/src/com/b44t/messenger/DcContext.java @@ -216,6 +216,7 @@ public void unref() { public DcArray getLocations (int chat_id, int contact_id, long timestamp_start, long timestamp_end) { return new DcArray(getLocationsCPtr(chat_id, contact_id, timestamp_start, timestamp_end)); } public native void deleteAllLocations (); public DcProvider getProviderFromEmailWithDns (String email) { long cptr = getProviderFromEmailWithDnsCPtr(email); return cptr!=0 ? new DcProvider(cptr) : null; } + public DcHttpResponse getHttpResponse (String url) { long cptr = getHttpResponseCPtr(url); return cptr!=0 ? new DcHttpResponse(cptr) : null; } public String getNameNAddr() { String displayname = getConfig("displayname"); @@ -255,4 +256,5 @@ public String getNameNAddr() { private native long checkQrCPtr (String qr); private native long getProviderFromEmailWithDnsCPtr (String addr); private native long newBackupProviderCPtr(); + private native long getHttpResponseCPtr(String url); } diff --git a/src/com/b44t/messenger/DcHttpResponse.java b/src/com/b44t/messenger/DcHttpResponse.java new file mode 100644 index 0000000000..f41f9cd1c9 --- /dev/null +++ b/src/com/b44t/messenger/DcHttpResponse.java @@ -0,0 +1,22 @@ +package com.b44t.messenger; + +public class DcHttpResponse { + + public DcHttpResponse(long httpResponseCPtr) { + this.httpResponseCPtr = httpResponseCPtr; + } + + @Override protected void finalize() throws Throwable { + super.finalize(); + unrefHttpResponseCPtr(); + httpResponseCPtr = 0; + } + + public native String getMimetype (); + public native String getEncoding (); + public native byte[] getBlob (); + + // working with raw c-data + private long httpResponseCPtr; // CAVE: the name is referenced in the JNI + private native void unrefHttpResponseCPtr(); +} diff --git a/src/org/thoughtcrime/securesms/FullMsgActivity.java b/src/org/thoughtcrime/securesms/FullMsgActivity.java index c3677c3e80..7baa1f1bad 100644 --- a/src/org/thoughtcrime/securesms/FullMsgActivity.java +++ b/src/org/thoughtcrime/securesms/FullMsgActivity.java @@ -3,17 +3,20 @@ import android.os.Bundle; import android.view.Menu; import android.view.MenuItem; +import android.webkit.WebResourceResponse; import android.webkit.WebSettings; import androidx.appcompat.app.AlertDialog; import com.b44t.messenger.DcContext; +import com.b44t.messenger.DcHttpResponse; import org.thoughtcrime.securesms.connect.DcHelper; import org.thoughtcrime.securesms.util.DynamicTheme; import org.thoughtcrime.securesms.util.Prefs; import org.thoughtcrime.securesms.util.Util; +import java.io.ByteArrayInputStream; import java.lang.ref.WeakReference; public class FullMsgActivity extends WebViewActivity @@ -164,4 +167,27 @@ private void onChangeLoadRemoteContent(LoadRemoteContent loadRemoteContent) { webView.getSettings().setBlockNetworkLoads(!this.loadRemoteContent); webView.reload(); } + + @Override + protected WebResourceResponse interceptRequest(String url) { + WebResourceResponse res = null; + try { + if (url == null) { + throw new Exception("no url specified"); + } + DcHttpResponse httpResponse = dcContext.getHttpResponse(url); + if (httpResponse == null) { + throw new Exception(dcContext.getLastError()); + } + String mimeType = httpResponse.getMimetype(); + if (mimeType == null) { + mimeType = "application/octet-stream"; + } + res = new WebResourceResponse(mimeType, httpResponse.getEncoding(), new ByteArrayInputStream(httpResponse.getBlob())); + } catch (Exception e) { + e.printStackTrace(); + res = new WebResourceResponse("text/plain", "UTF-8", new ByteArrayInputStream(("Error: " + e.getMessage()).getBytes())); + } + return res; + } } diff --git a/src/org/thoughtcrime/securesms/WebViewActivity.java b/src/org/thoughtcrime/securesms/WebViewActivity.java index 272b681ea5..3cc795fdc7 100644 --- a/src/org/thoughtcrime/securesms/WebViewActivity.java +++ b/src/org/thoughtcrime/securesms/WebViewActivity.java @@ -21,10 +21,14 @@ import androidx.appcompat.widget.SearchView; import androidx.webkit.WebSettingsCompat; import androidx.webkit.WebViewFeature; +import androidx.webkit.ProxyController; +import androidx.webkit.ProxyConfig; import org.thoughtcrime.securesms.util.DynamicLanguage; import org.thoughtcrime.securesms.util.DynamicTheme; +import java.util.concurrent.Executor; + public class WebViewActivity extends PassphraseRequiredActionBarActivity implements SearchView.OnQueryTextListener, WebView.FindListener @@ -39,6 +43,29 @@ public class WebViewActivity extends PassphraseRequiredActionBarActivity protected void onPreCreate() { dynamicTheme.onCreate(this); dynamicLanguage.onCreate(this); + + if (WebViewFeature.isFeatureSupported(WebViewFeature.PROXY_OVERRIDE)) { + // Set proxy to non-routable address. + ProxyConfig proxyConfig = new ProxyConfig.Builder() + .removeImplicitRules() + .addProxyRule("0.0.0.0") + .build(); + Executor executor = new Executor() { + @Override + public void execute(Runnable command) { + command.run(); + } + }; + Runnable listener = new Runnable() { + @Override + public void run() { + Log.i(TAG, "Successfully set WebView proxy."); + } + }; + ProxyController.getInstance().setProxyOverride(proxyConfig, executor, listener); + } else { + Log.w(TAG, "Cannot set WebView proxy."); + } } @Override