#import "SessionManager.h" #import "MattermostBucket.h" @implementation SessionManager @synthesize keyChain; + (instancetype)sharedSession { static id sharedMyManager = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ sharedMyManager = [[self alloc] init]; }); return sharedMyManager; } - (instancetype)init { self = [super init]; if (self) { self.bucket = [[MattermostBucket alloc] init]; self.keyChain = [[KeyChainDataSource alloc] initWithMode:KSM_Identities]; } return self; } -(void)setRequestWithGroup:(NSString *)requestWithGroup certificateName:(NSString *)certificateName { self.requestWithGroup = requestWithGroup; self.certificateName = certificateName; self.isBackground = [certificateName length] == 0; } -(void)setDataForRequest:(NSDictionary *)data forRequestWithGroup:(NSString *)requestWithGroup { NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; [[self.bucket bucketByName:appGroupId] setObject:data forKey:requestWithGroup]; } -(NSString *)getAppGroupIdFromRequestIdentifier:(NSString *) requestWithGroup { return [requestWithGroup componentsSeparatedByString:@"|"][1]; } -(NSDictionary *)getCredentialsForRequest:(NSString *)requestWithGroup { NSString * appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; NSString *entitiesString = [self.bucket readFromFile:@"entities" appGroupId:appGroupId]; NSData *entitiesData = [entitiesString dataUsingEncoding:NSUTF8StringEncoding]; NSError *error; NSDictionary *entities = [NSJSONSerialization JSONObjectWithData:entitiesData options:NSJSONReadingMutableContainers error:&error]; if (error != nil) { return nil; } return [[entities objectForKey:@"general"] objectForKey:@"credentials"]; } -(NSDictionary *)getDataForRequest:(NSString *)requestWithGroup { NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; return [[self.bucket bucketByName:appGroupId] objectForKey:requestWithGroup]; } -(NSURLSession *)createSessionForRequestRequest:(NSString *)requestWithGroup { NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; NSURLSessionConfiguration* config; if (self.isBackground) { config = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:requestWithGroup]; } else { config = [NSURLSessionConfiguration defaultSessionConfiguration]; } config.sharedContainerIdentifier = appGroupId; return [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; } -(void) createPost:(NSDictionary *) post withFiles:(NSArray *)files credentials:(NSDictionary *) credentials requestWithGroup:(NSString *)requestWithGroup { NSString *serverUrl = [credentials objectForKey:@"url"]; NSString *token = [credentials objectForKey:@"token"]; NSString *channelId = [post objectForKey:@"channel_id"]; NSURLSession *session = [self createSessionForRequestRequest:requestWithGroup]; NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; for (id file in files) { NSURL *filePath = [NSURL fileURLWithPath:[file objectForKey:@"filePath"]]; NSString *fileName = [file objectForKey:@"filename"]; NSError *err; NSURL *tempContainerURL = [self tempContainerURL:appGroupId]; NSURL *destinationURL = [tempContainerURL URLByAppendingPathComponent: fileName]; BOOL bVal = [[NSFileManager defaultManager] copyItemAtURL:filePath toURL:destinationURL error:&err]; NSCharacterSet *allowedCharacters = [NSCharacterSet URLQueryAllowedCharacterSet]; NSString *encodedFilename = [[file objectForKey:@"filename"] stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacters]; NSString *url = [serverUrl stringByAppendingString:@"/api/v4/files"]; NSString *queryString = [NSString stringWithFormat:@"?channel_id=%@&filename=%@", channelId, encodedFilename]; NSURL *filesUrl = [NSURL URLWithString:[url stringByAppendingString:queryString]]; NSMutableURLRequest *uploadRequest = [NSMutableURLRequest requestWithURL:filesUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:120.0]; [uploadRequest setHTTPMethod:@"POST"]; [uploadRequest setValue:[@"Bearer " stringByAppendingString:token] forHTTPHeaderField:@"Authorization"]; [uploadRequest setValue:@"application/json" forHTTPHeaderField:@"Accept"]; NSURLSessionUploadTask *task = [session uploadTaskWithRequest:uploadRequest fromFile:destinationURL]; NSLog(@"Executing file request %@", fileName); [task resume]; } } -(void) createPost:(NSMutableDictionary *)post withFileIds:(NSArray *)fileIds credentials:(NSDictionary *) credentials { NSString *serverUrl = [credentials objectForKey:@"url"]; NSString *token = [credentials objectForKey:@"token"]; if (fileIds != nil && [fileIds count] > 0) { [post setObject:fileIds forKey:@"file_ids"]; } NSError *error; NSData *postData = [NSJSONSerialization dataWithJSONObject:post options:NSJSONWritingPrettyPrinted error:&error]; if (error == nil) { NSString* postAsString = [[NSString alloc] initWithData:postData encoding:NSUTF8StringEncoding]; NSURL *createUrl = [NSURL URLWithString:[serverUrl stringByAppendingString:@"/api/v4/posts"]]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:createUrl cachePolicy:NSURLRequestUseProtocolCachePolicy timeoutInterval:5.0]; [request setHTTPMethod:@"POST"]; [request setValue:[@"Bearer " stringByAppendingString:token] forHTTPHeaderField:@"Authorization"]; [request setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [request setValue:@"application/json; charset=utf-8" forHTTPHeaderField:@"Content-Type"]; [request setHTTPBody:[postAsString dataUsingEncoding:NSUTF8StringEncoding]]; NSURLSessionConfiguration* config = [NSURLSessionConfiguration ephemeralSessionConfiguration]; NSURLSession *createSession = [NSURLSession sessionWithConfiguration:config delegate:self delegateQueue:nil]; NSURLSessionDataTask *createTask = [createSession dataTaskWithRequest:request]; NSLog(@"Executing post request"); [createTask resume]; self.closeExtension(); } else { self.sendShareEvent(@"extensionPostFailed"); } } -(void)createPostForRequest:(NSString *)requestWithGroup { NSDictionary *data = [self getDataForRequest:requestWithGroup]; NSDictionary *post = [data objectForKey:@"post"]; NSArray *files = [data objectForKey:@"files"]; NSDictionary *credentials = [self getCredentialsForRequest:requestWithGroup]; if (credentials == nil) { self.sendShareEvent(@"extensionPostFailed"); return; } if (files != nil && [files count] > 0) { [self createPost:post withFiles:files credentials:credentials requestWithGroup:requestWithGroup]; } else { [self createPost:[post mutableCopy] withFileIds:nil credentials:credentials]; } } -(void)sendPostRequestForId:(NSString *)requestWithGroup { NSDictionary *data = [self getDataForRequest:requestWithGroup]; NSDictionary *credentials = [self getCredentialsForRequest:requestWithGroup]; NSMutableDictionary *post = [[data objectForKey:@"post"] mutableCopy]; NSArray *fileIds = [data objectForKey:@"file_ids"]; [self createPost:post withFileIds:fileIds credentials:credentials]; } -(NSURL*)tempContainerURL:(NSString*)appGroupId { NSFileManager *manager = [NSFileManager defaultManager]; NSURL *containerURL = [manager containerURLForSecurityApplicationGroupIdentifier:appGroupId]; NSURL *tempDirectoryURL = [containerURL URLByAppendingPathComponent:@"shareTempItems"]; if (![manager fileExistsAtPath:[tempDirectoryURL path]]) { NSError *err; [manager createDirectoryAtURL:tempDirectoryURL withIntermediateDirectories:YES attributes:nil error:&err]; if (err) { return nil; } } return tempDirectoryURL; } -(void)URLSession:(NSURLSession *)session didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler { NSLog(@"completition handler from normal challenge"); if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodClientCertificate]) { if (self.certificateName) { SecIdentityRef identity = [keyChain GetIdentityByName:self.certificateName]; if (identity != nil) { SecCertificateRef certificate = NULL; OSStatus status = SecIdentityCopyCertificate(identity, &certificate); if (!status) { CFArrayRef emailAddresses = NULL; SecCertificateCopyEmailAddresses(certificate, &emailAddresses); NSArray *emails = (NSArray *)CFBridgingRelease(emailAddresses); CFStringRef summaryRef = SecCertificateCopySubjectSummary(certificate); NSString *tagstr = (NSString*)CFBridgingRelease(summaryRef); NSString *email = @""; if ([emails count] > 0){ email = [emails objectAtIndex:0]; } NSLog(@"completion %@ %@", tagstr, email); const void *certs[] = {certificate}; CFArrayRef certArray = CFArrayCreate(kCFAllocatorDefault, certs, 1, NULL); NSURLCredential *credential = [NSURLCredential credentialWithIdentity:identity certificates:(__bridge NSArray*)certArray persistence:NSURLCredentialPersistencePermanent]; [challenge.sender useCredential:credential forAuthenticationChallenge:challenge]; completionHandler(NSURLSessionAuthChallengeUseCredential,credential); NSLog(@"completion handler for certificate"); return; } } } completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); } else { NSLog(@"completion handler regular stuff"); completionHandler(NSURLSessionAuthChallengeUseCredential, [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]); } } -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { NSString *requestWithGroup; if (self.isBackground) { requestWithGroup = [[session configuration] identifier]; } else { requestWithGroup = self.requestWithGroup; } NSURL *requestUrl = [[dataTask originalRequest] URL]; if ([[requestUrl absoluteString] containsString:@"files"]) { NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; NSError *error; NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:0 error:&error]; if (error == nil && json != nil) { NSArray *fileInfos = [json objectForKey:@"file_infos"]; NSDictionary *dataFromBucket = [self getDataForRequest:requestWithGroup]; NSMutableDictionary *data = [dataFromBucket mutableCopy]; NSMutableArray *fileIds = [[data objectForKey:@"file_ids"] mutableCopy]; if (fileIds == nil && data != nil) { fileIds = [[NSMutableArray alloc] init]; } for (id file in fileInfos) { [fileIds addObject:[file objectForKey:@"id"]]; NSString * filename = [file objectForKey:@"name"]; NSLog(@"got file id %@ %@", [file objectForKey:@"id"], filename); NSURL *tempContainerURL = [self tempContainerURL:appGroupId]; NSURL *destinationURL = [tempContainerURL URLByAppendingPathComponent: filename]; [[NSFileManager defaultManager] removeItemAtURL:destinationURL error:nil]; } [data setObject:fileIds forKey:@"file_ids"]; [self setDataForRequest:data forRequestWithGroup:requestWithGroup]; } else { self.sendShareEvent(@"extensionPostFailed"); } } } -(void)URLSession:(NSURLSession *)session task:(NSURLSessionDataTask *)task didCompleteWithError:(nullable NSError *)error { NSString *requestWithGroup; if (self.isBackground) { requestWithGroup = [[session configuration] identifier]; } else { requestWithGroup = self.requestWithGroup; } if(error != nil) { NSLog(@"completition ERROR %@", [error userInfo]); NSLog(@"invalidating session %@", requestWithGroup); [session invalidateAndCancel]; self.sendShareEvent(@"extensionPostFailed"); } else if (requestWithGroup != nil) { NSString *appGroupId = [self getAppGroupIdFromRequestIdentifier:requestWithGroup]; NSURL *requestUrl = [[task originalRequest] URL]; NSDictionary *data = [self getDataForRequest:requestWithGroup]; NSArray *files = [data objectForKey:@"files"]; NSMutableArray *fileIds = [data objectForKey:@"file_ids"]; if ([[requestUrl absoluteString] containsString:@"files"] && [files count] == [fileIds count]) { [self sendPostRequestForId:requestWithGroup]; [[self.bucket bucketByName:appGroupId] removeObjectForKey:requestWithGroup]; } } else { NSLog(@"SOMETHING ELSE"); } } -(void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { if (self.savedCompletionHandler) { self.savedCompletionHandler(); self.savedCompletionHandler = nil; } } @end