Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

177469304: Firebase dynamic links with custom domain will only work if the custom domai has a trailing '/' #7087

Closed
nneverlander opened this issue Dec 3, 2020 · 14 comments · Fixed by #8672
Assignees

Comments

@nneverlander
Copy link

nneverlander commented Dec 3, 2020

[REQUIRED] Step 1: Describe your environment

  • Xcode version: 12.2
  • Firebase SDK version: 6.31.1
  • Installation method: CocoaPods (select one)
  • Firebase Component: DynamicLinks

[REQUIRED] Step 2: Describe the problem

Steps to reproduce:

Using a custom sub domain for dynamic links (like links.example.com) doesn't work. The piece of code below from the firebase library is checking for a trailing '/' at the end of the host. See the line:

if (urlStr.length > domainURIPrefixStr.length + 1 && ([urlStr characterAtIndex:domainURIPrefixStr.length] == '/'))

Why is this check necessary? This check will only allow custom domains that have a trailing '/'

Relevant Code:

BOOL FIRDLIsURLForWhiteListedCustomDomain(NSURL *_Nullable URL) {
  BOOL customDomainMatchFound = false;
  for (NSURL *allowedCustomDomain in FIRDLCustomDomains) {
    // All custom domain host names should match at a minimum.
    if ([allowedCustomDomain.host isEqualToString:URL.host]) {
      NSString *urlStr = URL.absoluteString;
      NSString *domainURIPrefixStr = allowedCustomDomain.absoluteString;

      // Next, do a string compare to check if entire domainURIPrefix matches as well.
      if (([URL.absoluteString rangeOfString:allowedCustomDomain.absoluteString
                                     options:NSCaseInsensitiveSearch | NSAnchoredSearch]
               .location) == 0) {
        // The (short) URL needs to be longer than the domainURIPrefix, it's first character after
        // the domainURIPrefix needs to be '/' and should be followed by at-least one more
        // character.
        if (urlStr.length > domainURIPrefixStr.length + 1 &&
            ([urlStr characterAtIndex:domainURIPrefixStr.length] == '/')) {
          // Check if there are any more '/' after the first '/'trailing the
          // domainURIPrefix. This does not apply to unique match links copied from the clipboard.
          // The clipboard links will have '?link=' after the domainURIPrefix.
          NSString *urlWithoutDomainURIPrefix =
              [urlStr substringFromIndex:domainURIPrefixStr.length + 1];
          if ([urlWithoutDomainURIPrefix rangeOfString:@"/"].location == NSNotFound ||
              [urlWithoutDomainURIPrefix rangeOfString:@"?link="].location != NSNotFound) {
            customDomainMatchFound = true;
            break;
          }
        }
      }
    }
  }
  return customDomainMatchFound;
}
@google-oss-bot
Copy link

I found a few problems with this issue:

  • I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
  • This issue does not seem to follow the issue template. Make sure you provide all the required information.
@nneverlander
Copy link
Author

nneverlander commented Dec 3, 2020

I am using dynamic links to send password reset emails with a custom domain. The generated link in the email looks like this:

https://links.example.com?link=https://example.com/__/auth/action?apiKey%abc%26mode%3DresetPassword%26oobCode%3D9OsQMmdKAPo6J7RRO2bAUMYTV3TEzReToKJpSy-xSWcAAAF2KLCPsw%26continueUrl%3Dhttps://example.com/__/auth/action%26lang%3Den&ibi=com.example.ios&ifl=https://example.com/__/auth/action?apiKey%abc%26mode%3DresetPassword%26oobCode%3D9OsQMmdKAPo6J7RRO2bAUMYTV3TEzReToKJpSy-xSWcAAAF2KLCPsw%26continueUrl%3Dhttps://example.com/__/auth/action%26lang%3Den

The link doesn't have a trailing '/' causing the SDK to fail the customDomainMatchFound check.

@Kaspik
Copy link

Kaspik commented Dec 4, 2020

I believe the same applies to Google Analytics logging automatically query params.

Universal link https://www.domain.com/someLink?utm_source=email&utm_medium=email&utm_campaign=campaign
doesn't work where
Universal link https://www.domain.com/someLink/?utm_source=email&utm_medium=email&utm_campaign=campaign
does work

@paulb777 Is this intended? If not, should I open another issue, or is it related?

@nneverlander
Copy link
Author

nneverlander commented Dec 4, 2020 via email

@eldhosembabu
Copy link
Contributor

Internal bug created and will be prioritizing and looking into it: b/177469304

