diff options
Diffstat (limited to 'platform/ios/src/MGLAPIClient.m')
-rw-r--r-- | platform/ios/src/MGLAPIClient.m | 202 |
1 files changed, 0 insertions, 202 deletions
diff --git a/platform/ios/src/MGLAPIClient.m b/platform/ios/src/MGLAPIClient.m deleted file mode 100644 index 8a987d76d8..0000000000 --- a/platform/ios/src/MGLAPIClient.m +++ /dev/null @@ -1,202 +0,0 @@ -#import "MGLAPIClient.h" -#import "NSBundle+MGLAdditions.h" -#import "NSData+MGLAdditions.h" -#import "MGLAccountManager.h" - -static NSString * const MGLAPIClientUserAgentBase = @"MapboxEventsiOS"; -static NSString * const MGLAPIClientBaseURL = @"https://events.mapbox.com"; -static NSString * const MGLAPIClientEventsPath = @"events/v2"; - -static NSString * const MGLAPIClientHeaderFieldUserAgentKey = @"User-Agent"; -static NSString * const MGLAPIClientHeaderFieldContentTypeKey = @"Content-Type"; -static NSString * const MGLAPIClientHeaderFieldContentTypeValue = @"application/json"; -static NSString * const MGLAPIClientHeaderFieldContentEncodingKey = @"Content-Encoding"; -static NSString * const MGLAPIClientHTTPMethodPost = @"POST"; - -@interface MGLAPIClient () - -@property (nonatomic, copy) NSURLSession *session; -@property (nonatomic, copy) NSURL *baseURL; -@property (nonatomic, copy) NSData *digicertCert_2016; -@property (nonatomic, copy) NSData *geoTrustCert_2016; -@property (nonatomic, copy) NSData *digicertCert_2017; -@property (nonatomic, copy) NSData *geoTrustCert_2017; -@property (nonatomic, copy) NSData *testServerCert; -@property (nonatomic, copy) NSString *userAgent; -@property (nonatomic) BOOL usesTestServer; - -@end - -@implementation MGLAPIClient - -- (instancetype)init { - self = [super init]; - if (self) { - _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] - delegate:self delegateQueue:nil]; - [self loadCertificates]; - [self setupBaseURL]; - [self setupUserAgent]; - } - return self; -} - -#pragma mark Public API - -- (void)postEvents:(nonnull NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler { - __block NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self requestForEvents:events] - completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) { - NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - NSError *statusError = nil; - if (httpResponse.statusCode >= 400) { - NSString *description = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"API_CLIENT_400_DESC", nil, nil, @"The session data task failed. Original request was: %@", nil), dataTask.originalRequest]; - NSString *reason = [NSString stringWithFormat:NSLocalizedStringWithDefaultValue(@"API_CLIENT_400_REASON", nil, nil, @"The status code was %ld", nil), (long)httpResponse.statusCode]; - NSDictionary *userInfo = @{NSLocalizedDescriptionKey: description, - NSLocalizedFailureReasonErrorKey: reason}; - statusError = [NSError errorWithDomain:MGLErrorDomain code:1 userInfo:userInfo]; - } - if (completionHandler) { - error = error ?: statusError; - completionHandler(error); - } - dataTask = nil; - }]; - [dataTask resume]; -} - -- (void)postEvent:(nonnull MGLMapboxEventAttributes *)event completionHandler:(nullable void (^)(NSError * _Nullable error))completionHandler { - [self postEvents:@[event] completionHandler:completionHandler]; -} - -#pragma mark Utilities - -- (NSURLRequest *)requestForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { - NSString *path = [NSString stringWithFormat:@"%@?access_token=%@", MGLAPIClientEventsPath, [MGLAccountManager accessToken]]; - NSURL *url = [NSURL URLWithString:path relativeToURL:self.baseURL]; - NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; - [request setValue:self.userAgent forHTTPHeaderField:MGLAPIClientHeaderFieldUserAgentKey]; - [request setValue:MGLAPIClientHeaderFieldContentTypeValue forHTTPHeaderField:MGLAPIClientHeaderFieldContentTypeKey]; - [request setHTTPMethod:MGLAPIClientHTTPMethodPost]; - - NSData *jsonData = [self serializedDataForEvents:events]; - - // Compressing less than 3 events can have a negative impact on the size. - if (events.count > 2) { - NSData *compressedData = [jsonData mgl_compressedData]; - [request setValue:@"deflate" forHTTPHeaderField:MGLAPIClientHeaderFieldContentEncodingKey]; - [request setHTTPBody:compressedData]; - } - - // Set JSON data if events.count were less than 3 or something went wrong with compressing HTTP body data. - if (!request.HTTPBody) { - [request setValue:nil forHTTPHeaderField:MGLAPIClientHeaderFieldContentEncodingKey]; - [request setHTTPBody:jsonData]; - } - - return [request copy]; -} - -- (void)setupBaseURL { - NSString *testServerURLString = [[NSUserDefaults standardUserDefaults] stringForKey:@"MGLTelemetryTestServerURL"]; - NSURL *testServerURL = [NSURL URLWithString:testServerURLString]; - if (testServerURL && [testServerURL.scheme isEqualToString:@"https"]) { - self.baseURL = testServerURL; - self.usesTestServer = YES; - } else { - self.baseURL = [NSURL URLWithString:MGLAPIClientBaseURL]; - } -} - -- (void)loadCertificates { - NSData *certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust_2016"]; - self.geoTrustCert_2016 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert_2016"]; - self.digicertCert_2016 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-geotrust_2017"]; - self.geoTrustCert_2017 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_com-digicert_2017"]; - self.digicertCert_2017 = certificate; - [self loadCertificate:&certificate withResource:@"api_mapbox_staging"]; - self.testServerCert = certificate; -} - -- (void)loadCertificate:(NSData **)certificate withResource:(NSString *)resource { - NSBundle *frameworkBundle = [NSBundle mgl_frameworkBundle]; - NSString *cerPath = [frameworkBundle pathForResource:resource ofType:@"der"]; - if (cerPath != nil) { - *certificate = [NSData dataWithContentsOfFile:cerPath]; - } -} - -- (void)setupUserAgent { - NSString *appName = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleIdentifier"]; - NSString *appVersion = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleShortVersionString"]; - NSString *appBuildNumber = [[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"]; - NSString *semanticVersion = [NSBundle mgl_frameworkInfoDictionary][@"MGLSemanticVersionString"]; - NSString *shortVersion = [NSBundle mgl_frameworkInfoDictionary][@"CFBundleShortVersionString"]; - NSString *sdkVersion = semanticVersion ?: shortVersion; - _userAgent = [NSString stringWithFormat:@"%@/%@/%@ %@/%@", appName, appVersion, appBuildNumber, MGLAPIClientUserAgentBase, sdkVersion]; -} - -#pragma mark - JSON Serialization - -- (NSData *)serializedDataForEvents:(NS_ARRAY_OF(MGLMapboxEventAttributes *) *)events { - return [NSJSONSerialization dataWithJSONObject:events options:0 error:nil]; -} - -#pragma mark NSURLSessionDelegate - -- (BOOL)evaluateCertificateWithCertificateData:(NSData *)certificateData keyCount:(CFIndex)keyCount serverTrust:(SecTrustRef)serverTrust challenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { - for (int lc = 0; lc < keyCount; lc++) { - SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, lc); - NSData *remoteCertificateData = CFBridgingRelease(SecCertificateCopyData(certificate)); - if ([remoteCertificateData isEqualToData:certificateData]) { - completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - return YES; - } - } - return NO; -} - -- (void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^) (NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler { - - if([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { - SecTrustRef serverTrust = [[challenge protectionSpace] serverTrust]; - SecTrustResultType trustResult; - - // Validate the certificate chain with the device's trust store anyway this *might* use revocation checking - SecTrustEvaluate(serverTrust, &trustResult); - - BOOL found = NO; // For clarity; we start in a state where the challange has not been completed and no certificate has been found - - if (trustResult == kSecTrustResultUnspecified) { - // Look for a pinned certificate in the server's certificate chain - CFIndex numKeys = SecTrustGetCertificateCount(serverTrust); - - // Check certs in the following order: digicert 2016, digicert 2017, geotrust 2016, geotrust 2017 - found = [self evaluateCertificateWithCertificateData:self.digicertCert_2016 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - if (!found) { - found = [self evaluateCertificateWithCertificateData:self.digicertCert_2017 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - if (!found) { - found = [self evaluateCertificateWithCertificateData:self.geoTrustCert_2016 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - if (!found) { - found = [self evaluateCertificateWithCertificateData:self.geoTrustCert_2017 keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - - // If challenge can't be completed with any of the above certs, then try the test server if the app is configured to use the test server - if (!found && _usesTestServer) { - found = [self evaluateCertificateWithCertificateData:self.testServerCert keyCount:numKeys serverTrust:serverTrust challenge:challenge completionHandler:completionHandler]; - } - } - - if (!found) { - // No certificate was found so cancel the connection. - completionHandler(NSURLSessionAuthChallengeCancelAuthenticationChallenge, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); - } - } -} - -@end |