aboutsummaryrefslogtreecommitdiffhomepage
path: root/Firebase/Auth
diff options
context:
space:
mode:
authorGravatar Paul Beusterien <paulbeusterien@google.com>2018-04-24 16:19:11 -0700
committerGravatar GitHub <noreply@github.com>2018-04-24 16:19:11 -0700
commit83b519f0a53a2efc946b32b1708d882a34f30d3a (patch)
tree57ec0e02b22e9b59d7d5976a83df6f4701620995 /Firebase/Auth
parent6a432ad6281c8f387e643757aba12d616f6757fd (diff)
Remove GTM dependency from FirebaseAuth (#1175)
Diffstat (limited to 'Firebase/Auth')
-rw-r--r--Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m80
-rw-r--r--Firebase/Auth/Source/FIRAuthWebUtils.h80
-rw-r--r--Firebase/Auth/Source/FIRAuthWebUtils.m134
-rw-r--r--Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m30
4 files changed, 277 insertions, 47 deletions
diff --git a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m
index a44a340..948a515 100644
--- a/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m
+++ b/Firebase/Auth/Source/AuthProviders/Phone/FIRPhoneAuthProvider.m
@@ -16,8 +16,6 @@
#import "FIRPhoneAuthProvider.h"
-#import <GoogleToolboxForMac/GTMNSDictionary+URLArguments.h>
-
#import <FirebaseCore/FIRLogger.h>
#import "FIRPhoneAuthCredential_Internal.h"
#import <FirebaseCore/FIRApp.h>
@@ -31,6 +29,7 @@
#import "FIRAuthNotificationManager.h"
#import "FIRAuthErrorUtils.h"
#import "FIRAuthBackend.h"
+#import "FIRAuthWebUtils.h"
#import "FirebaseAuthVersion.h"
#import <FirebaseCore/FIROptions.h>
#import "FIRGetProjectConfigRequest.h"
@@ -78,7 +77,7 @@ static NSString *const kAuthTypeVerifyApp = @"verifyApp";
/** @var kReCAPTCHAURLStringFormat
@brief The format of the URL used to open the reCAPTCHA page during app verification.
*/
-NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?%@";
+NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?";
@implementation FIRPhoneAuthProvider {
@@ -244,15 +243,22 @@ NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?%@";
@return The reCAPTCHA token if successful.
*/
- (NSString *)reCAPTCHATokenForURL:(NSURL *)URL error:(NSError **)error {
- NSDictionary<NSString *, NSString *> *URLQueryItems =
- [NSDictionary gtm_dictionaryWithHttpArgumentsString:URL.query];
- NSURL *deepLinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]];
- URLQueryItems =
- [NSDictionary gtm_dictionaryWithHttpArgumentsString:deepLinkURL.query];
- if (URLQueryItems[@"recaptchaToken"]) {
- return URLQueryItems[@"recaptchaToken"];
+ NSURLComponents *actualURLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
+ NSArray<NSURLQueryItem *> *queryItems = [actualURLComponents queryItems];
+ NSString *deepLinkURL = [FIRAuthWebUtils queryItemValue:@"deep_link_id" from:queryItems];
+ NSData *errorData;
+ if (deepLinkURL) {
+ actualURLComponents = [NSURLComponents componentsWithString:deepLinkURL];
+ queryItems = [actualURLComponents queryItems];
+ NSString *recaptchaToken = [FIRAuthWebUtils queryItemValue:@"recaptchaToken" from:queryItems];
+ if (recaptchaToken) {
+ return recaptchaToken;
+ }
+ NSString *firebaseError = [FIRAuthWebUtils queryItemValue:@"firebaseError" from:queryItems];
+ errorData = [firebaseError dataUsingEncoding:NSUTF8StringEncoding];
+ } else {
+ errorData = nil;
}
- NSData *errorData = [URLQueryItems[@"firebaseError"] dataUsingEncoding:NSUTF8StringEncoding];
NSError *jsonError;
NSDictionary *errorDict = [NSJSONSerialization JSONObjectWithData:errorData
options:0
@@ -298,13 +304,19 @@ NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?%@";
if (!([[expectedURLComponents URL] isEqual:[actualURLComponents URL]])) {
return NO;
}
- NSDictionary<NSString *, NSString *> *URLQueryItems =
- [NSDictionary gtm_dictionaryWithHttpArgumentsString:URL.query];
- NSURL *deeplinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]];
- NSDictionary<NSString *, NSString *> *deeplinkQueryItems =
- [NSDictionary gtm_dictionaryWithHttpArgumentsString:deeplinkURL.query];
- if ([deeplinkQueryItems[@"authType"] isEqualToString:kAuthTypeVerifyApp] &&
- [deeplinkQueryItems[@"eventId"] isEqualToString:eventID]) {
+ actualURLComponents = [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
+ NSArray<NSURLQueryItem *> *queryItems = [actualURLComponents queryItems];
+ NSString *deepLinkURL = [FIRAuthWebUtils queryItemValue:@"deep_link_id" from:queryItems];
+ if (deepLinkURL == nil) {
+ return NO;
+ }
+ NSURLComponents *deepLinkURLComponents = [NSURLComponents componentsWithString:deepLinkURL];
+ NSArray<NSURLQueryItem *> *deepLinkQueryItems = [deepLinkURLComponents queryItems];
+
+ NSString *deepLinkAuthType = [FIRAuthWebUtils queryItemValue:@"authType" from:deepLinkQueryItems];
+ NSString *deepLinkEventID = [FIRAuthWebUtils queryItemValue:@"eventId" from:deepLinkQueryItems];
+ if ([deepLinkAuthType isEqualToString:kAuthTypeVerifyApp] &&
+ [deepLinkEventID isEqualToString:eventID]) {
return YES;
}
return NO;
@@ -444,27 +456,29 @@ NSString *const kReCAPTCHAURLStringFormat = @"https://%@/__/auth/handler?%@";
return;
}
NSString *bundleID = [NSBundle mainBundle].bundleIdentifier;
- NSString *clienID = self->_auth.app.options.clientID;
+ NSString *clientID = self->_auth.app.options.clientID;
NSString *apiKey = self->_auth.requestConfiguration.APIKey;
- NSMutableDictionary *urlArguments = [[NSMutableDictionary alloc] initWithDictionary: @{
- @"apiKey" : apiKey,
- @"authType" : kAuthTypeVerifyApp,
- @"ibi" : bundleID ?: @"",
- @"clientId" : clienID,
- @"v" : [FIRAuthBackend authUserAgent],
- @"eventId" : eventID,
- }];
+ NSMutableArray<NSURLQueryItem *> *queryItems = [@[
+ [NSURLQueryItem queryItemWithName:@"apiKey" value:apiKey],
+ [NSURLQueryItem queryItemWithName:@"authType" value:kAuthTypeVerifyApp],
+ [NSURLQueryItem queryItemWithName:@"ibi" value:bundleID ?: @""],
+ [NSURLQueryItem queryItemWithName:@"clientId" value:clientID],
+ [NSURLQueryItem queryItemWithName:@"v" value:[FIRAuthBackend authUserAgent]],
+ [NSURLQueryItem queryItemWithName:@"eventId" value:eventID]
+ ] mutableCopy
+ ];
+
if (self->_auth.requestConfiguration.languageCode) {
- urlArguments[@"hl"] = self->_auth.requestConfiguration.languageCode;
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:@"hl"value:
+ self->_auth.requestConfiguration.languageCode]];
}
- NSString *argumentsString = [urlArguments gtm_httpArgumentsString];
- NSString *URLString =
- [NSString stringWithFormat:kReCAPTCHAURLStringFormat, authDomain, argumentsString];
- completion([NSURL URLWithString:URLString], nil);
+ NSURLComponents *components = [[NSURLComponents alloc] initWithString:
+ [NSString stringWithFormat:kReCAPTCHAURLStringFormat, authDomain]];
+ [components setQueryItems:queryItems];
+ completion([components URL], nil);
}];
}
-
/** @fn fetchAuthDomainWithCompletion:completion:
@brief Fetches the auth domain associated with the Firebase Project.
@param completion The callback invoked after the auth domain has been constructed or an error
diff --git a/Firebase/Auth/Source/FIRAuthWebUtils.h b/Firebase/Auth/Source/FIRAuthWebUtils.h
new file mode 100644
index 0000000..fe1c29a
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthWebUtils.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import <Foundation/Foundation.h>
+
+@class FIRAuthRequestConfiguration;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/** @typedef FIRFetchAuthDomainCallback
+ @brief The callback invoked at the end of the flow to fetch the Auth domain.
+ @param authDomain The Auth domain.
+ @param error The error that occured while fetching the auth domain, if any.
+ */
+typedef void (^FIRFetchAuthDomainCallback)(NSString *_Nullable authDomain,
+ NSError *_Nullable error);
+
+/** @class FIRAuthURLUtils
+ @brief A utility class used to facilitate the creation of auth related URLs.
+ */
+@interface FIRAuthWebUtils : NSObject
+
+/** @fn randomStringWithLength:
+ @brief Generates a random string of a specified length.
+ */
++ (NSString *)randomStringWithLength:(NSUInteger)length;
+
+/** @fn isCallbackSchemeRegisteredForCustomURLScheme:
+ @brief Checks whether or not the provided custom URL scheme has been registered by the app.
+ @param URLScheme The custom URL scheme to be checked against all custom URL schemes registered by the app.
+ @return whether or not the provided custom URL scheme has been registered by the app.
+ */
++ (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme;
+
+/** @fn isExpectedCallbackURL:eventID:authType
+ @brief Parses a URL into all available query items.
+ @param URL The actual callback URL.
+ @param eventID The expected event ID.
+ @param authType The expected auth type.
+ @param callbackScheme The expected callback custom scheme.
+ @return Whether or not the actual callback URL matches the expected callback URL.
+ */
++ (BOOL)isExpectedCallbackURL:(nullable NSURL *)URL
+ eventID:(NSString *)eventID
+ authType:(NSString *)authType
+ callbackScheme:(NSString *)callbackScheme;
+
+/** @fn fetchAuthDomainWithCompletion:completion:
+ @brief Fetches the auth domain associated with the Firebase Project.
+ @param completion The callback invoked after the auth domain has been constructed or an error
+ has been encountered.
+ */
++ (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
+ completion:(FIRFetchAuthDomainCallback)completion;
+
+/** @fn queryItemValue:from:
+ @brief Utility function to get a value from a NSURLQueryItem array.
+ @param name The key.
+ @param queryList The NSURLQueryItem array.
+ @return The value for the key.
+ */
+
++ (NSString *)queryItemValue:(NSString *)name from:(NSArray<NSURLQueryItem *> *)queryList;
+
+@end
+
+NS_ASSUME_NONNULL_END \ No newline at end of file
diff --git a/Firebase/Auth/Source/FIRAuthWebUtils.m b/Firebase/Auth/Source/FIRAuthWebUtils.m
new file mode 100644
index 0000000..d694a06
--- /dev/null
+++ b/Firebase/Auth/Source/FIRAuthWebUtils.m
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2018 Google
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#import "FIRAuthWebUtils.h"
+
+#import <GoogleToolboxForMac/GTMNSDictionary+URLArguments.h>
+
+#import "FIRAuthBackend.h"
+#import "FIRAuthErrorUtils.h"
+#import "FIRGetProjectConfigRequest.h"
+#import "FIRGetProjectConfigResponse.h"
+
+/** @var kAuthDomainSuffix
+ @brief The suffix of the auth domain pertiaining to a given Firebase project.
+ */
+static NSString *const kAuthDomainSuffix = @"firebaseapp.com";
+
+@implementation FIRAuthWebUtils
+
++ (NSString *)randomStringWithLength:(NSUInteger)length {
+ NSMutableString *randomString = [[NSMutableString alloc] init];
+ for (int i=0; i < length; i++) {
+ [randomString appendString:
+ [NSString stringWithFormat:@"%c", 'a' + arc4random_uniform('z' - 'a' + 1)]];
+ }
+ return randomString;
+}
+
++ (BOOL)isCallbackSchemeRegisteredForCustomURLScheme:(NSString *)URLScheme {
+ NSString *expectedCustomScheme = [URLScheme lowercaseString];
+ NSArray *urlTypes = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleURLTypes"];
+ for (NSDictionary *urlType in urlTypes) {
+ NSArray *urlTypeSchemes = urlType[@"CFBundleURLSchemes"];
+ for (NSString *urlTypeScheme in urlTypeSchemes) {
+ if ([urlTypeScheme.lowercaseString isEqualToString:expectedCustomScheme]) {
+ return YES;
+ }
+ }
+ }
+ return NO;
+}
+
++ (BOOL)isExpectedCallbackURL:(NSURL *)URL
+ eventID:(NSString *)eventID
+ authType:(NSString *)authType
+ callbackScheme:(NSString *)callbackScheme {
+ if (!URL) {
+ return NO;
+ }
+ NSURLComponents *actualURLComponents =
+ [NSURLComponents componentsWithURL:URL resolvingAgainstBaseURL:NO];
+ actualURLComponents.query = nil;
+ actualURLComponents.fragment = nil;
+
+ NSURLComponents *expectedURLComponents = [NSURLComponents new];
+ expectedURLComponents.scheme = callbackScheme;
+ expectedURLComponents.host = @"firebaseauth";
+ expectedURLComponents.path = @"/link";
+
+ if (!([[expectedURLComponents URL] isEqual:[actualURLComponents URL]])) {
+ return NO;
+ }
+ NSDictionary<NSString *, NSString *> *URLQueryItems =
+ [NSDictionary gtm_dictionaryWithHttpArgumentsString:URL.query];
+ NSURL *deeplinkURL = [NSURL URLWithString:URLQueryItems[@"deep_link_id"]];
+ NSDictionary<NSString *, NSString *> *deeplinkQueryItems =
+ [NSDictionary gtm_dictionaryWithHttpArgumentsString:deeplinkURL.query];
+ if ([deeplinkQueryItems[@"authType"] isEqualToString:authType] &&
+ [deeplinkQueryItems[@"eventId"] isEqualToString:eventID]) {
+ return YES;
+ }
+ return NO;
+}
+
++ (void)fetchAuthDomainWithRequestConfiguration:(FIRAuthRequestConfiguration *)requestConfiguration
+ completion:(FIRFetchAuthDomainCallback)completion {
+ FIRGetProjectConfigRequest *request =
+ [[FIRGetProjectConfigRequest alloc] initWithRequestConfiguration:requestConfiguration];
+
+ [FIRAuthBackend getProjectConfig:request
+ callback:^(FIRGetProjectConfigResponse *_Nullable response,
+ NSError *_Nullable error) {
+ if (error) {
+ completion(nil, error);
+ return;
+ }
+ NSString *authDomain;
+ for (NSString *domain in response.authorizedDomains) {
+ NSInteger index = domain.length - kAuthDomainSuffix.length;
+ if (index >= 2) {
+ if ([domain hasSuffix:kAuthDomainSuffix] && domain.length >= kAuthDomainSuffix.length + 2) {
+ authDomain = domain;
+ break;
+ }
+ }
+ }
+ if (!authDomain.length) {
+ completion(nil, [FIRAuthErrorUtils unexpectedErrorResponseWithDeserializedResponse:response]);
+ return;
+ }
+ completion(authDomain, nil);
+ }];
+}
+
+/** @fn queryItemValue:from:
+ @brief Utility function to get a value from a NSURLQueryItem array.
+ @param name The key.
+ @param queryList The NSURLQueryItem array.
+ @return The value for the key.
+ */
+
++ (NSString *)queryItemValue:(NSString *)name from:(NSArray<NSURLQueryItem *> *)queryList {
+ for (NSURLQueryItem *item in queryList) {
+ if ([item.name isEqualToString:name]) {
+ return item.value;
+ }
+ }
+ return nil;
+}
+
+@end \ No newline at end of file
diff --git a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m
index 2251c42..274fd07 100644
--- a/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m
+++ b/Firebase/Auth/Source/RPCs/FIRVerifyAssertionRequest.m
@@ -16,9 +16,6 @@
#import "FIRVerifyAssertionRequest.h"
-#import <GoogleToolboxForMac/GTMNSData+zlib.h>
-#import <GoogleToolboxForMac/GTMNSDictionary+URLArguments.h>
-
/** @var kVerifyAssertionEndpoint
@brief The "verifyAssertion" endpoint.
*/
@@ -95,16 +92,19 @@ static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
}
- (nullable id)unencodedHTTPRequestBodyWithError:(NSError *_Nullable *_Nullable)error {
- NSMutableDictionary *postBody = [@{
- kProviderIDKey : _providerID,
- } mutableCopy];
+ NSURLComponents *components = [[NSURLComponents alloc] init];
+ NSMutableArray<NSURLQueryItem *> *queryItems = [@[[NSURLQueryItem queryItemWithName:kProviderIDKey
+ value:_providerID]]
+ mutableCopy];
if (_providerIDToken) {
- postBody[kProviderIDTokenKey] = _providerIDToken;
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderIDTokenKey
+ value:_providerIDToken]];
}
if (_providerAccessToken) {
- postBody[kProviderAccessTokenKey] = _providerAccessToken;
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderAccessTokenKey
+ value:_providerAccessToken]];
}
if (!_providerIDToken && !_providerAccessToken) {
@@ -113,17 +113,19 @@ static NSString *const kReturnSecureTokenKey = @"returnSecureToken";
}
if (_providerOAuthTokenSecret) {
- postBody[kProviderOAuthTokenSecretKey] = _providerOAuthTokenSecret;
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:kProviderOAuthTokenSecretKey
+ value:_providerOAuthTokenSecret]];
}
if (_inputEmail) {
- postBody[kIdentifierKey] = _inputEmail;
+ [queryItems addObject:[NSURLQueryItem queryItemWithName:kIdentifierKey
+ value:_inputEmail]];
}
-
+ [components setQueryItems:queryItems];
NSMutableDictionary *body = [@{
- kRequestURIKey : @"http://localhost", // Unused by server, but required
- kPostBodyKey : [postBody gtm_httpArgumentsString]
- } mutableCopy];
+ kRequestURIKey : @"http://localhost", // Unused by server, but required
+ kPostBodyKey : [components query]
+ } mutableCopy];
if (_pendingIDToken) {
body[kPendingIDTokenKey] = _pendingIDToken;