Nav apraksta

FIRAuthWebUtils.m 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /*
  2. * Copyright 2018 Google
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. #import "FIRAuthWebUtils.h"
  17. #import "FIRAuthBackend.h"
  18. #import "FIRAuthErrorUtils.h"
  19. #import "FIRGetProjectConfigRequest.h"
  20. #import "FIRGetProjectConfigResponse.h"
  21. NS_ASSUME_NONNULL_BEGIN
  22. /** @var kAuthDomainSuffix
  23. @brief The suffix of the auth domain pertiaining to a given Firebase project.
  24. */
  25. static NSString *const kAuthDomainSuffix = @"firebaseapp.com";
  26. @implementation FIRAuthWebUtils
  27. + (NSString *)randomStringWithLength:(NSUInteger)length {
  28. NSMutableString *randomString = [[NSMutableString alloc] init];
  29. for (int i=0; i < length; i++) {
  30. [randomString appendString:
  31. [NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]];
  32. }
  33. return randomString;
  34. }
  35. + (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme {
  36. NSString *expectedCustomScheme = [URLScheme lowercaseString];
  37. NSArray *urlTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];
  38. for (NSDictionary *urlType in urlTypes) {
  39. NSArray *urlTypeSchemes = urlType[@"CFBundleURLSchemes"];
  40. for (NSString *urlTypeScheme in urlTypeSchemes) {
  41. if ([urlTypeScheme.lowercaseString isEqualToString:expectedCustomScheme]) {
  42. return YES;
  43. }
  44. }
  45. }
  46. return NO;
  47. }
  48. + (BOOL)isExpectedCallbackURL:(nullable NSURL *)URL
  49. eventID:(NSString *)eventID
  50. authType:(NSString *)authType
  51. callbackScheme:(NSString *)callbackScheme {
  52. if (!URL) {
  53. return NO;
  54. }
  55. NSURLComponents *actualURLComponents =
  56. [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
  57. actualURLComponents.query = nil;
  58. actualURLComponents.fragment = nil;
  59. NSURLComponents *expectedURLComponents = [[NSURLComponents alloc] init];
  60. expectedURLComponents.scheme = callbackScheme;
  61. expectedURLComponents.host = @"firebaseauth";
  62. expectedURLComponents.path = @"/link";
  63. if (![expectedURLComponents.URL isEqual:actualURLComponents.URL]) {
  64. return NO;
  65. }
  66. NSDictionary<NSString *, NSString *> *URLQueryItems =
  67. [self dictionaryWithHttpArgumentsString:URL.query];
  68. NSURL *deeplinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]];
  69. NSDictionary<NSString *, NSString *> *deeplinkQueryItems =
  70. [self dictionaryWithHttpArgumentsString:deeplinkURL.query];
  71. if ([deeplinkQueryItems[@"authType"] isEqualToString:authType] &&
  72. [deeplinkQueryItems[@"eventId"] isEqualToString:eventID]) {
  73. return YES;
  74. }
  75. return NO;
  76. }
  77. + (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
  78. completion:(FIRFetchAuthDomainCallback)completion {
  79. FIRGetProjectConfigRequest *request =
  80. [[FIRGetProjectConfigRequest alloc] initWithRequestConfiguration:requestConfiguration];
  81. [FIRAuthBackend getProjectConfig:request
  82. callback:^(FIRGetProjectConfigResponse *_Nullable response,
  83. NSError *_Nullable error) {
  84. if (error) {
  85. completion(nil, error);
  86. return;
  87. }
  88. NSString *authDomain;
  89. for (NSString *domain in response.authorizedDomains) {
  90. NSInteger index = domain.length - kAuthDomainSuffix.length;
  91. if (index >= 2) {
  92. if ([domain hasSuffix:kAuthDomainSuffix] && domain.length >= kAuthDomainSuffix.length + 2) {
  93. authDomain = domain;
  94. break;
  95. }
  96. }
  97. }
  98. if (!authDomain.length) {
  99. completion(nil, [FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:response]);
  100. return;
  101. }
  102. completion(authDomain, nil);
  103. }];
  104. }
  105. /** @fn queryItemValue:from:
  106. @brief Utility function to get a value from a NSURLQueryItem array.
  107. @param name The key.
  108. @param queryList The NSURLQueryItem array.
  109. @return The value for the key.
  110. */
  111. + (nullable NSString *)queryItemValue:(NSString *)name from:(NSArray<NSURLQueryItem *> *)queryList {
  112. for (NSURLQueryItem *item in queryList) {
  113. if ([item.name isEqualToString:name]) {
  114. return item.value;
  115. }
  116. }
  117. return nil;
  118. }
  119. + (NSDictionary *)dictionaryWithHttpArgumentsString:(NSString *)argString {
  120. NSMutableDictionary* ret = [NSMutableDictionary dictionary];
  121. NSArray* components = [argString componentsSeparatedByString:@"&"];
  122. NSString* component;
  123. // Use reverse order so that the first occurrence of a key replaces
  124. // those subsequent.
  125. for (component in [components reverseObjectEnumerator]) {
  126. if (component.length == 0)
  127. continue;
  128. NSRange pos = [component rangeOfString:@"="];
  129. NSString *key;
  130. NSString *val;
  131. if (pos.location == NSNotFound) {
  132. key = [self stringByUnescapingFromURLArgument:component];
  133. val = @"";
  134. } else {
  135. key = [self stringByUnescapingFromURLArgument:[component substringToIndex:pos.location]];
  136. val = [self stringByUnescapingFromURLArgument:
  137. [component substringFromIndex:pos.location + pos.length]];
  138. }
  139. // returns nil on invalid UTF8 and NSMutableDictionary raises an exception when passed nil
  140. // values.
  141. if (!key) key = @"";
  142. if (!val) val = @"";
  143. [ret setObject:val forKey:key];
  144. }
  145. return ret;
  146. }
  147. + (NSString *)stringByUnescapingFromURLArgument:(NSString *)argument {
  148. NSMutableString *resultString = [NSMutableString stringWithString:argument];
  149. [resultString replaceOccurrencesOfString:@"+"
  150. withString:@" "
  151. options:NSLiteralSearch
  152. range:NSMakeRange(0, [resultString length])];
  153. return [resultString stringByRemovingPercentEncoding];
  154. }
  155. @end
  156. NS_ASSUME_NONNULL_END