react-native-splash-screen icon indicating copy to clipboard operation
react-native-splash-screen copied to clipboard

React Navigation deep linking - async getInitialURL(). Method [RNSplashScreen show]; breaks deep linking flow.

Open chukhlov opened this issue 1 year ago • 0 comments

Hi all. I would like to report you about a serious issue that breaks the safety flow when dealing with deep links. My React-Native version 0.71.8

Flow to reproduce.

  1. Setup React Navigation - https://reactnavigation.org

  2. Setup Deep links

  • https://reactnavigation.org/docs/deep-linking/
  • https://itsitdude.medium.com/react-native-navigation-flow-deep-linking-b91d3237baf7

When an unauthorized user tries to call a deep link for a private screen, the app should automatically redirect the user to the login screen. The getInitialURL method in the snippet below is responsible for preventing unauthorized users from visiting private screens.

import {Linking} from 'react-native';
import {restoreSession} from 'services/session';
import config from './config';
import {isPrivateRoute} from './utils';

const linking = {
  prefixes: ['reactnavigation://app', 'https://reactnavigation.org'],

  async getInitialURL() {
    try {
      const url = await Linking.getInitialURL();

      // check if URL is for private screen (screen for authorized users)
      if (isPrivateRoute(url || '')) {
        await restoreSession(); // restore user session before show private screen
      }

      return url;
    } catch (error) {
      return 'reactnavigation://app/onboarding'; // This is fallback address in a case when url is not registered for deep linking.
    }
  },

  subscribe(listener: any) {
    const linkingSubscription = Linking.addEventListener('url', async ({url}) => {
      try {
        // check if URL is for private screen (screen for authorized users)
        if (isPrivateRoute(url || '')) {
          await restoreSession(); // restore user session before show private screen
        }

        return listener(url);
      } catch (error) {
        return 'reactnavigation://app/onboarding'; // This is fallback address in a case when url is not registered for deep linking.
      }
    });

    return () => {
      linkingSubscription.remove();
    };
  },

  config,
};

export default linking;

This code works pretty good before injecting library react-native-splash-screen into ios/AppDelegeta.mm file.

Deep linking flow breaks once add a line [RNSplashScreen show] into AppDelegate.mm file.

BOOL didFinishLaunchingSuccess = [super application:application didFinishLaunchingWithOptions:launchOptions];

// Call [RNSplashScreen show] only after [super application:didFinishLaunchingWithOptions:]
[RNSplashScreen show]; 

return didFinishLaunchingSuccess;

Next line of code [RNSplashScreen show] breaks navigation mechanism inside of method async getInitialURL() {...}. Unauthorized users able to land to private screens.

By removing a line [RNSplashScreen show] from the ios/AppDelegate.mm file, the getInitialURL() method will prevent unauthorized users from visiting private screens.

The issue was reproduced in different projects with different React Native versions (0.70+) I was unable to test this issue with React Native versions below 0.70.

chukhlov avatar Jul 18 '23 22:07 chukhlov