@glomopay/react-native-sdk 4.1.0 → 5.0.0
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/CHANGELOG.md +29 -0
- package/MIGRATION.md +112 -0
- package/README.md +173 -36
- package/lib/bridge/file-input-handler.d.ts +25 -0
- package/lib/bridge/file-input-handler.d.ts.map +1 -0
- package/lib/bridge/file-input-handler.js +38 -0
- package/lib/bridge/file-save-handler.d.ts +32 -0
- package/lib/bridge/file-save-handler.d.ts.map +1 -0
- package/lib/bridge/file-save-handler.js +92 -0
- package/lib/bridge/message-router.d.ts +44 -0
- package/lib/bridge/message-router.d.ts.map +1 -0
- package/lib/bridge/message-router.js +48 -0
- package/lib/bridge/payment-payload.d.ts +18 -0
- package/lib/bridge/payment-payload.d.ts.map +1 -0
- package/lib/bridge/payment-payload.js +31 -0
- package/lib/capabilities/file-save.d.ts +40 -0
- package/lib/capabilities/file-save.d.ts.map +1 -0
- package/lib/capabilities/file-save.js +101 -0
- package/lib/capabilities/index.d.ts +22 -0
- package/lib/capabilities/index.d.ts.map +1 -0
- package/lib/capabilities/index.js +34 -0
- package/lib/capabilities/use-capability-reporting.d.ts +24 -0
- package/lib/capabilities/use-capability-reporting.d.ts.map +1 -0
- package/lib/capabilities/use-capability-reporting.js +44 -0
- package/lib/config/base.d.ts +12 -0
- package/lib/config/base.d.ts.map +1 -1
- package/lib/config/base.js +13 -1
- package/lib/glomo-checkout.d.ts +6 -1
- package/lib/glomo-checkout.d.ts.map +1 -1
- package/lib/glomo-checkout.js +11 -5
- package/lib/glomo-lrs-checkout.d.ts.map +1 -1
- package/lib/glomo-lrs-checkout.js +33 -10
- package/lib/glomo-standard-checkout.d.ts +3 -1
- package/lib/glomo-standard-checkout.d.ts.map +1 -1
- package/lib/glomo-standard-checkout.js +21 -13
- package/lib/glomo-subscriptions-checkout.d.ts.map +1 -1
- package/lib/glomo-subscriptions-checkout.js +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +4 -3
- package/lib/injections/index.d.ts +24 -0
- package/lib/injections/index.d.ts.map +1 -1
- package/lib/injections/index.js +41 -0
- package/lib/injections/webview-flow.injection.d.ts.map +1 -1
- package/lib/injections/webview-flow.injection.js +76 -0
- package/lib/injections/webview-main.injection.d.ts.map +1 -1
- package/lib/injections/webview-main.injection.js +31 -0
- package/lib/injections/webview-standard.injection.d.ts.map +1 -1
- package/lib/injections/webview-standard.injection.js +31 -0
- package/lib/services/file-saver.d.ts +109 -0
- package/lib/services/file-saver.d.ts.map +1 -0
- package/lib/services/file-saver.js +416 -0
- package/lib/types/checkout.d.ts +58 -6
- package/lib/types/checkout.d.ts.map +1 -1
- package/lib/types/checkout.js +24 -2
- package/lib/types/standard-checkout.d.ts +6 -6
- package/lib/types/standard-checkout.d.ts.map +1 -1
- package/lib/types/subscriptions-checkout.d.ts +3 -3
- package/lib/types/subscriptions-checkout.d.ts.map +1 -1
- package/lib/use-glomo-checkout.js +2 -2
- package/lib/use-lrs-checkout.d.ts +9 -5
- package/lib/use-lrs-checkout.d.ts.map +1 -1
- package/lib/use-lrs-checkout.js +317 -171
- package/lib/use-standard-checkout.d.ts +17 -13
- package/lib/use-standard-checkout.d.ts.map +1 -1
- package/lib/use-standard-checkout.js +281 -207
- package/lib/utils/analytics.d.ts +177 -51
- package/lib/utils/analytics.d.ts.map +1 -1
- package/lib/utils/analytics.js +299 -81
- package/lib/utils/device-compliance.d.ts +57 -12
- package/lib/utils/device-compliance.d.ts.map +1 -1
- package/lib/utils/device-compliance.js +101 -37
- package/lib/utils/event-projections.d.ts +56 -0
- package/lib/utils/event-projections.d.ts.map +1 -0
- package/lib/utils/event-projections.js +42 -0
- package/lib/utils/file-metadata.d.ts +52 -0
- package/lib/utils/file-metadata.d.ts.map +1 -0
- package/lib/utils/file-metadata.js +134 -0
- package/lib/utils/use-sdk-session.d.ts +12 -0
- package/lib/utils/use-sdk-session.d.ts.map +1 -0
- package/lib/utils/use-sdk-session.js +37 -0
- package/lib/utils/validation.d.ts +37 -3
- package/lib/utils/validation.d.ts.map +1 -1
- package/lib/utils/validation.js +64 -8
- package/lib/webview/capability-props.d.ts +27 -0
- package/lib/webview/capability-props.d.ts.map +1 -0
- package/lib/webview/capability-props.js +61 -0
- package/lib/webview/use-permission-request.d.ts +33 -0
- package/lib/webview/use-permission-request.d.ts.map +1 -0
- package/lib/webview/use-permission-request.js +89 -0
- package/package.json +10 -2
- package/src/bridge/file-input-handler.ts +66 -0
- package/src/bridge/file-save-handler.ts +141 -0
- package/src/bridge/message-router.ts +92 -0
- package/src/bridge/payment-payload.ts +31 -0
- package/src/capabilities/file-save.ts +124 -0
- package/src/capabilities/index.ts +34 -0
- package/src/capabilities/use-capability-reporting.ts +55 -0
- package/src/config/base.ts +13 -0
- package/src/glomo-checkout.tsx +11 -7
- package/src/glomo-lrs-checkout.tsx +41 -26
- package/src/glomo-standard-checkout.tsx +31 -34
- package/src/glomo-subscriptions-checkout.tsx +1 -0
- package/src/index.ts +4 -2
- package/src/injections/index.ts +43 -0
- package/src/injections/webview-flow.injection.ts +76 -0
- package/src/injections/webview-main.injection.ts +31 -0
- package/src/injections/webview-standard.injection.ts +31 -0
- package/src/services/file-saver.ts +497 -0
- package/src/types/checkout.ts +62 -6
- package/src/types/standard-checkout.ts +6 -6
- package/src/types/subscriptions-checkout.ts +7 -3
- package/src/use-glomo-checkout.tsx +2 -2
- package/src/use-lrs-checkout.tsx +656 -365
- package/src/use-standard-checkout.tsx +728 -466
- package/src/utils/analytics.ts +422 -117
- package/src/utils/device-compliance.ts +148 -38
- package/src/utils/event-projections.ts +74 -0
- package/src/utils/file-metadata.ts +140 -0
- package/src/utils/use-sdk-session.ts +41 -0
- package/src/utils/validation.ts +70 -10
- package/src/webview/capability-props.ts +86 -0
- package/src/webview/use-permission-request.ts +114 -0
- package/src/jail-monkey.d.ts +0 -19
|
@@ -6,8 +6,9 @@ import { WebView, type WebViewMessageEvent, type WebViewProps } from "react-nati
|
|
|
6
6
|
|
|
7
7
|
import { useStandardCheckout } from "./use-standard-checkout";
|
|
8
8
|
import { type GlomoStandardCheckoutRef, type GlomoStandardCheckoutProps } from "./types/standard-checkout";
|
|
9
|
-
import { type CheckoutAnalyticsTrackers } from "./utils/analytics";
|
|
10
|
-
import { isValidUrl } from "./utils/validation";
|
|
9
|
+
import { type CheckoutAnalyticsTrackers, type FlowType } from "./utils/analytics";
|
|
10
|
+
import { isValidUrl, isMockModeKey } from "./utils/validation";
|
|
11
|
+
import { buildCapabilityProps } from "./webview/capability-props";
|
|
11
12
|
|
|
12
13
|
/**
|
|
13
14
|
* Internal-only props for GlomoStandardCheckout.
|
|
@@ -16,6 +17,9 @@ import { isValidUrl } from "./utils/validation";
|
|
|
16
17
|
*/
|
|
17
18
|
export interface GlomoStandardCheckoutInternalProps extends GlomoStandardCheckoutProps {
|
|
18
19
|
_analyticsTrackers?: CheckoutAnalyticsTrackers;
|
|
20
|
+
|
|
21
|
+
/** Names the flow for telemetry the tracker map does not cover - see UseStandardCheckoutInternalOptions */
|
|
22
|
+
_flowType?: FlowType;
|
|
19
23
|
_skipOrderIdValidation?: boolean;
|
|
20
24
|
_testInjectionScript?: string;
|
|
21
25
|
}
|
|
@@ -29,7 +33,9 @@ export interface GlomoStandardCheckoutInternalProps extends GlomoStandardCheckou
|
|
|
29
33
|
*
|
|
30
34
|
* @param onPaymentSuccess - The success callback with payload, for a successful payment
|
|
31
35
|
* @param onPaymentFailure - The failure callback with payload, for a failed payment
|
|
32
|
-
* @param
|
|
36
|
+
* @param onUserJourneyCompleted - Optional callback for asynchronous payment journeys - bank transfers and pay via bank. Carries the journey type and the transfer details the page reported, not a confirmed payment. LRS/Cards flows will never trigger this.
|
|
37
|
+
* @param onPaymentTerminate - Optional callback called when the checkout ends without a payment outcome. Receives a payload whose `source` is a TERMINATION_SOURCES value naming how it ended: the page's own close control, the Android back button/gesture, or an iOS swipe-down on the modal. The back chevron over a bank flow is deliberately not a termination - it returns the user to the checkout with the session intact.
|
|
38
|
+
* @param onUserRefusedDevicePermissions - Optional callback invoked when the user refuses a device permission the bank's page asked for - camera today. Upload-related permissions are requested by react-native-webview itself and do not reach this callback. Currently Android only: due to platform limitations on iOS, the WebView raises its own prompt and never reports the answer back, so this cannot fire there.
|
|
33
39
|
*
|
|
34
40
|
* @param onConnectionError - Optional callback for connection/network errors
|
|
35
41
|
* @param onSdkError - Optional callback for handling SDK validation errors and configuration issues
|
|
@@ -48,9 +54,10 @@ function GlomoStandardCheckoutComponent(
|
|
|
48
54
|
onPaymentTerminate,
|
|
49
55
|
onSdkError,
|
|
50
56
|
onUserJourneyCompleted,
|
|
51
|
-
|
|
57
|
+
onUserRefusedDevicePermissions,
|
|
52
58
|
devMode = false,
|
|
53
59
|
_analyticsTrackers,
|
|
60
|
+
_flowType,
|
|
54
61
|
_skipOrderIdValidation,
|
|
55
62
|
_testInjectionScript,
|
|
56
63
|
}: GlomoStandardCheckoutInternalProps,
|
|
@@ -58,7 +65,7 @@ function GlomoStandardCheckoutComponent(
|
|
|
58
65
|
) {
|
|
59
66
|
// Computing mockMode based on the publicKey prefix
|
|
60
67
|
const mockMode = useMemo(() => {
|
|
61
|
-
const resolvedMockMode = publicKey
|
|
68
|
+
const resolvedMockMode = isMockModeKey(publicKey);
|
|
62
69
|
if (devMode) {
|
|
63
70
|
console.log(
|
|
64
71
|
`[Glomo-RN-SDK Standard] ${resolvedMockMode ? "Using" : "Not using"} Mock mode for publicKey: ${publicKey}`
|
|
@@ -97,11 +104,11 @@ function GlomoStandardCheckoutComponent(
|
|
|
97
104
|
onPaymentTerminate,
|
|
98
105
|
onSdkError,
|
|
99
106
|
onUserJourneyCompleted,
|
|
100
|
-
|
|
107
|
+
onUserRefusedDevicePermissions,
|
|
101
108
|
devMode,
|
|
102
109
|
},
|
|
103
110
|
mockMode,
|
|
104
|
-
{ analyticsTrackers: _analyticsTrackers, _skipOrderIdValidation, _testInjectionScript }
|
|
111
|
+
{ analyticsTrackers: _analyticsTrackers, flowType: _flowType, _skipOrderIdValidation, _testInjectionScript }
|
|
105
112
|
);
|
|
106
113
|
|
|
107
114
|
// Exposing the start() and getStatus() methods via the ref
|
|
@@ -110,6 +117,12 @@ function GlomoStandardCheckoutComponent(
|
|
|
110
117
|
getStatus: () => status,
|
|
111
118
|
}));
|
|
112
119
|
|
|
120
|
+
// Configuration shared by every WebView the SDK renders, regardless of flow
|
|
121
|
+
const capabilityProps = useMemo(
|
|
122
|
+
() => buildCapabilityProps({ devMode, onPermissionRequest: handlePermissionRequest }),
|
|
123
|
+
[devMode, handlePermissionRequest]
|
|
124
|
+
);
|
|
125
|
+
|
|
113
126
|
// Making the WebView component
|
|
114
127
|
const makeWebView = React.useCallback(
|
|
115
128
|
(
|
|
@@ -153,10 +166,8 @@ function GlomoStandardCheckoutComponent(
|
|
|
153
166
|
|
|
154
167
|
return (
|
|
155
168
|
<WebView
|
|
169
|
+
{...capabilityProps}
|
|
156
170
|
ref={ref}
|
|
157
|
-
webviewDebuggingEnabled={__DEV__ && devMode}
|
|
158
|
-
javaScriptEnabled={true}
|
|
159
|
-
domStorageEnabled={true}
|
|
160
171
|
onMessage={messageHandler}
|
|
161
172
|
onError={handleError}
|
|
162
173
|
onHttpError={handleHttpError}
|
|
@@ -172,36 +183,14 @@ function GlomoStandardCheckoutComponent(
|
|
|
172
183
|
}
|
|
173
184
|
}}
|
|
174
185
|
source={{ uri: url }}
|
|
175
|
-
javaScriptCanOpenWindowsAutomatically={true}
|
|
176
|
-
setSupportMultipleWindows={true}
|
|
177
|
-
incognito={true}
|
|
178
|
-
cacheEnabled={false}
|
|
179
|
-
cacheMode='LOAD_NO_CACHE'
|
|
180
|
-
pullToRefreshEnabled={false}
|
|
181
|
-
limitsNavigationsToAppBoundDomains={false}
|
|
182
|
-
menuItems={[]}
|
|
183
186
|
injectedJavaScript={injectedJavaScript}
|
|
184
187
|
injectedJavaScriptBeforeContentLoaded={injectedJavaScriptBeforeContentLoaded}
|
|
185
188
|
style={styles.webview}
|
|
186
|
-
showsHorizontalScrollIndicator={false}
|
|
187
|
-
showsVerticalScrollIndicator={false}
|
|
188
|
-
mixedContentMode='always'
|
|
189
|
-
thirdPartyCookiesEnabled={true}
|
|
190
|
-
sharedCookiesEnabled={true}
|
|
191
|
-
allowsInlineMediaPlayback={true}
|
|
192
|
-
mediaPlaybackRequiresUserAction={false}
|
|
193
|
-
mediaCapturePermissionGrantType='prompt'
|
|
194
|
-
allowFileAccess={true}
|
|
195
|
-
allowUniversalAccessFromFileURLs={true}
|
|
196
|
-
allowFileAccessFromFileURLs={true}
|
|
197
|
-
androidLayerType='hardware'
|
|
198
|
-
// @ts-expect-error onPermissionRequest is an Android-only WebView prop not yet in react-native-webview type definitions
|
|
199
|
-
onPermissionRequest={handlePermissionRequest}
|
|
200
189
|
{...additionalProps}
|
|
201
190
|
/>
|
|
202
191
|
);
|
|
203
192
|
},
|
|
204
|
-
[handleError, handleHttpError, handleNavigationStateChange,
|
|
193
|
+
[handleError, handleHttpError, handleNavigationStateChange, capabilityProps, devMode]
|
|
205
194
|
);
|
|
206
195
|
|
|
207
196
|
const MainWebViewComponent = useMemo(
|
|
@@ -262,6 +251,8 @@ function GlomoStandardCheckoutComponent(
|
|
|
262
251
|
<TouchableOpacity
|
|
263
252
|
onPress={handleFlowBack}
|
|
264
253
|
style={styles.flowBackButton}
|
|
254
|
+
accessibilityRole='button'
|
|
255
|
+
accessibilityLabel='Go back to checkout'
|
|
265
256
|
>
|
|
266
257
|
<Text style={styles.flowBackChevron}>{"\u2039"}</Text>
|
|
267
258
|
</TouchableOpacity>
|
|
@@ -324,8 +315,14 @@ const styles = StyleSheet.create({
|
|
|
324
315
|
borderBottomColor: "#e0e0e0",
|
|
325
316
|
},
|
|
326
317
|
flowBackButton: {
|
|
327
|
-
|
|
318
|
+
/**
|
|
319
|
+
* Sized to the 44dp / 44pt minimum touch target both platforms specify. The glyph alone is
|
|
320
|
+
* 42px tall and the hit area used to hug it horizontally, which is the only SDK-drawn
|
|
321
|
+
* control in this package and the one a user reaches mid-payment.
|
|
322
|
+
*/
|
|
323
|
+
paddingVertical: 6,
|
|
328
324
|
paddingLeft: 20,
|
|
325
|
+
paddingRight: 20,
|
|
329
326
|
},
|
|
330
327
|
flowBackChevron: {
|
|
331
328
|
fontSize: 42,
|
package/src/index.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
/** The GlomoPay RN SDK
|
|
1
|
+
/** The GlomoPay RN SDK v5 exports */
|
|
2
2
|
|
|
3
|
-
//
|
|
3
|
+
// v5 public API - unified checkout
|
|
4
4
|
export { GlomoCheckout } from "./glomo-checkout";
|
|
5
5
|
export {
|
|
6
6
|
type GlomoCheckoutRef,
|
|
@@ -8,7 +8,9 @@ export {
|
|
|
8
8
|
type GlomoCheckoutPayload,
|
|
9
9
|
type CheckoutStatus,
|
|
10
10
|
type GlomoUserJourneyCompletedPayload,
|
|
11
|
+
type GlomoTerminationPayload,
|
|
11
12
|
ASYNC_PAYMENT_EVENTS,
|
|
13
|
+
TERMINATION_SOURCES,
|
|
12
14
|
} from "./types/checkout";
|
|
13
15
|
export { type GlomoServer } from "./config/base";
|
|
14
16
|
export { type SdkError } from "./utils/analytics";
|
package/src/injections/index.ts
CHANGED
|
@@ -6,6 +6,49 @@ import { injectedScript as flowScript } from "./webview-flow.injection";
|
|
|
6
6
|
import { injectedScript as educationCarouselScript } from "./webview-education-carousel.injection";
|
|
7
7
|
import { injectedScript as standardScript } from "./webview-standard.injection";
|
|
8
8
|
|
|
9
|
+
/**
|
|
10
|
+
* Publishes what this SDK build can handle, for the checkout page to gate on.
|
|
11
|
+
*
|
|
12
|
+
* Appends rather than assigns, and de-duplicates, because the array is shared with anything else
|
|
13
|
+
* that writes to it. The page reads it at the moment it needs a capability rather than snapshotting
|
|
14
|
+
* it at load, so a script that runs after the page has mounted still takes effect.
|
|
15
|
+
*
|
|
16
|
+
* Returns an empty string when there is nothing to advertise - the page treats a missing array and
|
|
17
|
+
* an empty one the same way, so there is no reason to inject the assignment.
|
|
18
|
+
*/
|
|
19
|
+
export function buildCapabilityAdvertisement(capabilities: string[]): string {
|
|
20
|
+
if (capabilities.length === 0) {
|
|
21
|
+
return "";
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return `
|
|
25
|
+
(function() {
|
|
26
|
+
window.__glomoSdkCapabilities__ = (window.__glomoSdkCapabilities__ || [])
|
|
27
|
+
.concat(${JSON.stringify(capabilities)})
|
|
28
|
+
.filter(function(cap, i, all) { return all.indexOf(cap) === i; });
|
|
29
|
+
})();
|
|
30
|
+
true;
|
|
31
|
+
`;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* The scripts injected into each WebView, for a build with the given capabilities.
|
|
36
|
+
*
|
|
37
|
+
* Capabilities are advertised on the WebViews that load a checkout or a bank page, and not on the
|
|
38
|
+
* education carousel - that renders our own content, which has nothing to gate. Advertising a
|
|
39
|
+
* capability where nothing can exercise it is noise on a contract the page reads.
|
|
40
|
+
*/
|
|
41
|
+
export function buildInjectionScripts(capabilities: string[]) {
|
|
42
|
+
const advertisement = buildCapabilityAdvertisement(capabilities);
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
main: mainScript + advertisement,
|
|
46
|
+
flow: flowScript + advertisement,
|
|
47
|
+
standard: standardScript + advertisement,
|
|
48
|
+
educationCarousel: educationCarouselScript,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
9
52
|
export const InjectionScripts = {
|
|
10
53
|
main: mainScript,
|
|
11
54
|
flow: flowScript,
|
|
@@ -203,6 +203,82 @@ export const injectedScript: string = `
|
|
|
203
203
|
});
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* File-input click detection.
|
|
209
|
+
*
|
|
210
|
+
* Does not open the picker - react-native-webview does that natively through
|
|
211
|
+
* onShowFileChooser, and the SDK never sees the rest of it. This carries the only record
|
|
212
|
+
* that an upload was attempted, and on iOS it is the only file signal at all, since
|
|
213
|
+
* WKWebView runs its own picker and reports nothing back.
|
|
214
|
+
*
|
|
215
|
+
* Capture phase, so a page that stops propagation on its own handler cannot silence it.
|
|
216
|
+
*
|
|
217
|
+
* Posts the shape of the input and nothing that identifies it. The id and name of a KYC
|
|
218
|
+
* upload control are third-party identity, and unconsumed page data sitting on the bridge is
|
|
219
|
+
* how identity ends up spread into a tracker by someone who never read this.
|
|
220
|
+
*/
|
|
221
|
+
document.addEventListener('click', function(event) {
|
|
222
|
+
try {
|
|
223
|
+
const target = event.target;
|
|
224
|
+
if (!target || target.tagName !== 'INPUT' || target.type !== 'file') {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
safePostMessage({
|
|
228
|
+
type: 'file.input',
|
|
229
|
+
accept: target.getAttribute('accept') || '',
|
|
230
|
+
hasCapture: target.hasAttribute('capture')
|
|
231
|
+
});
|
|
232
|
+
} catch (error) {
|
|
233
|
+
// Never let this break a bank's own upload handling
|
|
234
|
+
}
|
|
235
|
+
}, true);
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
/**
|
|
239
|
+
* getUserMedia observation.
|
|
240
|
+
*
|
|
241
|
+
* Telemetry only, and it must stay that way. A rejection with NotAllowedError IS the user
|
|
242
|
+
* denying camera access - an observation, not an inference - and on iOS it is the only one
|
|
243
|
+
* available, because WKWebView raises its own prompt and never reports the answer back.
|
|
244
|
+
*
|
|
245
|
+
* It deliberately does NOT drive onUserRefusedDevicePermissions. Coverage depends on whether
|
|
246
|
+
* a given bank uses getUserMedia or a capture-enabled file input, which is third-party
|
|
247
|
+
* markup we do not control and are not told about when it changes. A callback that fires for
|
|
248
|
+
* some banks would leave a merchant unable to tell "the user did not deny" from "this bank's
|
|
249
|
+
* flow is not observable". Silence is unambiguous; partial coverage is not.
|
|
250
|
+
*
|
|
251
|
+
* Wrapped thinly and never allowed to throw: this runs inside a bank's page, and a fault in
|
|
252
|
+
* our handler must not be able to break their capture flow.
|
|
253
|
+
*/
|
|
254
|
+
(function() {
|
|
255
|
+
try {
|
|
256
|
+
const media = navigator.mediaDevices;
|
|
257
|
+
if (!media || typeof media.getUserMedia !== 'function') {
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
const originalGetUserMedia = media.getUserMedia.bind(media);
|
|
261
|
+
media.getUserMedia = function(constraints) {
|
|
262
|
+
return originalGetUserMedia(constraints).catch(function(error) {
|
|
263
|
+
try {
|
|
264
|
+
if (error && error.name === 'NotAllowedError') {
|
|
265
|
+
safePostMessage({
|
|
266
|
+
type: 'permission.denied',
|
|
267
|
+
resource: (constraints && constraints.video) ? 'camera' : 'microphone',
|
|
268
|
+
errorName: error.name
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
} catch (reportingError) {
|
|
272
|
+
// Reporting must never change what the page sees
|
|
273
|
+
}
|
|
274
|
+
throw error;
|
|
275
|
+
});
|
|
276
|
+
};
|
|
277
|
+
} catch (error) {
|
|
278
|
+
// A page that has frozen navigator.mediaDevices keeps working, unobserved
|
|
279
|
+
}
|
|
280
|
+
})();
|
|
281
|
+
|
|
206
282
|
// Logging that injection is complete
|
|
207
283
|
console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete');
|
|
208
284
|
|
|
@@ -209,6 +209,37 @@ export const injectedScript: string = `
|
|
|
209
209
|
});
|
|
210
210
|
});
|
|
211
211
|
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* File-input click detection.
|
|
215
|
+
*
|
|
216
|
+
* Does not open the picker - react-native-webview does that natively through
|
|
217
|
+
* onShowFileChooser, and the SDK never sees the rest of it. This carries the only record
|
|
218
|
+
* that an upload was attempted, and on iOS it is the only file signal at all, since
|
|
219
|
+
* WKWebView runs its own picker and reports nothing back.
|
|
220
|
+
*
|
|
221
|
+
* Capture phase, so a page that stops propagation on its own handler cannot silence it.
|
|
222
|
+
*
|
|
223
|
+
* Posts the shape of the input and nothing that identifies it. The id and name of a KYC
|
|
224
|
+
* upload control are third-party identity, and unconsumed page data sitting on the bridge is
|
|
225
|
+
* how identity ends up spread into a tracker by someone who never read this.
|
|
226
|
+
*/
|
|
227
|
+
document.addEventListener('click', function(event) {
|
|
228
|
+
try {
|
|
229
|
+
const target = event.target;
|
|
230
|
+
if (!target || target.tagName !== 'INPUT' || target.type !== 'file') {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
safePostMessage({
|
|
234
|
+
type: 'file.input',
|
|
235
|
+
accept: target.getAttribute('accept') || '',
|
|
236
|
+
hasCapture: target.hasAttribute('capture')
|
|
237
|
+
});
|
|
238
|
+
} catch (error) {
|
|
239
|
+
// Never let this break a bank's own upload handling
|
|
240
|
+
}
|
|
241
|
+
}, true);
|
|
242
|
+
|
|
212
243
|
// Logging that injection is complete
|
|
213
244
|
console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete');
|
|
214
245
|
|
|
@@ -203,6 +203,37 @@ export const injectedScript: string = `
|
|
|
203
203
|
});
|
|
204
204
|
});
|
|
205
205
|
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* File-input click detection.
|
|
209
|
+
*
|
|
210
|
+
* Does not open the picker - react-native-webview does that natively through
|
|
211
|
+
* onShowFileChooser, and the SDK never sees the rest of it. This carries the only record
|
|
212
|
+
* that an upload was attempted, and on iOS it is the only file signal at all, since
|
|
213
|
+
* WKWebView runs its own picker and reports nothing back.
|
|
214
|
+
*
|
|
215
|
+
* Capture phase, so a page that stops propagation on its own handler cannot silence it.
|
|
216
|
+
*
|
|
217
|
+
* Posts the shape of the input and nothing that identifies it. The id and name of a KYC
|
|
218
|
+
* upload control are third-party identity, and unconsumed page data sitting on the bridge is
|
|
219
|
+
* how identity ends up spread into a tracker by someone who never read this.
|
|
220
|
+
*/
|
|
221
|
+
document.addEventListener('click', function(event) {
|
|
222
|
+
try {
|
|
223
|
+
const target = event.target;
|
|
224
|
+
if (!target || target.tagName !== 'INPUT' || target.type !== 'file') {
|
|
225
|
+
return;
|
|
226
|
+
}
|
|
227
|
+
safePostMessage({
|
|
228
|
+
type: 'file.input',
|
|
229
|
+
accept: target.getAttribute('accept') || '',
|
|
230
|
+
hasCapture: target.hasAttribute('capture')
|
|
231
|
+
});
|
|
232
|
+
} catch (error) {
|
|
233
|
+
// Never let this break a bank's own upload handling
|
|
234
|
+
}
|
|
235
|
+
}, true);
|
|
236
|
+
|
|
206
237
|
// Logging that injection is complete
|
|
207
238
|
console.log(LOG_PREFIX + 'GlomoPay WebView JavaScript injection complete');
|
|
208
239
|
|