@exodus/react-native-webview 11.26.1-exodus.2 → 11.26.1-exodus.21

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,16 +1,15 @@
1
1
  import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
2
- import { Image, View, NativeModules, } from 'react-native';
2
+ import { Text, View, NativeModules, Platform, } from 'react-native';
3
3
  import invariant from 'invariant';
4
4
  // @ts-expect-error react-native doesn't have this type
5
5
  import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands';
6
6
  import RNCWebView from "./WebViewNativeComponent.ios";
7
- import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, } from './WebViewShared';
7
+ import { defaultOriginWhitelist, defaultDeeplinkWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, versionPasses, } from './WebViewShared';
8
8
  import styles from './WebView.styles';
9
9
  const codegenNativeCommands = codegenNativeCommandsUntyped;
10
10
  const Commands = codegenNativeCommands({
11
11
  supportedCommands: ['goBack', 'goForward', 'reload', 'stopLoading', /* 'injectJavaScript', */ 'requestFocus', 'postMessage', 'loadUrl'],
12
12
  });
13
- const { resolveAssetSource } = Image;
14
13
  const processDecelerationRate = (decelerationRate) => {
15
14
  let newDecelerationRate = decelerationRate;
16
15
  if (newDecelerationRate === 'normal') {
@@ -32,57 +31,63 @@ const useWarnIfChanges = (value, name) => {
32
31
  /**
33
32
  * Harcoded defaults for security.
34
33
  */
35
- const allowFileAccessFromFileURLs = false;
36
- const allowUniversalAccessFromFileURLs = false;
37
- const injectedJavaScriptForMainFrameOnly = true;
38
- const injectedJavaScriptBeforeContentLoadedForMainFrameOnly = true;
39
34
  const mediaPlaybackRequiresUserAction = true;
40
35
  // iOS only configs
41
36
  const allowsInlineMediaPlayback = true;
42
- const allowsAirPlayForMediaPlayback = false;
43
37
  const useSharedProcessPool = false;
44
38
  const sharedCookiesEnabled = false;
45
39
  const enableApplePay = false;
46
- const onFileDownload = () => console.error('tried to download file');
47
40
  const dataDetectorTypes = 'none';
48
- const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled = true, originWhitelist = defaultOriginWhitelist, textInteractionEnabled = true, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, startInLoadingState, onNavigationStateChange, onLoadStart, onError, onLoad, onLoadEnd, onLoadProgress, onContentProcessDidTerminate: onContentProcessDidTerminateProp, onHttpError: onHttpErrorProp, onMessage: onMessageProp, renderLoading, renderError, style, containerStyle, source, incognito, decelerationRate: decelerationRateProp, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, ...otherProps }, ref) => {
41
+ const hardMinimumIOSVersion = '12.5.6 <13, 13.6.1 <14, 14.8.1 <15, 15.7.1';
42
+ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled = true, originWhitelist = defaultOriginWhitelist, deeplinkWhitelist = defaultDeeplinkWhitelist, textInteractionEnabled = true, injectedJavaScript, injectedJavaScriptBeforeContentLoaded, startInLoadingState, onLoadStart, onError, onLoad, onLoadEnd, onMessage: onMessageProp, renderLoading, renderError, style, containerStyle, source, incognito, validateMeta, validateData, decelerationRate: decelerationRateProp, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, minimumIOSVersion, unsupportedVersionComponent: UnsupportedVersionComponent, ...otherProps }, ref) => {
49
43
  const webViewRef = useRef(null);
50
44
  const onShouldStartLoadWithRequestCallback = useCallback((shouldStart, _url, lockIdentifier = 0) => {
51
45
  const viewManager = RNCWebViewManager;
52
46
  viewManager.startLoadWithResult(!!shouldStart, lockIdentifier);
53
47
  }, []);
54
- const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onHttpError, onLoadingError, onLoadingFinish, onLoadingProgress, onContentProcessDidTerminate } = useWebWiewLogic({
55
- onNavigationStateChange,
48
+ const { onLoadingStart, onShouldStartLoadWithRequest, onMessage, viewState, setViewState, lastErrorEvent, onLoadingError, onLoadingFinish, onLoadingProgress } = useWebWiewLogic({
56
49
  onLoad,
57
50
  onError,
58
- onHttpErrorProp,
59
51
  onLoadEnd,
60
- onLoadProgress,
61
52
  onLoadStart,
62
53
  onMessageProp,
63
54
  startInLoadingState,
64
55
  originWhitelist,
56
+ deeplinkWhitelist,
65
57
  onShouldStartLoadWithRequestProp,
66
58
  onShouldStartLoadWithRequestCallback,
67
- onContentProcessDidTerminateProp,
59
+ validateMeta,
60
+ validateData,
68
61
  });
69
62
  useImperativeHandle(ref, () => ({
70
- goForward: () => Commands.goForward(webViewRef.current),
71
- goBack: () => Commands.goBack(webViewRef.current),
63
+ goForward: () => webViewRef.current && Commands.goForward(webViewRef.current),
64
+ goBack: () => webViewRef.current && Commands.goBack(webViewRef.current),
72
65
  reload: () => {
73
66
  setViewState('LOADING');
74
- Commands.reload(webViewRef.current);
67
+ if (webViewRef.current) {
68
+ Commands.reload(webViewRef.current);
69
+ }
75
70
  },
76
- stopLoading: () => Commands.stopLoading(webViewRef.current),
77
- postMessage: (data) => Commands.postMessage(webViewRef.current, data),
71
+ stopLoading: () => webViewRef.current && Commands.stopLoading(webViewRef.current),
72
+ postMessage: (data) => webViewRef.current && Commands.postMessage(webViewRef.current, data),
78
73
  // injectJavaScript: (data: string) => Commands.injectJavaScript(webViewRef.current, data),
79
- requestFocus: () => Commands.requestFocus(webViewRef.current),
74
+ requestFocus: () => webViewRef.current && Commands.requestFocus(webViewRef.current),
80
75
  }), [setViewState, webViewRef]);
81
76
  useWarnIfChanges(allowsInlineMediaPlayback, 'allowsInlineMediaPlayback');
82
- useWarnIfChanges(allowsAirPlayForMediaPlayback, 'allowsAirPlayForMediaPlayback');
83
77
  useWarnIfChanges(incognito, 'incognito');
84
78
  useWarnIfChanges(mediaPlaybackRequiresUserAction, 'mediaPlaybackRequiresUserAction');
85
79
  useWarnIfChanges(dataDetectorTypes, 'dataDetectorTypes');
80
+ const version = String(Platform.Version);
81
+ if (!(versionPasses(version, minimumIOSVersion) && versionPasses(version, hardMinimumIOSVersion))) {
82
+ if (UnsupportedVersionComponent) {
83
+ return <UnsupportedVersionComponent />;
84
+ }
85
+ return (<View style={{ alignSelf: 'flex-start' }}>
86
+ <Text style={{ color: 'red' }}>
87
+ iOS version is outdated and insecure. Update it to continue.
88
+ </Text>
89
+ </View>);
90
+ }
86
91
  let otherView = null;
87
92
  if (viewState === 'LOADING') {
88
93
  otherView = (renderLoading || defaultRenderLoading)();
@@ -98,9 +103,9 @@ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled =
98
103
  const webViewContainerStyle = [styles.container, containerStyle];
99
104
  const decelerationRate = processDecelerationRate(decelerationRateProp);
100
105
  const NativeWebView = RNCWebView;
101
- const webView = (<NativeWebView key="webViewKey" {...otherProps} allowFileAccessFromFileURLs={allowFileAccessFromFileURLs} allowUniversalAccessFromFileURLs={allowUniversalAccessFromFileURLs} enableApplePay={enableApplePay} javaScriptEnabled={javaScriptEnabled} cacheEnabled={cacheEnabled} dataDetectorTypes={dataDetectorTypes} useSharedProcessPool={useSharedProcessPool} textInteractionEnabled={textInteractionEnabled} decelerationRate={decelerationRate} messagingEnabled={typeof onMessageProp === 'function'} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onFileDownload={onFileDownload} onLoadingStart={onLoadingStart} onHttpError={onHttpError} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} onContentProcessDidTerminate={onContentProcessDidTerminate} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} injectedJavaScriptForMainFrameOnly={injectedJavaScriptForMainFrameOnly} injectedJavaScriptBeforeContentLoadedForMainFrameOnly={injectedJavaScriptBeforeContentLoadedForMainFrameOnly} allowsAirPlayForMediaPlayback={allowsAirPlayForMediaPlayback} allowsInlineMediaPlayback={allowsInlineMediaPlayback} incognito={incognito} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction} ref={webViewRef} sharedCookiesEnabled={sharedCookiesEnabled}
106
+ const webView = (<NativeWebView key="webViewKey" {...otherProps} enableApplePay={enableApplePay} javaScriptEnabled={javaScriptEnabled} cacheEnabled={cacheEnabled} dataDetectorTypes={dataDetectorTypes} useSharedProcessPool={useSharedProcessPool} textInteractionEnabled={textInteractionEnabled} decelerationRate={decelerationRate} messagingEnabled={typeof onMessageProp === 'function'} onLoadingError={onLoadingError} onLoadingFinish={onLoadingFinish} onLoadingProgress={onLoadingProgress} onLoadingStart={onLoadingStart} onMessage={onMessage} onShouldStartLoadWithRequest={onShouldStartLoadWithRequest} injectedJavaScript={injectedJavaScript} injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded} allowsInlineMediaPlayback={allowsInlineMediaPlayback} incognito={incognito} mediaPlaybackRequiresUserAction={mediaPlaybackRequiresUserAction} ref={webViewRef} sharedCookiesEnabled={sharedCookiesEnabled}
102
107
  // TODO: find a better way to type this.
103
- source={resolveAssetSource(source)} style={webViewStyles}/>);
108
+ source={source} style={webViewStyles}/>);
104
109
  return (<View style={webViewContainerStyle}>
105
110
  {webView}
106
111
  {otherView}
@@ -1,37 +1,37 @@
1
1
  import React from 'react';
2
- import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent, WebViewHttpErrorEvent, WebViewMessageEvent, WebViewNavigation, WebViewNavigationEvent, WebViewProgressEvent, WebViewRenderProcessGoneEvent, WebViewTerminatedEvent } from './WebViewTypes';
3
- declare const defaultOriginWhitelist: readonly ["http://*", "https://*"];
4
- declare const createOnShouldStartLoadWithRequest: (loadRequest: (shouldStart: boolean, url: string, lockIdentifier: number) => void, originWhitelist: readonly string[], onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest | undefined) => ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
2
+ import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent, WebViewMessageEvent, WebViewMessage, WebViewNavigationEvent, WebViewOpenWindowEvent, WebViewProgressEvent, WebViewNativeEvent } from './WebViewTypes';
3
+ declare const defaultOriginWhitelist: readonly ["https://*"];
4
+ declare const defaultDeeplinkWhitelist: readonly ["https://"];
5
+ declare const createOnShouldStartLoadWithRequest: (loadRequest: (shouldStart: boolean, url: string, lockIdentifier: number) => void, originWhitelist: readonly string[], deepLinkWhitelist: readonly string[], onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest | undefined) => ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
5
6
  declare const defaultRenderLoading: () => JSX.Element;
