Search code examples
reactjsreact-nativeexpomangopay

3DS2 BrowserInfo data with React Native and Expo


In order to integrate the 3DS2 protocol of my payment provider (MangoPay), I have to give the BrowserInfo data.

Here is an example:

{
"BrowserInfo": {
        "AcceptHeader" : "application/json,text/javascript,*/*;q=0.01<", 
        "JavaEnabled": true,
        "Language":"fr",
        "ColorDepth": 32,
        "ScreenHeight": 667,
        "ScreenWidth": 375, 
        "TimeZoneOffset": "-120" 
        "UserAgent": "Mozilla/5.0 (iPhone; CPU iPhone OS 13_6_1 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148" 
        "JavascriptEnabled": true
}

Currently, I am able to open a browser instance using WebBrowser.openBrowserAsync.

How can I retrieve those information using React Native + Expo?


Solution

  • The only doable way I found is a multiple steps process.

    Public web page

    Create and host a public web page doing the following:

    1. Fetch the browser info onto an object
    2. Redirect to the given redirect URL with the info

    In a nutshell:

    <!DOCTYPE html>
    <html lang="en">
      <body>
        <script type="text/javascript">
          const browserInfo = {
            // Currently unable to fetch the default value automatically.
            // @see https://developer.mozilla.org/en-US/docs/Web/HTTP/Content_negotiation/List_of_default_Accept_values
            acceptHeader: 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8',
            javaEnabled: window.navigator.javaEnabled(),
            language: window.navigator.language,
            colorDepth: window.screen.colorDepth,
            screenHeight: window.screen.availHeight,
            screenWidth: window.screen.availWidth,
            timeZoneOffset: window.navigator.timeZoneOffset,
            userAgent: window.navigator.userAgent,
            javascriptEnabled: true,
          }
          console.log('browserInfo', browserInfo);
    
          const urlParams = new URLSearchParams(window.location.search);
    
          if (urlParams.has('redirectUrl')) {
            const redirectUrl = new URL(urlParams.get('redirectUrl'));
            Object.entries(browserInfo).forEach(([key, value]) => {
              redirectUrl.searchParams.append(key, value);
            });
            document.location = redirectUrl.toString();
          }
        </script>
      </body>
    </html>
    

    Expo app redirect fetching

    On expo, you have two things to do:

    1. Start an event listener to fetch the redirect
    2. Open a WebBrowser instance to the previous public page

    Example:

    import React, { FC, useCallback } from 'react';
    import * as Linking from 'expo-linking';
    import * as WebBrowser from 'expo-web-browser';
    import * as queryString from 'query-string';
    import {
      Button,
    } from '@kidways/apps-components';
    import {
      ButtonProps,
      View,
    } from 'react-native';
    import { useFocusEffect } from '@react-navigation/native';
    
    const App: FC = () => {
      const urlEventHandler = (event) => {
        const parsedUrl = queryString.parseUrl(event.url);
        const path = parsedUrl.url.split('/--/')[1];
    
        if (
          path === 'browser-info'
        ) {
          // At this point, you have all the needed information.
          console.log('browser-info', parsedUrl.query);
        }
      };
    
      useFocusEffect(
        useCallback(() => {
          Linking.addEventListener('url', urlEventHandler);
    
          return () => Linking.removeEventListener('url', urlEventHandler);
        }, []),
      );
    
      const handleBrowserInfoTest: ButtonProps['onPress'] = () => {
        WebBrowser.openBrowserAsync(
          'https://your.domain/browser.html?redirectUrl='
          + Linking.createURL('browser-info')
        );
      }
    
      return (
        <View>
          <Button
            title="Browser Info"
            onPress={handleBrowserInfoTest}
          />
        </View>
      );
    };
    

    With this code, you have a way to fetch the browser info just by pressing the button.

    This solution is not ideal because of the user browser opening to achieve that, but I am afraid there is currently no other way.