mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-11 22:55:59 +05:45
* Adding error handling and returning correct error codes * * Handling auth cancellation a few other error cases * Adding some logging for EAP (Using NSLogs temporarily. DONOT MERGE) * Add in a setter for clientID to allow overrides (#5514) * Add in a setter for clientID to allow overrides * Update styling * Adding some result parsing logs * Fixing code hash logging * Add FirebaseAppDistribution to ZipBuilder * * Making sure keychain is accesible after first unlock even if app is backgrounded (#5563) * Fix auth persistence logging and invalid type casting (#5631) * Logging app id requesting releases (#5655) * AppDistribution keychain access fixes (#5683) * Using the GULKeychainUtils instead of custom keychain utility. Also added better logging * Updating keychain name and fixing tests * Code review feedback updates * Making serviceID unique per app * Adding gmp app id to the keychain along with the bundle id * Moving Keychain Utility functions in the AuthPersistence class and deleting the utility class * Lazy initialize auth state (#5755) * Lazy initialize auth state * Making sure we dont log an error is auth state is not persisted in the keychain * Switch from NSLog to FIRFADLogger (#5756) * Add FIRLogger * Switch from NSLog to FIRFADLogger * * Use FIS Auth for authenticating the tester * Remove AppAuth and start wiring up interceptor to do sign in * Extracting registration flow UI in interceptor * Adding support for iOS 9 and 10 * Create app distribution api service to handle tester api calls. (#6060) * Pull out calls to the FAD API to make them reuseable * Fix tests and run styl updates * Uncomment FIRFADLog Statements * Use [] accessor rather than . accessor * Re-running style updates * Trying to get these checks to pass the first time around * App distribution signin persist (#6063) * Pull out calls to the FAD API to make them reuseable * Fix tests and run styl updates * Add in UserDefaults storage after a tester has signed in * Add testing for the main AppDistribution file * Ran style.sh * Remove FIRFADLocalStorage and call GULUserDefaults directly. Update tests to stop mocking on teardown. * Add support for dynamic url schemes and fix two crashes (#6081) * Add support for dynamic url schemes and fix two crashes * Add support for dynamic url schemes in the format appdistribution-<app id without colons> * Fix crash when launching an app directly via a URL scheme * Fix a crash on iOS 10 simulator caused by calling NSLogv twice * Remove uses of NSLog * Fix warnings * Switch encodedAppId to be a class method * Fix styles * Create changelog and readme in preparation for release. (#6095) Just changing markdown files so will not wait for gha checks. * Change slices property from copy to strong (#6097) Fix lint warning * Change error handlers to return bool values instead of void (#6101) * Mapping sign in flow errors to app distribution errors. Also renaming AppDelegateInterceptor to FIRAppDistributionUIService (#6099) * Add github action for App Distribution (#6094) * Updating app distribution deployment target to iOS 9 (#6118) * Making sure we return granular errors during sign in persistence. Also fixing some naming and comment issues (#6117) * Encoding colons to dashes in the app id (#6119) * Move Internal headers to Sources (#6106) * Move Internal headers to Sources/ folder * PR feedback * Remove appDistribution from zip builder * Respond to code review feedback (#6138) * Initializing UIWindow using initWithWindowScene for ios 13 and removing UI code from main FIRAppDistribution.m (#6144) * Initializing UIWindow using initWithWindowScene for ios 13. Also making sure we only reset window in the App delegate if a registration flow is in progress. * Remove UI code from main class, add unit tests, and clean up UIService * stylish * Remove defines in favor of solely 'if (@available(iOS 13.0, *))' * Respond to code review feedback Co-authored-by: Cleo Schneider <cleoschneider@google.com> Co-authored-by: Pranav Rajgopal <pranavrajgopal@google.com> Co-authored-by: Cleo Schneider <cleoschneider@google.com>
202 lines
8.3 KiB
Objective-C
202 lines
8.3 KiB
Objective-C
// Copyright 2020 Google LLC
|
|
//
|
|
// 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 "FirebaseAppDistribution/Sources/FIRFADApiService.h"
|
|
#import <Foundation/Foundation.h>
|
|
#import "FirebaseAppDistribution/Sources/FIRFADLogger.h"
|
|
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
|
|
#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"
|
|
|
|
NSString *const kFIRFADApiErrorDomain = @"com.firebase.appdistribution.api";
|
|
NSString *const kFIRFADApiErrorDetailsKey = @"details";
|
|
NSString *const kHTTPGet = @"GET";
|
|
// The App Distribution Tester API endpoint used to retrieve releases
|
|
NSString *const kReleasesEndpointURLTemplate =
|
|
@"https://firebaseapptesters.googleapis.com/v1alpha/devices/"
|
|
@"-/testerApps/%@/installations/%@/releases";
|
|
NSString *const kInstallationAuthHeader = @"X-Goog-Firebase-Installations-Auth";
|
|
NSString *const kApiHeaderKey = @"X-Goog-Api-Key";
|
|
NSString *const kResponseReleasesKey = @"releases";
|
|
|
|
@implementation FIRFADApiService
|
|
|
|
+ (void)generateAuthTokenWithCompletion:(FIRFADGenerateAuthTokenCompletion)completion {
|
|
FIRInstallations *installations = [FIRInstallations installations];
|
|
|
|
// Get a FIS Authentication Token.
|
|
[installations authTokenWithCompletion:^(
|
|
FIRInstallationsAuthTokenResult *_Nullable authTokenResult,
|
|
NSError *_Nullable error) {
|
|
if ([self handleError:&error
|
|
description:@"Failed to generate Firebase Installation Auth Token."
|
|
code:FIRFADApiTokenGenerationFailure]) {
|
|
FIRFADErrorLog(@"Error getting fresh auth tokens. Error: %@", [error localizedDescription]);
|
|
|
|
completion(nil, nil, error);
|
|
return;
|
|
}
|
|
|
|
[installations installationIDWithCompletion:^(NSString *__nullable identifier,
|
|
NSError *__nullable error) {
|
|
if ([self handleError:&error
|
|
description:@"Failed to fetch Firebase Installation ID."
|
|
code:FIRFADApiInstallationIdentifierError]) {
|
|
FIRFADErrorLog(@"Error getting installation id. Error: %@", [error localizedDescription]);
|
|
|
|
completion(nil, nil, error);
|
|
|
|
return;
|
|
}
|
|
|
|
completion(identifier, authTokenResult, nil);
|
|
}];
|
|
}];
|
|
}
|
|
|
|
+ (NSMutableURLRequest *)createHTTPRequest:(NSString *)method
|
|
withUrl:(NSString *)urlString
|
|
withAuthToken:(FIRInstallationsAuthTokenResult *)authTokenResult {
|
|
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init];
|
|
|
|
FIRFADInfoLog(@"Requesting releases for app id - %@", [[FIRApp defaultApp] options].googleAppID);
|
|
[request setURL:[NSURL URLWithString:urlString]];
|
|
[request setHTTPMethod:method];
|
|
[request setValue:authTokenResult.authToken forHTTPHeaderField:kInstallationAuthHeader];
|
|
[request setValue:[[FIRApp defaultApp] options].APIKey forHTTPHeaderField:kApiHeaderKey];
|
|
return request;
|
|
}
|
|
|
|
+ (NSArray *)handleReleaseResponse:(NSData *)data
|
|
response:(NSURLResponse *)response
|
|
error:(NSError **_Nullable)error {
|
|
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
|
FIRFADInfoLog(@"HTTPResonse status code %ld response %@", (long)[httpResponse statusCode],
|
|
httpResponse);
|
|
|
|
if ([self handleHttpResponseError:httpResponse error:error]) {
|
|
FIRFADErrorLog(@"App Tester API service error - %@", [*error localizedDescription]);
|
|
return nil;
|
|
}
|
|
|
|
return [self parseApiResponseWithData:data error:error];
|
|
}
|
|
|
|
+ (void)fetchReleasesWithCompletion:(FIRFADFetchReleasesCompletion)completion {
|
|
void (^executeFetch)(NSString *_Nullable, FIRInstallationsAuthTokenResult *, NSError *_Nullable) =
|
|
^(NSString *_Nullable identifier, FIRInstallationsAuthTokenResult *authTokenResult,
|
|
NSError *_Nullable error) {
|
|
NSString *urlString =
|
|
[NSString stringWithFormat:kReleasesEndpointURLTemplate,
|
|
[[FIRApp defaultApp] options].googleAppID, identifier];
|
|
NSMutableURLRequest *request = [self createHTTPRequest:@"GET"
|
|
withUrl:urlString
|
|
withAuthToken:authTokenResult];
|
|
|
|
FIRFADInfoLog(@"Url : %@, Auth token: %@ API KEY: %@", urlString, authTokenResult.authToken,
|
|
[[FIRApp defaultApp] options].APIKey);
|
|
|
|
NSURLSessionDataTask *listReleasesDataTask = [[NSURLSession sharedSession]
|
|
dataTaskWithRequest:request
|
|
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
NSArray *releases = [self handleReleaseResponse:data
|
|
response:response
|
|
error:&error];
|
|
dispatch_async(dispatch_get_main_queue(), ^{
|
|
completion(releases, error);
|
|
});
|
|
}];
|
|
|
|
[listReleasesDataTask resume];
|
|
};
|
|
|
|
[self generateAuthTokenWithCompletion:executeFetch];
|
|
}
|
|
|
|
+ (BOOL)handleHttpResponseError:(NSHTTPURLResponse *)httpResponse error:(NSError **_Nullable)error {
|
|
if (*error || !httpResponse) {
|
|
return [self handleError:error
|
|
description:@"Unknown http error occurred"
|
|
code:FIRApiErrorUnknownFailure];
|
|
;
|
|
}
|
|
|
|
if ([httpResponse statusCode] != 200) {
|
|
*error = [self createErrorFromStatusCode:[httpResponse statusCode]];
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
+ (NSError *)createErrorFromStatusCode:(NSInteger)statusCode {
|
|
if (statusCode == 401) {
|
|
return [self createErrorWithDescription:@"Tester not authenticated."
|
|
code:FIRFADApiErrorUnauthenticated];
|
|
}
|
|
|
|
if (statusCode == 403 || statusCode == 400) {
|
|
return [self createErrorWithDescription:@"Tester not authorized."
|
|
code:FIRFADApiErrorUnauthorized];
|
|
}
|
|
|
|
if (statusCode == 404) {
|
|
return [self createErrorWithDescription:@"Tester or releases not found"
|
|
code:FIRFADApiErrorUnauthorized];
|
|
}
|
|
|
|
if (statusCode == 408 || statusCode == 504) {
|
|
return [self createErrorWithDescription:@"Request timeout." code:FIRFADApiErrorTimeout];
|
|
}
|
|
|
|
FIRFADErrorLog(@"Encountered unmapped status code: %ld", (long)statusCode);
|
|
NSString *description = [NSString stringWithFormat:@"Unknown status code: %ld", (long)statusCode];
|
|
return [self createErrorWithDescription:description code:FIRApiErrorUnknownFailure];
|
|
}
|
|
|
|
+ (BOOL)handleError:(NSError **_Nullable)error
|
|
description:(NSString *)description
|
|
code:(FIRFADApiError)code {
|
|
if (*error) {
|
|
*error = [self createErrorWithDescription:description code:code];
|
|
return YES;
|
|
}
|
|
|
|
return NO;
|
|
}
|
|
|
|
+ (NSError *)createErrorWithDescription:description code:(FIRFADApiError)code {
|
|
NSDictionary *userInfo = @{NSLocalizedDescriptionKey : description};
|
|
return [NSError errorWithDomain:kFIRFADApiErrorDomain code:code userInfo:userInfo];
|
|
}
|
|
|
|
+ (NSArray *_Nullable)parseApiResponseWithData:(NSData *)data error:(NSError **_Nullable)error {
|
|
NSDictionary *serializedResponse = [NSJSONSerialization JSONObjectWithData:data
|
|
options:0
|
|
error:error];
|
|
if (*error) {
|
|
FIRFADErrorLog(@"Tester API - Error deserializing json response");
|
|
NSString *description = (*error).userInfo[NSLocalizedDescriptionKey]
|
|
? (*error).userInfo[NSLocalizedDescriptionKey]
|
|
: @"Failed to parse response";
|
|
[self handleError:error description:description code:FIRApiErrorParseFailure];
|
|
|
|
return nil;
|
|
}
|
|
|
|
NSArray *releases = [serializedResponse objectForKey:kResponseReleasesKey];
|
|
|
|
return releases;
|
|
}
|
|
|
|
@end
|