6
7
  declare const defaultRenderError: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => JSX.Element;
7
- export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
8
- export declare const useWebWiewLogic: ({ startInLoadingState, onNavigationStateChange, onLoadStart, onLoad, onLoadProgress, onLoadEnd, onError, onHttpErrorProp, onMessageProp, onRenderProcessGoneProp, onContentProcessDidTerminateProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, }: {
8
+ export { defaultOriginWhitelist, defaultDeeplinkWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
9
+ export declare const useWebWiewLogic: ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }: {
9
10
  startInLoadingState?: boolean | undefined;
10
- onNavigationStateChange?: ((event: WebViewNavigation) => void) | undefined;
11
11
  onLoadStart?: ((event: WebViewNavigationEvent) => void) | undefined;
12
12
  onLoad?: ((event: WebViewNavigationEvent) => void) | undefined;
13
- onLoadProgress?: ((event: WebViewProgressEvent) => void) | undefined;
14
13
  onLoadEnd?: ((event: WebViewNavigationEvent | WebViewErrorEvent) => void) | undefined;
15
14
  onError?: ((event: WebViewErrorEvent) => void) | undefined;
16
- onHttpErrorProp?: ((event: WebViewHttpErrorEvent) => void) | undefined;
17
- onMessageProp?: ((event: WebViewMessageEvent) => void) | undefined;
18
- onRenderProcessGoneProp?: ((event: WebViewRenderProcessGoneEvent) => void) | undefined;
19
- onContentProcessDidTerminateProp?: ((event: WebViewTerminatedEvent) => void) | undefined;
15
+ onMessageProp?: ((event: WebViewMessage) => void) | undefined;
16
+ onOpenWindowProp?: ((event: WebViewOpenWindowEvent) => void) | undefined;
20
17
  originWhitelist: readonly string[];
18
+ deeplinkWhitelist: readonly string[];
21
19
  onShouldStartLoadWithRequestProp?: OnShouldStartLoadWithRequest | undefined;
22
20
  onShouldStartLoadWithRequestCallback: (shouldStart: boolean, url: string, lockIdentifier?: number | undefined) => void;
21
+ validateMeta: (event: WebViewNativeEvent) => WebViewNativeEvent;
22
+ validateData: (data: object) => object;
23
23
  }) => {
24
24
  onShouldStartLoadWithRequest: ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
25
25
  onLoadingStart: (event: WebViewNavigationEvent) => void;
26
26
  onLoadingProgress: (event: WebViewProgressEvent) => void;
27
27
  onLoadingError: (event: WebViewErrorEvent) => void;
28
28
  onLoadingFinish: (event: WebViewNavigationEvent) => void;
29
- onHttpError: (event: WebViewHttpErrorEvent) => void;
30
- onRenderProcessGone: (event: WebViewRenderProcessGoneEvent) => void;
31
- onContentProcessDidTerminate: (event: WebViewTerminatedEvent) => void;
32
29
  onMessage: (event: WebViewMessageEvent) => void;
30
+ onOpenWindow: (event: WebViewOpenWindowEvent) => void;
31
+ passesWhitelist: (url: string) => boolean | null;
33
32
  viewState: "IDLE" | "LOADING" | "ERROR";
34
33
  setViewState: React.Dispatch<React.SetStateAction<"IDLE" | "LOADING" | "ERROR">>;
35
34
  lastErrorEvent: WebViewError | null;
36
35
  };
36
+ export declare const versionPasses: (version: string | undefined, minimum: string | undefined) => boolean;
37
37
  //# sourceMappingURL=WebViewShared.d.ts.map
@@ -2,31 +2,58 @@ import escapeStringRegexp from 'escape-string-regexp';
2
2
  import React, { useCallback, useMemo, useRef, useState } from 'react';
3
3
  import { Linking, View, ActivityIndicator, Text, Platform } from 'react-native';
4
4
  import styles from './WebView.styles';
5
- const defaultOriginWhitelist = ['http://*', 'https://*'];
5
+ const defaultOriginWhitelist = ['https://*'];
6
+ const defaultDeeplinkWhitelist = ['https://'];
7
+ const defaultDeeplinkBlocklist = [/^http:/i, /^file:/i, /^javascript:/i];
6
8
  const extractOrigin = (url) => {
7
9
  const result = /^[A-Za-z][A-Za-z0-9+\-.]+:(\/\/)?[^/]*/.exec(url);
8
10
  return result === null ? '' : result[0];
9
11
  };
10
- const originWhitelistToRegex = (originWhitelist) => `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}`;
11
- const passesWhitelist = (compiledWhitelist, url) => {
12
+ const stringWhitelistToRegex = (originWhitelist) => new RegExp(`^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}$`);
13
+ const matchWithRegexList = (compiledRegexList, value) => {
14
+ return compiledRegexList.some(x => x.test(value));
15
+ };
16
+ const matchWithPrefixStringList = (prefixes, value) => {
17
+ if (typeof value !== 'string')
18
+ throw new Error(`value was not a string`);
19
+ return prefixes.some(x => String(x).length && String.prototype.startsWith.call(value, x));
20
+ };
21
+ const _passesWhitelist = (compiledWhitelist, url) => {
12
22
  const origin = extractOrigin(url);
13
- return compiledWhitelist.some(x => new RegExp(x).test(origin));
23
+ if (!origin)
24
+ return false;
25
+ if (origin !== new URL(url).origin)
26
+ return null;
27
+ return matchWithRegexList(compiledWhitelist, origin);
14
28
  };
15
- const compileWhitelist = (originWhitelist) => ['about:blank', ...(originWhitelist || [])].map(originWhitelistToRegex);
16
- const createOnShouldStartLoadWithRequest = (loadRequest, originWhitelist, onShouldStartLoadWithRequest) => {
29
+ const compileWhitelist = (originWhitelist) => ['about:blank', ...(originWhitelist || [])].map(stringWhitelistToRegex);
30
+ const createOnShouldStartLoadWithRequest = (loadRequest, originWhitelist, deepLinkWhitelist, onShouldStartLoadWithRequest) => {
31
+ const compiledWhiteList = compileWhitelist(originWhitelist);
17
32
  return ({ nativeEvent }) => {
18
33
  let shouldStart = true;
19
- const { url, lockIdentifier } = nativeEvent;
20
- if (!passesWhitelist(compileWhitelist(originWhitelist), url)) {
21
- Linking.canOpenURL(url).then((supported) => {
22
- if (supported) {
23
- return Linking.openURL(url);
34
+ const { url, lockIdentifier, isTopFrame } = nativeEvent;
35
+ /** Check if the url passes the origin whitelist */
36
+ if (!_passesWhitelist(compiledWhiteList, url)) {
37
+ /** Check if the url passes the hardcoded deeplink blocklist */
38
+ const foundMatchInBlocklist = matchWithRegexList(defaultDeeplinkBlocklist, url);
39
+ if (!foundMatchInBlocklist) {
40
+ /** Check if the url passes the dynamic deeplink allow list */
41
+ const foundMatchInAllowlist = matchWithPrefixStringList(deepLinkWhitelist, url);
42
+ if (foundMatchInAllowlist) {
43
+ Linking.canOpenURL(url).then((supported) => {
44
+ if (supported && isTopFrame) {
45
+ return Linking.openURL(url);
46
+ }
47
+ console.warn(`Can't open url: ${url}`);
48
+ return undefined;
49
+ }).catch(e => {
50
+ console.warn('Error opening URL: ', e);
51
+ });
52
+ }
53
+ else {
54
+ console.warn(`Failed to pass default block list or whitelist deep link url: ${url}`);
24
55
  }
25
- console.warn(`Can't open url: ${url}`);
26
- return undefined;
27
- }).catch(e => {
28
- console.warn('Error opening URL: ', e);
29
- });
56
+ }
30
57
  shouldStart = false;
31
58
  }
32
59
  else if (onShouldStartLoadWithRequest) {
@@ -44,21 +71,31 @@ const defaultRenderError = (errorDomain, errorCode, errorDesc) => (<View style={
44
71
  <Text style={styles.errorText}>{`Error Code: ${errorCode}`}</Text>
45
72
  <Text style={styles.errorText}>{`Description: ${errorDesc}`}</Text>
46
73
  </View>);
47
- export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
48
- export const useWebWiewLogic = ({ startInLoadingState, onNavigationStateChange, onLoadStart, onLoad, onLoadProgress, onLoadEnd, onError, onHttpErrorProp, onMessageProp, onRenderProcessGoneProp, onContentProcessDidTerminateProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, }) => {
74
+ export { defaultOriginWhitelist, defaultDeeplinkWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
75
+ export const useWebWiewLogic = ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }) => {
49
76
  const [viewState, setViewState] = useState(startInLoadingState ? "LOADING" : "IDLE");
50
77
  const [lastErrorEvent, setLastErrorEvent] = useState(null);
51
78
  const startUrl = useRef(null);
52
- const updateNavigationState = useCallback((event) => {
53
- onNavigationStateChange === null || onNavigationStateChange === void 0 ? void 0 : onNavigationStateChange(event.nativeEvent);
54
- }, [onNavigationStateChange]);
79
+ const passesWhitelist = (url) => {
80
+ if (!url || typeof url !== 'string')
81
+ return false;
82
+ return _passesWhitelist(compileWhitelist(originWhitelist), url);
83
+ };
84
+ const passesWhitelistUse = useCallback(passesWhitelist, [originWhitelist]);
85
+ const extractMeta = (nativeEvent) => ({
86
+ url: String(nativeEvent.url),
87
+ loading: Boolean(nativeEvent.loading),
88
+ title: String(nativeEvent.title),
89
+ canGoBack: Boolean(nativeEvent.canGoBack),
90
+ canGoForward: Boolean(nativeEvent.canGoForward),
91
+ lockIdentifier: Number(nativeEvent.lockIdentifier),
92
+ });
55
93
  const onLoadingStart = useCallback((event) => {
56
94
  // Needed for android
57
95
  startUrl.current = event.nativeEvent.url;
58
96
  // !Needed for android
59
97
  onLoadStart === null || onLoadStart === void 0 ? void 0 : onLoadStart(event);
60
- updateNavigationState(event);
61
- }, [onLoadStart, updateNavigationState]);
98
+ }, [onLoadStart]);
62
99
  const onLoadingError = useCallback((event) => {
63
100
  event.persist();
64
101
  if (onError) {
@@ -75,55 +112,92 @@ export const useWebWiewLogic = ({ startInLoadingState, onNavigationStateChange,
75
112
  setViewState('ERROR');
76
113
  setLastErrorEvent(event.nativeEvent);
77
114
  }, [onError, onLoadEnd]);
78
- const onHttpError = useCallback((event) => {
79
- onHttpErrorProp === null || onHttpErrorProp === void 0 ? void 0 : onHttpErrorProp(event);
80
- }, [onHttpErrorProp]);
81
- // Android Only
82
- const onRenderProcessGone = useCallback((event) => {
83
- onRenderProcessGoneProp === null || onRenderProcessGoneProp === void 0 ? void 0 : onRenderProcessGoneProp(event);
84
- }, [onRenderProcessGoneProp]);
85
- // !Android Only
86
- // iOS Only
87
- const onContentProcessDidTerminate = useCallback((event) => {
88
- onContentProcessDidTerminateProp === null || onContentProcessDidTerminateProp === void 0 ? void 0 : onContentProcessDidTerminateProp(event);
89
- }, [onContentProcessDidTerminateProp]);
90
- // !iOS Only
91
115
  const onLoadingFinish = useCallback((event) => {
92
116
  onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
93
117
  onLoadEnd === null || onLoadEnd === void 0 ? void 0 : onLoadEnd(event);
94
118
  const { nativeEvent: { url } } = event;
119
+ if (!passesWhitelistUse(url))
120
+ return;
95
121
  // on Android, only if url === startUrl
96
122
  if (Platform.OS !== "android" || url === startUrl.current) {
97
123
  setViewState('IDLE');
98
124
  }
99
125
  // !on Android, only if url === startUrl
100
- updateNavigationState(event);
101
- }, [onLoad, onLoadEnd, updateNavigationState]);
126
+ // REMOVED: updateNavigationState(event);
127
+ }, [onLoad, onLoadEnd, passesWhitelistUse]);
102
128
  const onMessage = useCallback((event) => {
103
- onMessageProp === null || onMessageProp === void 0 ? void 0 : onMessageProp(event);
104
- }, [onMessageProp]);
129
+ const { nativeEvent } = event;
130
+ if (!passesWhitelistUse(nativeEvent.url))
131
+ return;
132
+ // TODO: can/should we perform any other validation?
133
+ const data = JSON.stringify(validateData(JSON.parse(nativeEvent.data)));
134
+ const meta = validateMeta(extractMeta(nativeEvent));
135
+ onMessageProp === null || onMessageProp === void 0 ? void 0 : onMessageProp({ ...meta, data });
136
+ }, [onMessageProp, passesWhitelistUse, validateData, validateMeta]);
105
137
  const onLoadingProgress = useCallback((event) => {
106
138
  const { nativeEvent: { progress } } = event;
139
+ if (!passesWhitelistUse(event.nativeEvent.url))
140
+ return;
107
141
  // patch for Android only
108
142
  if (Platform.OS === "android" && progress === 1) {
109
143
  setViewState(prevViewState => prevViewState === 'LOADING' ? 'IDLE' : prevViewState);
110
144
  }
111
145
  // !patch for Android only
112
- onLoadProgress === null || onLoadProgress === void 0 ? void 0 : onLoadProgress(event);
113
- }, [onLoadProgress]);
114
- const onShouldStartLoadWithRequest = useMemo(() => createOnShouldStartLoadWithRequest(onShouldStartLoadWithRequestCallback, originWhitelist, onShouldStartLoadWithRequestProp), [originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback]);
146
+ // REMOVED: onLoadProgress?.(event);
147
+ }, [passesWhitelistUse]);
148
+ const onShouldStartLoadWithRequest = useMemo(() => createOnShouldStartLoadWithRequest(onShouldStartLoadWithRequestCallback, originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp), [originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback]);
149
+ // Android Only
150
+ const onOpenWindow = useCallback((event) => {
151
+ onOpenWindowProp === null || onOpenWindowProp === void 0 ? void 0 : onOpenWindowProp(event);
152
+ }, [onOpenWindowProp]);
153
+ // !Android Only
115
154
  return {
116
155
  onShouldStartLoadWithRequest,
117
156
  onLoadingStart,
118
157
  onLoadingProgress,
119
158
  onLoadingError,
120
159
  onLoadingFinish,
121
- onHttpError,
122
- onRenderProcessGone,
123
- onContentProcessDidTerminate,
124
160
  onMessage,
161
+ onOpenWindow,
162
+ passesWhitelist,
125
163
  viewState,
126
164
  setViewState,
127
165
  lastErrorEvent,
128
166
  };
129
167
  };
168
+ export const versionPasses = (version, minimum) => {
169
+ if (!version || !minimum)
170
+ return false;
171
+ if (typeof version !== 'string' || typeof minimum !== 'string')
172
+ return false;
173
+ if (minimum.includes(', ')) {
174
+ // We have a set of possible versions
175
+ const variants = minimum.split(', ');
176
+ // Every entry but the last one should be with an upper bound
177
+ if (!variants.slice(0, -1).every(x => x.includes(' <')))
178
+ return false;
179
+ return variants.some(x => versionPasses(version, x)); // Any match passes
180
+ }
181
+ if (minimum.includes(' <')) {
182
+ const [min, max, ...rest] = minimum.split(' <');
183
+ if (rest.length > 0)
184
+ return false;
185
+ // Last check is required for correctness/formatting validation
186
+ return versionPasses(version, min) && !versionPasses(version, max) && versionPasses(max, version);
187
+ }
188
+ const versionRegex = /^[0-9]+(\.[0-9]+)*$/;
189
+ if (!versionRegex.test(version) || !versionRegex.test(minimum))
190
+ return false;
191
+ const versionParts = version.split('.').map(Number);
192
+ const minimumParts = minimum.split('.').map(Number);
193
+ const len = Math.max(versionParts.length, minimumParts.length);
194
+ for (let i = 0; i < len; i += 1) {
195
+ const ver = versionParts[i] || 0;
196
+ const min = minimumParts[i] || 0;
197
+ if (ver > min)
198
+ return true;
199
+ if (ver < min)
200
+ return false;
201
+ }
202
+ return true; // equals
203
+ };