@eldhosembabu eldhosembabu changed the title Firebase dynamic links with custom domain will only work if the custom domai has a trailing '/' Jan 13, 2021
@reimertz
Copy link

Oh man, I've spent days trying to figure out why email sign in links worked fine in Apple Mail but no other email client.

Eventually went deep and logged the incoming url and somehow slash was missing even thought they weren't when manually copied. I assume iOS applies missing slash when copied?.

Anyhow, It's been 2 months since this was filed and is currently breaking email passwordless registrations for iOS users.
So please please, prioritize this some more! <3

@reimertz
Copy link

reimertz commented Feb 21, 2021

For me to get around this issue, I added a temp hack to handleUniversalLink:

- (BOOL)handleUniversalLink:(NSURL *)universalLinkURL
                 completion:(FIRDynamicLinkUniversalLinkHandler)completion {
                   
    NSString *slashedString = [universalLinkURL.absoluteString stringByReplacingOccurrencesOfString:@"ENTER_YOUR_CUSTOM_DOMAIN_HERE?link=" 
      withString:@"ENTER_YOUR_CUSTOM_DOMAIN_HERE/?link="];
    NSURL *fixedUniversalLinkURL = [NSURL URLWithString:slashedString];

  if ([self matchesShortLinkFormat:fixedUniversalLinkURL]) {
    __weak __typeof__(self) weakSelf = self;
    [self resolveShortLink:fixedUniversalLinkURL
                completion:^(NSURL *url, NSError *error) {
                  __typeof__(self) strongSelf = weakSelf;
                  if (strongSelf) {
                    FIRDynamicLink *dynamicLink = [strongSelf dynamicLinkFromCustomSchemeURL:url];
                    dispatch_async(dispatch_get_main_queue(), ^{
                      completion(dynamicLink, error);
                    });
                  } else {
                    completion(nil, nil);
                  }
                }];
    return YES;
  } else {
    [self dynamicLinkFromUniversalLinkURL:fixedUniversalLinkURL completion:completion];
    BOOL canHandleUniversalLink =
        [self canParseUniversalLinkURL:fixedUniversalLinkURL] && fixedUniversalLinkURL.query.length > 0 &&
        FIRDLDictionaryFromQuery(universalLinkURL.query)[kFIRDLParameterLink];
    return canHandleUniversalLink;
  }
}
    ```
@rkbhochalya
Copy link

I just wanted to add that sign-in links work from other email apps on iOS if a Google-provided domain (e.g. projectname.page.link) is used to generate sign-in links. This can be used as a workaround in some cases.

I have a working example react-native app with a Google-provided domain here.

@jonasN5
Copy link

jonasN5 commented Apr 10, 2021

Can you please fix this???? I've just lost a whole day until I debugged the problem myself and searched for this open issue. This completely blocks custom domains...

@allanwolski
Copy link

allanwolski commented Apr 13, 2021

@kaciula
Copy link

kaciula commented Jul 2, 2021

@reimertz Hi. I'm having the same problem and I would like to apply your workaround. I've created a local copy of the FirebaseDynamicLinks pod directory, I've modified the handleUniversalLink method and I'm pointing to this local pod inside the main Podfile. Not sure how to write the podspec for the local pod however.

Can you help with some basic steps of using a custom local pod of FirebaseDynamicLinks?

(I'm a Flutter developer so I am not very familiar with how pods work on ios.)

@ygotthilf
Copy link

ygotthilf commented Jul 28, 2021

I've also spent the whole day trying to figure out why deep link is not triggered by my app from GMail iOS App.

@movvam
Copy link

movvam commented Aug 31, 2021

exactly same^

@eldhosembabu
Copy link
Contributor

This seems like purposefully introduced in PR: #2563

eldhosembabu added a commit that referenced this issue Sep 22, 2021
[FDL] Refactoring and fixing url validation

Refactored the existing code to use Regex to validate FDL URL formats.

Added checks to make sure the 'link' query param is having an http/https prefix input.
== This is going to be breaking the existing SDK's unintended behavior to support links with non http/https content. The existing SDK was constructing the Dynamic link even though the backend response to resolve the link is not successful.

Added support for URL(s) with Query string starting with '?' alone. Previously it was supporting '/?' formats only. This fixes 177469304: Firebase dynamic links with custom domain will only work if the custom domain has a trailing '/' #7087

Added more test cases to be in sync with FDL backend validation.

Removed invalid test inputs and corrected few test cases to make the input in proper format.
@firebase firebase locked and limited conversation to collaborators Oct 23, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.