@exodus/react-native-webview 11.26.1-exodus.20 → 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.
- package/lib/WebView.android.js +3 -2
- package/lib/WebView.ios.js +3 -2
- package/lib/WebViewShared.d.ts +5 -3
- package/lib/WebViewShared.js +39 -16
- package/lib/WebViewTypes.d.ts +6 -0
- package/package.json +1 -1
package/lib/WebView.android.js
CHANGED
|
@@ -5,7 +5,7 @@ import BatchedBridge from 'react-native/Libraries/BatchedBridge/BatchedBridge';
|
|
|
5
5
|
import codegenNativeCommandsUntyped from 'react-native/Libraries/Utilities/codegenNativeCommands';
|
|
6
6
|
import invariant from 'invariant';
|
|
7
7
|
import RNCWebView from "./WebViewNativeComponent.android";
|
|
8
|
-
import { defaultOriginWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, versionPasses, } from './WebViewShared';
|
|
8
|
+
import { defaultOriginWhitelist, defaultDeeplinkWhitelist, defaultRenderError, defaultRenderLoading, useWebWiewLogic, versionPasses, } from './WebViewShared';
|
|
9
9
|
import styles from './WebView.styles';
|
|
10
10
|
const { getWebViewDefaultUserAgent } = NativeModules.RNCWebViewUtils;
|
|
11
11
|
let userAgentPromise;
|
|
@@ -31,7 +31,7 @@ const mediaPlaybackRequiresUserAction = true;
|
|
|
31
31
|
const setSupportMultipleWindows = true;
|
|
32
32
|
const mixedContentMode = 'never';
|
|
33
33
|
const hardMinimumChromeVersion = '100.0'; // TODO: determinime a good lower bound
|
|
34
|
-
const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnabled = true, thirdPartyCookiesEnabled = true, scalesPageToFit = true, saveFormDataDisabled = false, cacheEnabled = true, androidHardwareAccelerationDisabled = false, androidLayerType = "none", originWhitelist = defaultOriginWhitelist, setBuiltInZoomControls = true, setDisplayZoomControls = false, nestedScrollEnabled = false, startInLoadingState, onLoadStart, onError, onLoad, onLoadEnd, onMessage: onMessageProp, onOpenWindow: onOpenWindowProp, renderLoading, renderError, style, containerStyle, source, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, validateMeta, validateData, minimumChromeVersion, unsupportedVersionComponent: UnsupportedVersionComponent, ...otherProps }, ref) => {
|
|
34
|
+
const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnabled = true, thirdPartyCookiesEnabled = true, scalesPageToFit = true, saveFormDataDisabled = false, cacheEnabled = true, androidHardwareAccelerationDisabled = false, androidLayerType = "none", originWhitelist = defaultOriginWhitelist, deeplinkWhitelist = defaultDeeplinkWhitelist, setBuiltInZoomControls = true, setDisplayZoomControls = false, nestedScrollEnabled = false, startInLoadingState, onLoadStart, onError, onLoad, onLoadEnd, onMessage: onMessageProp, onOpenWindow: onOpenWindowProp, renderLoading, renderError, style, containerStyle, source, onShouldStartLoadWithRequest: onShouldStartLoadWithRequestProp, validateMeta, validateData, minimumChromeVersion, unsupportedVersionComponent: UnsupportedVersionComponent, ...otherProps }, ref) => {
|
|
35
35
|
var _a;
|
|
36
36
|
const messagingModuleName = useRef(`WebViewMessageHandler${uniqueRef += 1}`).current;
|
|
37
37
|
const webViewRef = useRef(null);
|
|
@@ -52,6 +52,7 @@ const WebViewComponent = forwardRef(({ overScrollMode = 'always', javaScriptEnab
|
|
|
52
52
|
onOpenWindowProp,
|
|
53
53
|
startInLoadingState,
|
|
54
54
|
originWhitelist,
|
|
55
|
+
deeplinkWhitelist,
|
|
55
56
|
onShouldStartLoadWithRequestProp,
|
|
56
57
|
onShouldStartLoadWithRequestCallback,
|
|
57
58
|
validateMeta,
|
package/lib/WebView.ios.js
CHANGED
|
@@ -4,7 +4,7 @@ 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, versionPasses, } 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({
|
|
@@ -39,7 +39,7 @@ const sharedCookiesEnabled = false;
|
|
|
39
39
|
const enableApplePay = false;
|
|
40
40
|
const dataDetectorTypes = 'none';
|
|
41
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) => {
|
|
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) => {
|
|
43
43
|
const webViewRef = useRef(null);
|
|
44
44
|
const onShouldStartLoadWithRequestCallback = useCallback((shouldStart, _url, lockIdentifier = 0) => {
|
|
45
45
|
const viewManager = RNCWebViewManager;
|
|
@@ -53,6 +53,7 @@ const WebViewComponent = forwardRef(({ javaScriptEnabled = true, cacheEnabled =
|
|
|
53
53
|
onMessageProp,
|
|
54
54
|
startInLoadingState,
|
|
55
55
|
originWhitelist,
|
|
56
|
+
deeplinkWhitelist,
|
|
56
57
|
onShouldStartLoadWithRequestProp,
|
|
57
58
|
onShouldStartLoadWithRequestCallback,
|
|
58
59
|
validateMeta,
|
package/lib/WebViewShared.d.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import { OnShouldStartLoadWithRequest, ShouldStartLoadRequestEvent, WebViewError, WebViewErrorEvent, WebViewMessageEvent, WebViewMessage, WebViewNavigationEvent, WebViewOpenWindowEvent, WebViewProgressEvent, WebViewNativeEvent } from './WebViewTypes';
|
|
3
3
|
declare const defaultOriginWhitelist: readonly ["https://*"];
|
|
4
|
-
declare const
|
|
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, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }: {
|
|
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
11
|
onLoadStart?: ((event: WebViewNavigationEvent) => void) | undefined;
|
|
11
12
|
onLoad?: ((event: WebViewNavigationEvent) => void) | undefined;
|
|
@@ -14,6 +15,7 @@ export declare const useWebWiewLogic: ({ startInLoadingState, onLoadStart, onLoa
|
|
|
14
15
|
onMessageProp?: ((event: WebViewMessage) => void) | undefined;
|
|
15
16
|
onOpenWindowProp?: ((event: WebViewOpenWindowEvent) => void) | undefined;
|
|
16
17
|
originWhitelist: readonly string[];
|
|
18
|
+
deeplinkWhitelist: readonly string[];
|
|
17
19
|
onShouldStartLoadWithRequestProp?: OnShouldStartLoadWithRequest | undefined;
|
|
18
20
|
onShouldStartLoadWithRequestCallback: (shouldStart: boolean, url: string, lockIdentifier?: number | undefined) => void;
|
|
19
21
|
validateMeta: (event: WebViewNativeEvent) => WebViewNativeEvent;
|
package/lib/WebViewShared.js
CHANGED
|
@@ -3,34 +3,57 @@ 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
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
|
|
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
|
+
};
|
|
11
21
|
const _passesWhitelist = (compiledWhitelist, url) => {
|
|
12
22
|
const origin = extractOrigin(url);
|
|
13
23
|
if (!origin)
|
|
14
24
|
return false;
|
|
15
25
|
if (origin !== new URL(url).origin)
|
|
16
26
|
return null;
|
|
17
|
-
return compiledWhitelist
|
|
27
|
+
return matchWithRegexList(compiledWhitelist, origin);
|
|
18
28
|
};
|
|
19
|
-
const compileWhitelist = (originWhitelist) => ['about:blank', ...(originWhitelist || [])].map(
|
|
20
|
-
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);
|
|
21
32
|
return ({ nativeEvent }) => {
|
|
22
33
|
let shouldStart = true;
|
|
23
34
|
const { url, lockIdentifier, isTopFrame } = nativeEvent;
|
|
24
|
-
if
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
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}`);
|
|
28
55
|
}
|
|
29
|
-
|
|
30
|
-
return undefined;
|
|
31
|
-
}).catch(e => {
|
|
32
|
-
console.warn('Error opening URL: ', e);
|
|
33
|
-
});
|
|
56
|
+
}
|
|
34
57
|
shouldStart = false;
|
|
35
58
|
}
|
|
36
59
|
else if (onShouldStartLoadWithRequest) {
|
|
@@ -48,8 +71,8 @@ const defaultRenderError = (errorDomain, errorCode, errorDesc) => (<View style={
|
|
|
48
71
|
<Text style={styles.errorText}>{`Error Code: ${errorCode}`}</Text>
|
|
49
72
|
<Text style={styles.errorText}>{`Description: ${errorDesc}`}</Text>
|
|
50
73
|
</View>);
|
|
51
|
-
export { defaultOriginWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
|
|
52
|
-
export const useWebWiewLogic = ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }) => {
|
|
74
|
+
export { defaultOriginWhitelist, defaultDeeplinkWhitelist, createOnShouldStartLoadWithRequest, defaultRenderLoading, defaultRenderError, };
|
|
75
|
+
export const useWebWiewLogic = ({ startInLoadingState, onLoadStart, onLoad, onLoadEnd, onError, onMessageProp, onOpenWindowProp, originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback, validateMeta, validateData, }) => {
|
|
53
76
|
const [viewState, setViewState] = useState(startInLoadingState ? "LOADING" : "IDLE");
|
|
54
77
|
const [lastErrorEvent, setLastErrorEvent] = useState(null);
|
|
55
78
|
const startUrl = useRef(null);
|
|
@@ -122,7 +145,7 @@ export const useWebWiewLogic = ({ startInLoadingState, onLoadStart, onLoad, onLo
|
|
|
122
145
|
// !patch for Android only
|
|
123
146
|
// REMOVED: onLoadProgress?.(event);
|
|
124
147
|
}, [passesWhitelistUse]);
|
|
125
|
-
const onShouldStartLoadWithRequest = useMemo(() => createOnShouldStartLoadWithRequest(onShouldStartLoadWithRequestCallback, originWhitelist, onShouldStartLoadWithRequestProp), [originWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback]);
|
|
148
|
+
const onShouldStartLoadWithRequest = useMemo(() => createOnShouldStartLoadWithRequest(onShouldStartLoadWithRequestCallback, originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp), [originWhitelist, deeplinkWhitelist, onShouldStartLoadWithRequestProp, onShouldStartLoadWithRequestCallback]);
|
|
126
149
|
// Android Only
|
|
127
150
|
const onOpenWindow = useCallback((event) => {
|
|
128
151
|
onOpenWindowProp === null || onOpenWindowProp === void 0 ? void 0 : onOpenWindowProp(event);
|
package/lib/WebViewTypes.d.ts
CHANGED
|
@@ -713,6 +713,12 @@ export interface WebViewSharedProps extends ViewProps {
|
|
|
713
713
|
* The default whitelisted origins are "http://*" and "https://*".
|
|
714
714
|
*/
|
|
715
715
|
readonly originWhitelist?: string[];
|
|
716
|
+
/**
|
|
717
|
+
* List of prefixes to allow being deep linked to. The strings do NOT allow
|
|
718
|
+
* wildcards and get matched against the full URL using "startsWith".
|
|
719
|
+
* The default behavior is to only allow "https://".
|
|
720
|
+
*/
|
|
721
|
+
readonly deeplinkWhitelist?: string[];
|
|
716
722
|
/**
|
|
717
723
|
* Function that allows custom handling of any web view requests. Return
|
|
718
724
|
* `true` from the function to continue loading the request and `false`
|
package/package.json
CHANGED
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"Thibault Malbranche <malbranche.thibault@gmail.com>"
|
|
10
10
|
],
|
|
11
11
|
"license": "MIT",
|
|
12
|
-
"version": "11.26.1-exodus.
|
|
12
|
+
"version": "11.26.1-exodus.21",
|
|
13
13
|
"homepage": "https://github.com/ExodusMovement/react-native-webview#readme",
|
|
14
14
|
"scripts": {
|
|
15
15
|
"android": "react-native run-android",
|