@exodus/react-native-webview 11.26.1-exodus.2 → 11.26.1-exodus.20
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.
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewManager.java +123 -269
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewModule.java +1 -45
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.java +25 -0
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewUtils.java +51 -0
- package/android/src/main/java/com/reactnativecommunity/webview/events/{TopHttpErrorEvent.kt → TopNewWindowEvent.kt} +5 -5
- package/apple/RNCWebView.h +1 -8
- package/apple/RNCWebView.m +34 -123
- package/apple/RNCWebViewManager.m +1 -10
- package/index.js +5 -2
- package/lib/WebView.android.js +52 -27
- package/lib/WebView.ios.js +28 -24
- package/lib/WebViewShared.d.ts +10 -12
- package/lib/WebViewShared.js +85 -34
- package/lib/WebViewTypes.d.ts +38 -155
- package/package.json +1 -1
- package/android/src/main/java/com/reactnativecommunity/webview/RNCWebViewPackage.kt +0 -15
- package/android/src/main/java/com/reactnativecommunity/webview/events/TopRenderProcessGoneEvent.kt +0 -26
package/lib/WebView.ios.js
CHANGED
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import React, { forwardRef, useCallback, useImperativeHandle, useRef } from 'react';
|
|
2
|
-
import {
|
|
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, 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,62 @@ 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
|
|
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, 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,
|
|
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,
|
|
65
56
|
onShouldStartLoadWithRequestProp,
|
|
66
57
|
onShouldStartLoadWithRequestCallback,
|
|
67
|
-
|
|
58
|
+
validateMeta,
|
|
59
|
+
validateData,
|
|
68
60
|
});
|
|
69
61
|
useImperativeHandle(ref, () => ({
|
|
70
|
-
goForward: () => Commands.goForward(webViewRef.current),
|
|
71
|
-
goBack: () => Commands.goBack(webViewRef.current),
|
|
62
|
+
goForward: () => webViewRef.current && Commands.goForward(webViewRef.current),
|
|
63
|
+
goBack: () => webViewRef.current && Commands.goBack(webViewRef.current),
|
|
72
64
|
reload: () => {
|
|
73
65
|
setViewState('LOADING');
|
|
74
|
-
|
|
66
|
+
if (webViewRef.current) {
|
|
67
|
+
Commands.reload(webViewRef.current);
|
|
68
|
+
}
|
|
75
69
|
},
|
|
76
|
-
stopLoading: () => Commands.stopLoading(webViewRef.current),
|
|
77
|
-
postMessage: (data) => Commands.postMessage(webViewRef.current, data),
|
|
70
|
+
stopLoading: () => webViewRef.current && Commands.stopLoading(webViewRef.current),
|
|
71
|
+
postMessage: (data) => webViewRef.current && Commands.postMessage(webViewRef.current, data),
|
|
78
72
|
// injectJavaScript: (data: string) => Commands.injectJavaScript(webViewRef.current, data),
|
|
79
|
-
requestFocus: () => Commands.requestFocus(webViewRef.current),
|
|
73
|
+
requestFocus: () => webViewRef.current && Commands.requestFocus(webViewRef.current),
|
|
80
74
|
}), [setViewState, webViewRef]);
|
|
81
75
|
useWarnIfChanges(allowsInlineMediaPlayback, 'allowsInlineMediaPlayback');
|
|
82
|
-
useWarnIfChanges(allowsAirPlayForMediaPlayback, 'allowsAirPlayForMediaPlayback');
|
|
83
76
|
useWarnIfChanges(incognito, 'incognito');
|
|
84
77
|
useWarnIfChanges(mediaPlaybackRequiresUserAction, 'mediaPlaybackRequiresUserAction');
|
|
85
78
|
useWarnIfChanges(dataDetectorTypes, 'dataDetectorTypes');
|
|
79
|
+
const version = String(Platform.Version);
|
|
80
|
+
if (!(versionPasses(version, minimumIOSVersion) && versionPasses(version, hardMinimumIOSVersion))) {
|
|
81
|
+
if (UnsupportedVersionComponent) {
|
|
82
|
+
return <UnsupportedVersionComponent />;
|
|
83
|
+
}
|
|
84
|
+
return (<View style={{ alignSelf: 'flex-start' }}>
|
|
85
|
+
<Text style={{ color: 'red' }}>
|
|
86
|
+
iOS version is outdated and insecure. Update it to continue.
|
|
87
|
+
</Text>
|
|
88
|
+
</View>);
|
|
89
|
+
}
|
|
86
90
|
let otherView = null;
|
|
87
91
|
if (viewState === 'LOADING') {
|
|
88
92
|
otherView = (renderLoading || defaultRenderLoading)();
|
|
@@ -98,9 +102,9 @@ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled =
|
|
|
98
102
|
const webViewContainerStyle = [styles.container, containerStyle];
|
|
99
103
|
const decelerationRate = processDecelerationRate(decelerationRateProp);
|
|
100
104
|
const NativeWebView = RNCWebView;
|
|
101
|
-
const webView = (<NativeWebView key="webViewKey" {...otherProps}
|
|
105
|
+
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
106
|
// TODO: find a better way to type this.
|
|
103
|
-
source={
|
|
107
|
+
source={source} style={webViewStyles}/>);
|
|
104
108
|
return (<View style={webViewContainerStyle}>
|
|
105
109
|
{webView}
|
|
106
110
|
{otherView}
|
package/lib/WebViewShared.d.ts
CHANGED
|
@@ -1,37 +1,35 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent,
|
|
3
|
-
declare const defaultOriginWhitelist: readonly ["
|
|
2
|
+
import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent, WebViewMessageEvent, WebViewMessage, WebViewNavigationEvent, WebViewOpenWindowEvent, WebViewProgressEvent, WebViewNativeEvent } from './WebViewTypes';
|
|
3
|
+
declare const defaultOriginWhitelist: readonly ["https://*"];
|
|
4
4
|
declare const createOnShouldStartLoadWithRequest: (loadRequest: (shouldStart: boolean, url: string, lockIdentifier: number) => void, originWhitelist: readonly string[], onShouldStartLoadWithRequest?: OnShouldStartLoadWithRequest | undefined) => ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
|
|
5
5
|
declare const defaultRenderLoading: () => JSX.Element;
|
|
6
6
|
declare const defaultRenderError: (errorDomain: string | undefined, errorCode: number, errorDesc: string) => JSX.Element;
|
|
7
7
|
export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
|
|
8
|
-
export declare const useWebWiewLogic: ({ startInLoadingState,
|
|
8
|
+
export declare const useWebWiewLogic: ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }: {
|
|
9
9
|
startInLoadingState?: boolean | undefined;
|
|
10
|
-
onNavigationStateChange?: ((event: WebViewNavigation) => void) | undefined;
|
|
11
10
|
onLoadStart?: ((event: WebViewNavigationEvent) => void) | undefined;
|
|
12
11
|
onLoad?: ((event: WebViewNavigationEvent) => void) | undefined;
|
|
13
|
-
onLoadProgress?: ((event: WebViewProgressEvent) => void) | undefined;
|
|
14
12
|
onLoadEnd?: ((event: WebViewNavigationEvent | WebViewErrorEvent) => void) | undefined;
|
|
15
13
|
onError?: ((event: WebViewErrorEvent) => void) | undefined;
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
onRenderProcessGoneProp?: ((event: WebViewRenderProcessGoneEvent) => void) | undefined;
|
|
19
|
-
onContentProcessDidTerminateProp?: ((event: WebViewTerminatedEvent) => void) | undefined;
|
|
14
|
+
onMessageProp?: ((event: WebViewMessage) => void) | undefined;
|
|
15
|
+
onOpenWindowProp?: ((event: WebViewOpenWindowEvent) => void) | undefined;
|
|
20
16
|
originWhitelist: readonly string[];
|
|
21
17
|
onShouldStartLoadWithRequestProp?: OnShouldStartLoadWithRequest | undefined;
|
|
22
18
|
onShouldStartLoadWithRequestCallback: (shouldStart: boolean, url: string, lockIdentifier?: number | undefined) => void;
|
|
19
|
+
validateMeta: (event: WebViewNativeEvent) => WebViewNativeEvent;
|
|
20
|
+
validateData: (data: object) => object;
|
|
23
21
|
}) => {
|
|
24
22
|
onShouldStartLoadWithRequest: ({ nativeEvent }: ShouldStartLoadRequestEvent) => void;
|
|
25
23
|
onLoadingStart: (event: WebViewNavigationEvent) => void;
|
|
26
24
|
onLoadingProgress: (event: WebViewProgressEvent) => void;
|
|
27
25
|
onLoadingError: (event: WebViewErrorEvent) => void;
|
|
28
26
|
onLoadingFinish: (event: WebViewNavigationEvent) => void;
|
|
29
|
-
onHttpError: (event: WebViewHttpErrorEvent) => void;
|
|
30
|
-
onRenderProcessGone: (event: WebViewRenderProcessGoneEvent) => void;
|
|
31
|
-
onContentProcessDidTerminate: (event: WebViewTerminatedEvent) => void;
|
|
32
27
|
onMessage: (event: WebViewMessageEvent) => void;
|
|
28
|
+
onOpenWindow: (event: WebViewOpenWindowEvent) => void;
|
|
29
|
+
passesWhitelist: (url: string) => boolean | null;
|
|
33
30
|
viewState: "IDLE" | "LOADING" | "ERROR";
|
|
34
31
|
setViewState: React.Dispatch<React.SetStateAction<"IDLE" | "LOADING" | "ERROR">>;
|
|
35
32
|
lastErrorEvent: WebViewError | null;
|
|
36
33
|
};
|
|
34
|
+
export declare const versionPasses: (version: string | undefined, minimum: string | undefined) => boolean;
|
|
37
35
|
//# sourceMappingURL=WebViewShared.d.ts.map
|
package/lib/WebViewShared.js
CHANGED
|
@@ -2,24 +2,28 @@ 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 = ['
|
|
5
|
+
const defaultOriginWhitelist = ['https://*'];
|
|
6
6
|
const extractOrigin = (url) => {
|
|
7
7
|
const result = /^[A-Za-z][A-Za-z0-9+\-.]+:(\/\/)?[^/]*/.exec(url);
|
|
8
8
|
return result === null ? '' : result[0];
|
|
9
9
|
};
|
|
10
|
-
const originWhitelistToRegex = (originWhitelist) => `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}
|
|
11
|
-
const
|
|
10
|
+
const originWhitelistToRegex = (originWhitelist) => `^${escapeStringRegexp(originWhitelist).replace(/\\\*/g, '.*')}$`;
|
|
11
|
+
const _passesWhitelist = (compiledWhitelist, url) => {
|
|
12
12
|
const origin = extractOrigin(url);
|
|
13
|
+
if (!origin)
|
|
14
|
+
return false;
|
|
15
|
+
if (origin !== new URL(url).origin)
|
|
16
|
+
return null;
|
|
13
17
|
return compiledWhitelist.some(x => new RegExp(x).test(origin));
|
|
14
18
|
};
|
|
15
19
|
const compileWhitelist = (originWhitelist) => ['about:blank', ...(originWhitelist || [])].map(originWhitelistToRegex);
|
|
16
20
|
const createOnShouldStartLoadWithRequest = (loadRequest, originWhitelist, onShouldStartLoadWithRequest) => {
|
|
17
21
|
return ({ nativeEvent }) => {
|
|
18
22
|
let shouldStart = true;
|
|
19
|
-
const { url, lockIdentifier } = nativeEvent;
|
|
20
|
-
if (!
|
|
23
|
+
const { url, lockIdentifier, isTopFrame } = nativeEvent;
|
|
24
|
+
if (!_passesWhitelist(compileWhitelist(originWhitelist), url)) {
|
|
21
25
|
Linking.canOpenURL(url).then((supported) => {
|
|
22
|
-
if (supported) {
|
|
26
|
+
if (supported && isTopFrame && /^https:\/\//.test(url)) {
|
|
23
27
|
return Linking.openURL(url);
|
|
24
28
|
}
|
|
25
29
|
console.warn(`Can't open url: ${url}`);
|
|
@@ -45,20 +49,30 @@ const defaultRenderError = (errorDomain, errorCode, errorDesc) => (<View style={
|
|
|
45
49
|
<Text style={styles.errorText}>{`Description: ${errorDesc}`}</Text>
|
|
46
50
|
</View>);
|
|
47
51
|
export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
|
|
48
|
-
export const useWebWiewLogic = ({ startInLoadingState,
|
|
52
|
+
export const useWebWiewLogic = ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }) => {
|
|
49
53
|
const [viewState, setViewState] = useState(startInLoadingState ? "LOADING" : "IDLE");
|
|
50
54
|
const [lastErrorEvent, setLastErrorEvent] = useState(null);
|
|
51
55
|
const startUrl = useRef(null);
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
|
|
56
|
+
const passesWhitelist = (url) => {
|
|
57
|
+
if (!url || typeof url !== 'string')
|
|
58
|
+
return false;
|
|
59
|
+
return _passesWhitelist(compileWhitelist(originWhitelist), url);
|
|
60
|
+
};
|
|
61
|
+
const passesWhitelistUse = useCallback(passesWhitelist, [originWhitelist]);
|
|
62
|
+
const extractMeta = (nativeEvent) => ({
|
|
63
|
+
url: String(nativeEvent.url),
|
|
64
|
+
loading: Boolean(nativeEvent.loading),
|
|
65
|
+
title: String(nativeEvent.title),
|
|
66
|
+
canGoBack: Boolean(nativeEvent.canGoBack),
|
|
67
|
+
canGoForward: Boolean(nativeEvent.canGoForward),
|
|
68
|
+
lockIdentifier: Number(nativeEvent.lockIdentifier),
|
|
69
|
+
});
|
|
55
70
|
const onLoadingStart = useCallback((event) => {
|
|
56
71
|
// Needed for android
|
|
57
72
|
startUrl.current = event.nativeEvent.url;
|
|
58
73
|
// !Needed for android
|
|
59
74
|
onLoadStart === null || onLoadStart === void 0 ? void 0 : onLoadStart(event);
|
|
60
|
-
|
|
61
|
-
}, [onLoadStart, updateNavigationState]);
|
|
75
|
+
}, [onLoadStart]);
|
|
62
76
|
const onLoadingError = useCallback((event) => {
|
|
63
77
|
event.persist();
|
|
64
78
|
if (onError) {
|
|
@@ -75,55 +89,92 @@ export const useWebWiewLogic = ({ startInLoadingState, onNavigationStateChange,
|
|
|
75
89
|
setViewState('ERROR');
|
|
76
90
|
setLastErrorEvent(event.nativeEvent);
|
|
77
91
|
}, [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
92
|
const onLoadingFinish = useCallback((event) => {
|
|
92
93
|
onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
|
|
93
94
|
onLoadEnd === null || onLoadEnd === void 0 ? void 0 : onLoadEnd(event);
|
|
94
95
|
const { nativeEvent: { url } } = event;
|
|
96
|
+
if (!passesWhitelistUse(url))
|
|
97
|
+
return;
|
|
95
98
|
// on Android, only if url === startUrl
|
|
96
99
|
if (Platform.OS !== "android" || url === startUrl.current) {
|
|
97
100
|
setViewState('IDLE');
|
|
98
101
|
}
|
|
99
102
|
// !on Android, only if url === startUrl
|
|
100
|
-
updateNavigationState(event);
|
|
101
|
-
}, [onLoad, onLoadEnd,
|
|
103
|
+
// REMOVED: updateNavigationState(event);
|
|
104
|
+
}, [onLoad, onLoadEnd, passesWhitelistUse]);
|
|
102
105
|
const onMessage = useCallback((event) => {
|
|
103
|
-
|
|
104
|
-
|
|
106
|
+
const { nativeEvent } = event;
|
|
107
|
+
if (!passesWhitelistUse(nativeEvent.url))
|
|
108
|
+
return;
|
|
109
|
+
// TODO: can/should we perform any other validation?
|
|
110
|
+
const data = JSON.stringify(validateData(JSON.parse(nativeEvent.data)));
|
|
111
|
+
const meta = validateMeta(extractMeta(nativeEvent));
|
|
112
|
+
onMessageProp === null || onMessageProp === void 0 ? void 0 : onMessageProp({ ...meta, data });
|
|
113
|
+
}, [onMessageProp, passesWhitelistUse, validateData, validateMeta]);
|
|
105
114
|
const onLoadingProgress = useCallback((event) => {
|
|
106
115
|
const { nativeEvent: { progress } } = event;
|
|
116
|
+
if (!passesWhitelistUse(event.nativeEvent.url))
|
|
117
|
+
return;
|
|
107
118
|
// patch for Android only
|
|
108
119
|
if (Platform.OS === "android" && progress === 1) {
|
|
109
120
|
setViewState(prevViewState => prevViewState === 'LOADING' ? 'IDLE' : prevViewState);
|
|
110
121
|
}
|
|
111
122
|
// !patch for Android only
|
|
112
|
-
|
|
113
|
-
}, [
|
|
123
|
+
// REMOVED: onLoadProgress?.(event);
|
|
124
|
+
}, [passesWhitelistUse]);
|
|
114
125
|
const onShouldStartLoadWithRequest = useMemo(() => createOnShouldStartLoadWithRequest(onShouldStartLoadWithRequestCallback, originWhitelist, onShouldStartLoadWithRequestProp), [originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback]);
|
|
126
|
+
// Android Only
|
|
127
|
+
const onOpenWindow = useCallback((event) => {
|
|
128
|
+
onOpenWindowProp === null || onOpenWindowProp === void 0 ? void 0 : onOpenWindowProp(event);
|
|
129
|
+
}, [onOpenWindowProp]);
|
|
130
|
+
// !Android Only
|
|
115
131
|
return {
|
|
116
132
|
onShouldStartLoadWithRequest,
|
|
117
133
|
onLoadingStart,
|
|
118
134
|
onLoadingProgress,
|
|
119
135
|
onLoadingError,
|
|
120
136
|
onLoadingFinish,
|
|
121
|
-
onHttpError,
|
|
122
|
-
onRenderProcessGone,
|
|
123
|
-
onContentProcessDidTerminate,
|
|
124
137
|
onMessage,
|
|
138
|
+
onOpenWindow,
|
|
139
|
+
passesWhitelist,
|
|
125
140
|
viewState,
|
|
126
141
|
setViewState,
|
|
127
142
|
lastErrorEvent,
|
|
128
143
|
};
|
|
129
144
|
};
|
|
145
|
+
export const versionPasses = (version, minimum) => {
|
|
146
|
+
if (!version || !minimum)
|
|
147
|
+
return false;
|
|
148
|
+
if (typeof version !== 'string' || typeof minimum !== 'string')
|
|
149
|
+
return false;
|
|
150
|
+
if (minimum.includes(', ')) {
|
|
151
|
+
// We have a set of possible versions
|
|
152
|
+
const variants = minimum.split(', ');
|
|
153
|
+
// Every entry but the last one should be with an upper bound
|
|
154
|
+
if (!variants.slice(0, -1).every(x => x.includes(' <')))
|
|
155
|
+
return false;
|
|
156
|
+
return variants.some(x => versionPasses(version, x)); // Any match passes
|
|
157
|
+
}
|
|
158
|
+
if (minimum.includes(' <')) {
|
|
159
|
+
const [min, max, ...rest] = minimum.split(' <');
|
|
160
|
+
if (rest.length > 0)
|
|
161
|
+
return false;
|
|
162
|
+
// Last check is required for correctness/formatting validation
|
|
163
|
+
return versionPasses(version, min) && !versionPasses(version, max) && versionPasses(max, version);
|
|
164
|
+
}
|
|
165
|
+
const versionRegex = /^[0-9]+(\.[0-9]+)*$/;
|
|
166
|
+
if (!versionRegex.test(version) || !versionRegex.test(minimum))
|
|
167
|
+
return false;
|
|
168
|
+
const versionParts = version.split('.').map(Number);
|
|
169
|
+
const minimumParts = minimum.split('.').map(Number);
|
|
170
|
+
const len = Math.max(versionParts.length, minimumParts.length);
|
|
171
|
+
for (let i = 0; i < len; i += 1) {
|
|
172
|
+
const ver = versionParts[i] || 0;
|
|
173
|
+
const min = minimumParts[i] || 0;
|
|
174
|
+
if (ver > min)
|
|
175
|
+
return true;
|
|
176
|
+
if (ver < min)
|
|
177
|
+
return false;
|
|
178
|
+
}
|
|
179
|
+
return true; // equals
|
|
180
|
+
};
|