@exodus/react-native-webview 13.16.0-exodus.5 → 13.16.0-exodus.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
package com.reactnativecommunity.webview;
|
|
2
2
|
|
|
3
|
-
import android.annotation.SuppressLint;
|
|
4
3
|
import android.graphics.Rect;
|
|
5
4
|
import android.net.Uri;
|
|
6
5
|
import android.text.TextUtils;
|
|
@@ -9,7 +8,6 @@ import android.view.Menu;
|
|
|
9
8
|
import android.view.MenuItem;
|
|
10
9
|
import android.view.MotionEvent;
|
|
11
10
|
import android.view.View;
|
|
12
|
-
import android.webkit.JavascriptInterface;
|
|
13
11
|
import android.webkit.ValueCallback;
|
|
14
12
|
import android.webkit.WebChromeClient;
|
|
15
13
|
import android.webkit.WebView;
|
|
@@ -55,8 +53,6 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
55
53
|
String injectedJSBeforeContentLoaded;
|
|
56
54
|
protected static final String JAVASCRIPT_INTERFACE = "ReactNativeWebView";
|
|
57
55
|
protected @Nullable
|
|
58
|
-
RNCWebViewBridge fallbackBridge;
|
|
59
|
-
protected @Nullable
|
|
60
56
|
WebViewCompat.WebMessageListener bridgeListener = null;
|
|
61
57
|
|
|
62
58
|
protected boolean messagingEnabled = false;
|
|
@@ -246,6 +242,15 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
246
242
|
this.bridgeListener = new WebViewCompat.WebMessageListener() {
|
|
247
243
|
@Override
|
|
248
244
|
public void onPostMessage(@NonNull WebView view, @NonNull WebMessageCompat message, @NonNull Uri sourceOrigin, boolean isMainFrame, @NonNull JavaScriptReplyProxy replyProxy) {
|
|
245
|
+
// Exodus: only accept messages from the top frame. The injected
|
|
246
|
+
// ReactNativeWebView object is available in every frame (subframes
|
|
247
|
+
// included), so without this guard any embedded iframe — even a
|
|
248
|
+
// cross-origin one that happens to pass the origin whitelist — could
|
|
249
|
+
// reach the native onMessage handler. This mirrors the iOS bridge,
|
|
250
|
+
// which is injected with forMainFrameOnly:YES.
|
|
251
|
+
if (!isMainFrame) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
249
254
|
RNCWebView.this.onMessage(message.getData(), sourceOrigin.toString());
|
|
250
255
|
}
|
|
251
256
|
};
|
|
@@ -257,10 +262,14 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
257
262
|
);
|
|
258
263
|
}
|
|
259
264
|
} else {
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
265
|
+
// Exodus: the legacy addJavascriptInterface bridge injects ReactNativeWebView
|
|
266
|
+
// into every frame and gives the native side no way to tell which frame a
|
|
267
|
+
// message came from, so it cannot enforce the top-frame restriction above.
|
|
268
|
+
// WEB_MESSAGE_LISTENER is supported on every WebView new enough to clear
|
|
269
|
+
// hardMinimumChromeVersion (100, see src/WebView.android.tsx), so this branch
|
|
270
|
+
// is unreachable in practice. Fail closed rather than install an unhardenable
|
|
271
|
+
// bridge.
|
|
272
|
+
FLog.w("RNCWebView", "WEB_MESSAGE_LISTENER is unsupported on this WebView; ReactNativeWebView messaging bridge not installed.");
|
|
264
273
|
}
|
|
265
274
|
injectJavascriptObject();
|
|
266
275
|
}
|
|
@@ -275,7 +284,6 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
275
284
|
}
|
|
276
285
|
}
|
|
277
286
|
|
|
278
|
-
@SuppressLint("AddJavascriptInterface")
|
|
279
287
|
public void setMessagingEnabled(boolean enabled) {
|
|
280
288
|
if (messagingEnabled == enabled) {
|
|
281
289
|
return;
|
|
@@ -423,30 +431,6 @@ public class RNCWebView extends WebView implements LifecycleEventListener {
|
|
|
423
431
|
return this.getThemedReactContext().getReactApplicationContext();
|
|
424
432
|
}
|
|
425
433
|
|
|
426
|
-
protected class RNCWebViewBridge {
|
|
427
|
-
private String TAG = "RNCWebViewBridge";
|
|
428
|
-
RNCWebView mWebView;
|
|
429
|
-
|
|
430
|
-
RNCWebViewBridge(RNCWebView c) {
|
|
431
|
-
mWebView = c;
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
/**
|
|
435
|
-
* This method is called whenever JavaScript running within the web view calls:
|
|
436
|
-
* - window[JAVASCRIPT_INTERFACE].postMessage
|
|
437
|
-
*/
|
|
438
|
-
@JavascriptInterface
|
|
439
|
-
public void postMessage(String message) {
|
|
440
|
-
if (mWebView.getMessagingEnabled()) {
|
|
441
|
-
// Post to main thread because `mWebView.getUrl()` requires to be executed on main.
|
|
442
|
-
mWebView.post(() -> mWebView.onMessage(message, mWebView.getUrl()));
|
|
443
|
-
} else {
|
|
444
|
-
FLog.w(TAG, "ReactNativeWebView.postMessage method was called but messaging is disabled. Pass an onMessage handler to the WebView.");
|
|
445
|
-
}
|
|
446
|
-
}
|
|
447
|
-
}
|
|
448
|
-
|
|
449
|
-
|
|
450
434
|
protected static class ProgressChangedFilter {
|
|
451
435
|
private boolean waitingForCommandLoadUrl = false;
|
|
452
436
|
|
|
@@ -3,11 +3,15 @@
|
|
|
3
3
|
/**
|
|
4
4
|
* Exodus: Thread-safe singleton that manages navigation decision handlers.
|
|
5
5
|
*
|
|
6
|
+
* All public methods use @synchronized for thread safety, and decision
|
|
7
|
+
* handlers are invoked outside the lock to avoid deadlocks
|
|
8
|
+
* (upstream react-native-webview#3916).
|
|
9
|
+
*
|
|
6
10
|
* Security improvements over upstream:
|
|
7
11
|
* - Uses NSInteger (64-bit) instead of int to prevent overflow
|
|
8
12
|
* - Adds collision checking to skip identifiers still in use
|
|
9
|
-
* - All public methods use @synchronized for thread safety
|
|
10
13
|
* - Explicitly copies blocks to heap to prevent use-after-free
|
|
14
|
+
* - Denies navigation by default if JS does not respond within 500ms
|
|
11
15
|
* - Provides cancelDecisionForLockIdentifier: for cleanup on WebView dealloc
|
|
12
16
|
*/
|
|
13
17
|
@implementation RNCWebViewDecisionManager
|
|
@@ -40,14 +44,17 @@
|
|
|
40
44
|
// if JS responded in time.
|
|
41
45
|
NSInteger capturedIdentifier = lockIdentifier;
|
|
42
46
|
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(500 * NSEC_PER_MSEC)), dispatch_get_main_queue(), ^{
|
|
47
|
+
DecisionBlock pendingHandler;
|
|
43
48
|
@synchronized (self) {
|
|
44
|
-
|
|
45
|
-
if (pendingHandler
|
|
46
|
-
|
|
47
|
-
pendingHandler(NO);
|
|
48
|
-
[self.decisionHandlers removeObjectForKey:@(capturedIdentifier)];
|
|
49
|
+
pendingHandler = [self.decisionHandlers objectForKey:@(capturedIdentifier)];
|
|
50
|
+
if (pendingHandler == nil) {
|
|
51
|
+
return;
|
|
49
52
|
}
|
|
53
|
+
[self.decisionHandlers removeObjectForKey:@(capturedIdentifier)];
|
|
50
54
|
}
|
|
55
|
+
// Invoke outside the lock, as in setResult:forLockIdentifier:.
|
|
56
|
+
RCTLogWarn(@"Navigation decision timeout for lock %ld, denying by default", (long)capturedIdentifier);
|
|
57
|
+
pendingHandler(NO);
|
|
51
58
|
});
|
|
52
59
|
|
|
53
60
|
return lockIdentifier;
|
|
@@ -55,15 +62,20 @@
|
|
|
55
62
|
}
|
|
56
63
|
|
|
57
64
|
- (void)setResult:(BOOL)shouldStart forLockIdentifier:(NSInteger)lockIdentifier {
|
|
65
|
+
// The handler is captured and removed under the lock, then invoked OUTSIDE
|
|
66
|
+
// it (upstream react-native-webview#3916). The handler hops to the main
|
|
67
|
+
// queue and can trigger another navigation that re-enters this class, so
|
|
68
|
+
// holding the lock across its invocation risks deadlock.
|
|
69
|
+
DecisionBlock handler;
|
|
58
70
|
@synchronized (self) {
|
|
59
|
-
|
|
71
|
+
handler = [self.decisionHandlers objectForKey:@(lockIdentifier)];
|
|
60
72
|
if (handler == nil) {
|
|
61
73
|
RCTLogWarn(@"Lock not found for identifier: %ld", (long)lockIdentifier);
|
|
62
74
|
return;
|
|
63
75
|
}
|
|
64
|
-
handler(shouldStart);
|
|
65
76
|
[self.decisionHandlers removeObjectForKey:@(lockIdentifier)];
|
|
66
77
|
}
|
|
78
|
+
handler(shouldStart);
|
|
67
79
|
}
|
|
68
80
|
|
|
69
81
|
|
package/package.json
CHANGED
|
@@ -10,7 +10,7 @@
|
|
|
10
10
|
"Thibault Malbranche <malbranche.thibault@gmail.com>"
|
|
11
11
|
],
|
|
12
12
|
"license": "MIT",
|
|
13
|
-
"version": "13.16.0-exodus.
|
|
13
|
+
"version": "13.16.0-exodus.7",
|
|
14
14
|
"homepage": "https://github.com/ExodusMovement/react-native-webview#readme",
|
|
15
15
|
"scripts": {
|
|
16
16
|
"android": "react-native run-android",
|