@exodus/react-native-webview 13.16.0-exodus.6 → 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.
@@ -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
- DecisionBlock pendingHandler = [self.decisionHandlers objectForKey:@(capturedIdentifier)];
45
- if (pendingHandler != nil) {
46
- RCTLogWarn(@"Navigation decision timeout for lock %ld, denying by default", (long)capturedIdentifier);
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
- DecisionBlock handler = [self.decisionHandlers objectForKey:@(lockIdentifier)];
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.6",
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",