From 19e52f7a271a1acee2bbccd2592e48821acd5c5c Mon Sep 17 00:00:00 2001 From: sethkfman <10342624+sethkfman@users.noreply.github.com> Date: Tue, 25 Jul 2023 10:28:57 -0600 Subject: [PATCH] fix: Android filename validation when downloading from browser (#6844) * added filename validation and Toast when validation fails during downloading * Added null check with fileName --- patches/react-native-webview+11.13.0.patch | 137 +++++++++++---------- 1 file changed, 72 insertions(+), 65 deletions(-) diff --git a/patches/react-native-webview+11.13.0.patch b/patches/react-native-webview+11.13.0.patch index 28d02a5346d..311d1734e94 100644 --- a/patches/react-native-webview+11.13.0.patch +++ b/patches/react-native-webview+11.13.0.patch @@ -83,7 +83,7 @@ index 0000000..f4a6af9 + } +} diff --git a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java -index f743bbc..a612d0f 100644 +index f743bbc..ede5475 100644 --- a/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +++ b/node_modules/react-native-webview/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java @@ -5,6 +5,7 @@ import android.annotation.TargetApi; @@ -128,7 +128,7 @@ index f743bbc..a612d0f 100644 import android.widget.FrameLayout; import androidx.annotation.Nullable; -@@ -88,18 +96,51 @@ import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; +@@ -88,18 +96,54 @@ import com.reactnativecommunity.webview.events.TopRenderProcessGoneEvent; import org.json.JSONException; import org.json.JSONObject; @@ -148,6 +148,7 @@ index f743bbc..a612d0f 100644 +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.charset.UnsupportedCharsetException; ++import java.text.Bidi; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; @@ -174,13 +175,15 @@ index f743bbc..a612d0f 100644 + +import android.content.DialogInterface; +import android.os.Bundle; ++import android.widget.Toast; ++ +import androidx.appcompat.app.AlertDialog; +import androidx.appcompat.app.AppCompatActivity; + /** * Manages instances of {@link WebView} *

-@@ -137,13 +178,19 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -137,13 +181,19 @@ public class RNCWebViewManager extends SimpleViewManager { public static final int COMMAND_LOAD_URL = 7; public static final int COMMAND_FOCUS = 8; @@ -201,7 +204,7 @@ index f743bbc..a612d0f 100644 protected static final String HTML_MIME_TYPE = "text/html"; protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView"; protected static final String HTTP_METHOD_POST = "POST"; -@@ -155,13 +202,19 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -155,13 +205,19 @@ public class RNCWebViewManager extends SimpleViewManager { protected RNCWebChromeClient mWebChromeClient = null; protected boolean mAllowsFullscreenVideo = false; @@ -226,7 +229,7 @@ index f743bbc..a612d0f 100644 }; } -@@ -182,6 +235,7 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -182,6 +238,7 @@ public class RNCWebViewManager extends SimpleViewManager { @TargetApi(Build.VERSION_CODES.LOLLIPOP) protected WebView createViewInstance(ThemedReactContext reactContext) { RNCWebView webView = createRNCWebViewInstance(reactContext); @@ -234,7 +237,7 @@ index f743bbc..a612d0f 100644 setupWebChromeClient(reactContext, webView); reactContext.addLifecycleEventListener(webView); mWebViewConfig.configWebView(webView); -@@ -209,47 +263,156 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -209,47 +266,161 @@ public class RNCWebViewManager extends SimpleViewManager { } webView.setDownloadListener(new DownloadListener() { @@ -250,24 +253,28 @@ index f743bbc..a612d0f 100644 - String fileName = URLUtil.guessFileName(url, contentDisposition, mimetype); - String downloadMessage = "Downloading " + fileName; -+ AlertDialog.Builder builder = new AlertDialog.Builder(mReactContext); -+ builder.setMessage("Do you want to download \n" + fileName + "?"); -+ builder.setCancelable(false); -+ builder.setPositiveButton("Download", new DialogInterface.OnClickListener() { -+ public void onClick(DialogInterface dialog, int which) { -+ String downloadMessage = "Downloading " + fileName; -+ -+ //Attempt to add cookie, if it exists -+ URL urlObj = null; -+ try { -+ urlObj = new URL(url); -+ String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost(); -+ String cookie = CookieManager.getInstance().getCookie(baseUrl); -+ request.addRequestHeader("Cookie", cookie); -+ } catch (MalformedURLException e) { -+ System.out.println("Error getting cookie for DownloadManager: " + e.toString()); -+ e.printStackTrace(); -+ } ++ //Filename validation checking for files that use RTL characters and do not allow those types ++ if(fileName == null || (fileName != null && (new Bidi(fileName, Bidi.DIRECTION_DEFAULT_LEFT_TO_RIGHT).isMixed()))) { ++ Toast.makeText(mReactContext, "Invalid filename or type", Toast.LENGTH_SHORT).show(); ++ } else { ++ AlertDialog.Builder builder = new AlertDialog.Builder(mReactContext); ++ builder.setMessage("Do you want to download \n" + fileName + "?"); ++ builder.setCancelable(false); ++ builder.setPositiveButton("Download", new DialogInterface.OnClickListener() { ++ public void onClick(DialogInterface dialog, int which) { ++ String downloadMessage = "Downloading " + fileName; ++ ++ //Attempt to add cookie, if it exists ++ URL urlObj = null; ++ try { ++ urlObj = new URL(url); ++ String baseUrl = urlObj.getProtocol() + "://" + urlObj.getHost(); ++ String cookie = CookieManager.getInstance().getCookie(baseUrl); ++ request.addRequestHeader("Cookie", cookie); ++ } catch (MalformedURLException e) { ++ System.out.println("Error getting cookie for DownloadManager: " + e.toString()); ++ e.printStackTrace(); ++ } - //Attempt to add cookie, if it exists - URL urlObj = null; @@ -279,25 +286,25 @@ index f743bbc..a612d0f 100644 - } catch (MalformedURLException e) { - System.out.println("Error getting cookie for DownloadManager: " + e.toString()); - e.printStackTrace(); -- } -+ //Finish setting up request -+ request.addRequestHeader("User-Agent", userAgent); -+ request.setTitle(fileName); -+ request.setDescription(downloadMessage); -+ request.allowScanningByMediaScanner(); -+ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); -+ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); -+ module.setDownloadRequest(request); -+ if (module.grantFileDownloaderPermissions()) { -+ module.downloadFile(); ++ //Finish setting up request ++ request.addRequestHeader("User-Agent", userAgent); ++ request.setTitle(fileName); ++ request.setDescription(downloadMessage); ++ request.allowScanningByMediaScanner(); ++ request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED); ++ request.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, fileName); ++ module.setDownloadRequest(request); ++ if (module.grantFileDownloaderPermissions()) { ++ module.downloadFile(); ++ } + } -+ } -+ }); -+ builder.setNegativeButton("Cancel", (DialogInterface.OnClickListener) (dialog, which) -> { -+ return; -+ }); -+ AlertDialog alertDialog = builder.create(); -+ alertDialog.show(); ++ }); ++ builder.setNegativeButton("Cancel", (DialogInterface.OnClickListener) (dialog, which) -> { ++ return; ++ }); ++ AlertDialog alertDialog = builder.create(); ++ alertDialog.show(); + } + } + }); @@ -417,7 +424,7 @@ index f743bbc..a612d0f 100644 @ReactProp(name = "javaScriptEnabled") public void setJavaScriptEnabled(WebView view, boolean enabled) { view.getSettings().setJavaScriptEnabled(enabled); -@@ -285,13 +448,10 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -285,13 +456,10 @@ public class RNCWebViewManager extends SimpleViewManager { if (enabled) { Context ctx = view.getContext(); if (ctx != null) { @@ -431,7 +438,7 @@ index f743bbc..a612d0f 100644 } } -@@ -327,12 +487,12 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -327,12 +495,12 @@ public class RNCWebViewManager extends SimpleViewManager { public void setLayerType(WebView view, String layerTypeString) { int layerType = View.LAYER_TYPE_NONE; switch (layerTypeString) { @@ -450,7 +457,7 @@ index f743bbc..a612d0f 100644 } view.setLayerType(layerType, null); } -@@ -387,9 +547,9 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -387,9 +555,9 @@ public class RNCWebViewManager extends SimpleViewManager { @ReactProp(name = "userAgent") public void setUserAgent(WebView view, @Nullable String userAgent) { if (userAgent != null) { @@ -462,7 +469,7 @@ index f743bbc..a612d0f 100644 } this.setUserAgentString(view); } -@@ -399,19 +559,19 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -399,19 +567,19 @@ public class RNCWebViewManager extends SimpleViewManager { if(applicationName != null) { if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { String defaultUserAgent = WebSettings.getDefaultUserAgent(view.getContext()); @@ -488,7 +495,7 @@ index f743bbc..a612d0f 100644 } else if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) { // handle unsets of `userAgent` prop as long as device is >= API 17 view.getSettings().setUserAgentString(WebSettings.getDefaultUserAgent(view.getContext())); -@@ -490,7 +650,6 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -490,7 +658,6 @@ public class RNCWebViewManager extends SimpleViewManager { // Disable caching view.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE); @@ -496,7 +503,7 @@ index f743bbc..a612d0f 100644 view.clearHistory(); view.clearCache(true); -@@ -842,13 +1001,116 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -842,13 +1009,116 @@ public class RNCWebViewManager extends SimpleViewManager { } } @@ -614,7 +621,7 @@ index f743bbc..a612d0f 100644 public void setIgnoreErrFailedForThisURL(@Nullable String url) { ignoreErrFailedForThisURL = url; -@@ -857,24 +1119,26 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -857,24 +1127,26 @@ public class RNCWebViewManager extends SimpleViewManager { @Override public void onPageFinished(WebView webView, String url) { super.onPageFinished(webView, url); @@ -646,7 +653,7 @@ index f743bbc..a612d0f 100644 ((RNCWebView) webView).dispatchEvent( webView, new TopLoadingStartEvent( -@@ -882,6 +1146,20 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -882,6 +1154,20 @@ public class RNCWebViewManager extends SimpleViewManager { createWebViewEvent(webView, url))); } @@ -667,7 +674,7 @@ index f743bbc..a612d0f 100644 @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { final RNCWebView rncWebView = (RNCWebView) view; -@@ -891,7 +1169,6 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -891,7 +1177,6 @@ public class RNCWebViewManager extends SimpleViewManager { final Pair> lock = RNCWebViewModule.shouldOverrideUrlLoadingLock.getNewLock(); final int lockIdentifier = lock.first; final AtomicReference lockObject = lock.second; @@ -675,7 +682,7 @@ index f743bbc..a612d0f 100644 final WritableMap event = createWebViewEvent(view, url); event.putInt("lockIdentifier", lockIdentifier); rncWebView.sendDirectMessage("onShouldStartLoadWithRequest", event); -@@ -919,6 +1196,17 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -919,6 +1204,17 @@ public class RNCWebViewManager extends SimpleViewManager { RNCWebViewModule.shouldOverrideUrlLoadingLock.removeLock(lockIdentifier); return shouldOverride; @@ -693,7 +700,7 @@ index f743bbc..a612d0f 100644 } else { FLog.w(TAG, "Couldn't use blocking synchronous call for onShouldStartLoadWithRequest due to debugging or missing Catalyst instance, falling back to old event-and-load."); progressChangedFilter.setWaitingForCommandLoadUrl(true); -@@ -934,67 +1222,86 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -934,67 +1230,86 @@ public class RNCWebViewManager extends SimpleViewManager { @TargetApi(Build.VERSION_CODES.N) @Override public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) { @@ -832,7 +839,7 @@ index f743bbc..a612d0f 100644 } @Override -@@ -1005,9 +1312,9 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1005,9 +1320,9 @@ public class RNCWebViewManager extends SimpleViewManager { String failingUrl) { if (ignoreErrFailedForThisURL != null @@ -845,7 +852,7 @@ index f743bbc..a612d0f 100644 // This is a workaround for a bug in the WebView. // See these chromium issues for more context: -@@ -1056,36 +1363,36 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1056,36 +1371,36 @@ public class RNCWebViewManager extends SimpleViewManager { @TargetApi(Build.VERSION_CODES.O) @Override public boolean onRenderProcessGone(WebView webView, RenderProcessGoneDetail detail) { @@ -906,7 +913,7 @@ index f743bbc..a612d0f 100644 } protected void emitFinishEvent(WebView webView, String url) { -@@ -1138,6 +1445,7 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1138,6 +1453,7 @@ public class RNCWebViewManager extends SimpleViewManager { protected View mVideoView; protected WebChromeClient.CustomViewCallback mCustomViewCallback; @@ -914,7 +921,7 @@ index f743bbc..a612d0f 100644 /* * - Permissions - -@@ -1217,19 +1525,44 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1217,19 +1533,44 @@ public class RNCWebViewManager extends SimpleViewManager { ArrayList requestedAndroidPermissions = new ArrayList<>(); for (String requestedResource : request.getResources()) { String androidPermission = null; @@ -960,7 +967,7 @@ index f743bbc..a612d0f 100644 } else { requestedAndroidPermissions.add(androidPermission); } -@@ -1238,8 +1571,11 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1238,8 +1579,11 @@ public class RNCWebViewManager extends SimpleViewManager { // If all the permissions are already granted, send the response to the WebView synchronously if (requestedAndroidPermissions.isEmpty()) { @@ -974,7 +981,7 @@ index f743bbc..a612d0f 100644 return; } -@@ -1250,6 +1586,10 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1250,6 +1594,10 @@ public class RNCWebViewManager extends SimpleViewManager { requestPermissions(requestedAndroidPermissions); } @@ -985,7 +992,7 @@ index f743bbc..a612d0f 100644 @Override public void onGeolocationPermissionsShowPrompt(String origin, GeolocationPermissions.Callback callback) { -@@ -1402,6 +1742,15 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1402,6 +1750,15 @@ public class RNCWebViewManager extends SimpleViewManager { } } @@ -1001,7 +1008,7 @@ index f743bbc..a612d0f 100644 @Override public void onHostPause() { } -@@ -1447,6 +1796,13 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1447,6 +1804,13 @@ public class RNCWebViewManager extends SimpleViewManager { protected boolean nestedScrollEnabled = false; protected ProgressChangedFilter progressChangedFilter; @@ -1015,7 +1022,7 @@ index f743bbc..a612d0f 100644 /** * WebView must be created with an context of the current activity *

-@@ -1475,6 +1831,42 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1475,6 +1839,42 @@ public class RNCWebViewManager extends SimpleViewManager { this.nestedScrollEnabled = nestedScrollEnabled; } @@ -1058,7 +1065,7 @@ index f743bbc..a612d0f 100644 @Override public void onHostResume() { // do nothing -@@ -1533,6 +1925,8 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1533,6 +1933,8 @@ public class RNCWebViewManager extends SimpleViewManager { } } @@ -1067,7 +1074,7 @@ index f743bbc..a612d0f 100644 public @Nullable RNCWebViewClient getRNCWebViewClient() { return mRNCWebViewClient; -@@ -1609,8 +2003,8 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1609,8 +2011,8 @@ public class RNCWebViewManager extends SimpleViewManager { public void callInjectedJavaScriptBeforeContentLoaded() { if (getSettings().getJavaScriptEnabled() && @@ -1078,7 +1085,7 @@ index f743bbc..a612d0f 100644 evaluateJavascriptWithFallback("(function() {\n" + injectedJSBeforeContentLoaded + ";\n})();"); } } -@@ -1672,16 +2066,16 @@ public class RNCWebViewManager extends SimpleViewManager { +@@ -1672,16 +2074,16 @@ public class RNCWebViewManager extends SimpleViewManager { if (mOnScrollDispatchHelper.onScrollChanged(x, y)) { ScrollEvent event = ScrollEvent.obtain(