ContactGroupPhotoLoader.m 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124
  1. // _____ _
  2. // |_ _| |_ _ _ ___ ___ _ __ __ _
  3. // | | | ' \| '_/ -_) -_) ' \/ _` |_
  4. // |_| |_||_|_| \___\___|_|_|_\__,_(_)
  5. //
  6. // Threema iOS Client
  7. // Copyright (c) 2013-2020 Threema GmbH
  8. //
  9. // This program is free software: you can redistribute it and/or modify
  10. // it under the terms of the GNU Affero General Public License, version 3,
  11. // as published by the Free Software Foundation.
  12. //
  13. // This program is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  16. // GNU Affero General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Affero General Public License
  19. // along with this program. If not, see <https://www.gnu.org/licenses/>.
  20. #import "ContactGroupPhotoLoader.h"
  21. #import "ActivityIndicatorProxy.h"
  22. #import "NSString+Hex.h"
  23. #import "ProtocolDefines.h"
  24. #import "Utils.h"
  25. #import "NaClCrypto.h"
  26. #import "SSLCAHelper.h"
  27. #import "EntityManager.h"
  28. #import "BlobUtil.h"
  29. #import "ThreemaError.h"
  30. #ifdef DEBUG
  31. static const DDLogLevel ddLogLevel = DDLogLevelVerbose;
  32. #else
  33. static const DDLogLevel ddLogLevel = DDLogLevelWarning;
  34. #endif
  35. @implementation ContactGroupPhotoLoader {
  36. NSData *blobId;
  37. NSData *encryptionKey;
  38. NSMutableData *receivedData;
  39. NSURLSessionDataTask *downloadConnection;
  40. void(^onCompletion)(NSData *imageData);
  41. void(^onError)(NSError *error);
  42. }
  43. - (void)startWithBlobId:(NSData*)_blobId encryptionKey:(NSData*)_encryptionKey onCompletion:(void (^)(NSData *))_onCompletion onError:(void (^)(NSError *))_onError {
  44. onCompletion = _onCompletion;
  45. onError = _onError;
  46. blobId = _blobId;
  47. encryptionKey = _encryptionKey;
  48. /* Fetch image data */
  49. NSURL *imageBlobUrl = [BlobUtil urlForBlobId:blobId];
  50. NSURLRequest *request = [NSURLRequest requestWithURL:imageBlobUrl cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:kBlobLoadTimeout];
  51. receivedData = [NSMutableData data];
  52. NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
  53. downloadConnection = [session dataTaskWithRequest:request completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {
  54. [receivedData setLength:0];
  55. NSInteger statusCode = [((NSHTTPURLResponse *)response) statusCode];
  56. if (statusCode >= 400)
  57. {
  58. [session invalidateAndCancel]; // stop connecting; no more delegate messages
  59. NSDictionary *errorInfo = [NSDictionary dictionaryWithObject:[NSString stringWithFormat:
  60. NSLocalizedString(@"Server returned status code %d",@""),
  61. statusCode]
  62. forKey:NSLocalizedDescriptionKey];
  63. NSError *statusError = [NSError errorWithDomain:NSURLErrorDomain code:statusCode userInfo:errorInfo];
  64. DDLogError(@"Connection failed - error %@ %@",
  65. [statusError localizedDescription],
  66. [[statusError userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
  67. onError([ThreemaError threemaError:[error localizedDescription] withCode:statusError.code]);
  68. [ActivityIndicatorProxy stopActivity];
  69. }
  70. else if (error) {
  71. DDLogError(@"Connection failed - error %@ %@",
  72. [error localizedDescription],
  73. [[error userInfo] objectForKey:NSURLErrorFailingURLStringErrorKey]);
  74. onError([ThreemaError threemaError:[error localizedDescription] withCode:error.code]);
  75. [ActivityIndicatorProxy stopActivity];
  76. } else {
  77. [receivedData appendData:data];
  78. DDLogVerbose(@"Request succeeded - received %lu bytes", (unsigned long)[receivedData length]);
  79. [ActivityIndicatorProxy stopActivity];
  80. dispatch_async(dispatch_get_main_queue(), ^{
  81. [self downloadCompleted];
  82. });
  83. }
  84. }];
  85. [downloadConnection resume];
  86. }
  87. - (void)downloadCompleted {
  88. /* Decrypt the box */
  89. NSData *imageData = [[NaClCrypto sharedCrypto] symmetricDecryptData:receivedData withKey:encryptionKey nonce:[NSData dataWithBytesNoCopy:kNonce_1 length:sizeof(kNonce_1) freeWhenDone:NO]];
  90. if (imageData == nil) {
  91. onError([ThreemaError threemaError:@"Image blob decryption failed"]);
  92. return;
  93. }
  94. onCompletion(imageData);
  95. }
  96. - (void)URLSession:(NSURLSession *)session didReceiveChallenge:(nonnull NSURLAuthenticationChallenge *)challenge completionHandler:(nonnull void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential * _Nullable))completionHandler {
  97. [SSLCAHelper session:session didReceiveAuthenticationChallenge:challenge completion:completionHandler];
  98. }
  99. - (void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask willCacheResponse:(nonnull NSCachedURLResponse *)proposedResponse completionHandler:(nonnull void (^)(NSCachedURLResponse * _Nullable))completionHandler {
  100. completionHandler(nil);
  101. }
  102. @end