diff --git a/SignalMessaging/profiles/OWSProfileManager.m b/SignalMessaging/profiles/OWSProfileManager.m index e85eae446..d395058d8 100644 --- a/SignalMessaging/profiles/OWSProfileManager.m +++ b/SignalMessaging/profiles/OWSProfileManager.m @@ -1056,9 +1056,11 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); } NSString *_Nullable avatarUrlPathAtStart = userProfile.avatarUrlPath; - if (userProfile.avatarUrlPath.length < 1) { + if (userProfile.profileKey.keyData.length < 1 || userProfile.avatarUrlPath.length < 1) { return; } + + OWSAES256Key *profileKeyAtStart = userProfile.profileKey; NSString *fileName = [self generateAvatarFilename]; NSString *filePath = [OWSUserProfile profileAvatarFilepathWithFilename:fileName]; @@ -1077,7 +1079,6 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); NSString *tempDirectory = OWSTemporaryDirectory(); NSString *tempFilePath = [tempDirectory stringByAppendingPathComponent:fileName]; - NSString *profilePictureURL = userProfile.avatarUrlPath; NSError *serializationError; NSMutableURLRequest *request = @@ -1091,9 +1092,8 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); } NSURLSession* session = [NSURLSession sharedSession]; - NSURLSessionTask* downloadTask = [session downloadTaskWithRequest:request completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) { - + @synchronized(self.currentAvatarDownloads) { [self.currentAvatarDownloads removeObject:userProfile.recipientId]; @@ -1105,32 +1105,68 @@ typedef void (^ProfileManagerFailureBlock)(NSError *error); } NSFileManager *fileManager = [NSFileManager defaultManager]; - NSURL *fileURL = [NSURL fileURLWithPath:filePath]; + NSURL *tempFileUrl = [NSURL fileURLWithPath:tempFilePath]; NSError *moveError; - if (![fileManager moveItemAtURL:location toURL:fileURL error:&moveError]) { + if (![fileManager moveItemAtURL:location toURL:tempFileUrl error:&moveError]) { OWSLogError(@"MoveItemAtURL for avatar failed: %@", moveError); return; } + + NSData *_Nullable encryptedData = (error ? nil : [NSData dataWithContentsOfFile:tempFilePath]); + NSData *_Nullable decryptedData = [self decryptProfileData:encryptedData profileKey:profileKeyAtStart]; + UIImage *_Nullable image = nil; + if (decryptedData) { + BOOL success = [decryptedData writeToFile:filePath atomically:YES]; + if (success) { + image = [UIImage imageWithContentsOfFile:filePath]; + } + } + + OWSUserProfile *latestUserProfile = [OWSUserProfile getOrBuildUserProfileForRecipientId:userProfile.recipientId dbConnection:self.dbConnection]; + + if (latestUserProfile.profileKey.keyData.length < 1 + || ![latestUserProfile.profileKey isEqual:userProfile.profileKey]) { + OWSLogWarn(@"Ignoring avatar download for obsolete user profile."); + } else if (![avatarUrlPathAtStart isEqualToString:latestUserProfile.avatarUrlPath]) { + OWSLogInfo(@"avatar url has changed during download"); + if (latestUserProfile.avatarUrlPath.length > 0) { + [self downloadAvatarForUserProfile:latestUserProfile]; + } + } else if (error) { + if ([response isKindOfClass:NSHTTPURLResponse.class] + && ((NSHTTPURLResponse *)response).statusCode == 403) { + OWSLogInfo(@"no avatar for: %@", userProfile.recipientId); + } else { + OWSLogError(@"avatar download for %@ failed with error: %@", userProfile.recipientId, error); + } + } else if (!encryptedData) { + OWSLogError(@"avatar encrypted data for %@ could not be read.", userProfile.recipientId); + } else if (!decryptedData) { + OWSLogError(@"avatar data for %@ could not be decrypted.", userProfile.recipientId); + } else if (!image) { + OWSLogError(@"avatar image for %@ could not be loaded with error: %@", userProfile.recipientId, error); + } else { + [self updateProfileAvatarCache:image filename:fileName]; - UIImage *image = [UIImage imageWithContentsOfFile:[fileURL path]]; - if (image) { - dispatch_async(dispatch_get_main_queue(), ^{ + [latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:^{ + [[NSNotificationCenter defaultCenter] + postNotificationNameAsync:OWSContactsManagerSignalAccountsDidChangeNotification + object:nil]; + }]; + } - [self updateProfileAvatarCache:image filename:fileName]; - - OWSUserProfile *latestUserProfile = - [OWSUserProfile getOrBuildUserProfileForRecipientId:userProfile.recipientId - dbConnection:self.dbConnection]; + // If we're updating the profile that corresponds to our local number, + // update the local profile as well. + if (userProfile.address.isLocalAddress) { + OWSUserProfile *localUserProfile = self.localUserProfile; + OWSAssertDebug(localUserProfile); - [latestUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:^{ - [[NSNotificationCenter defaultCenter] - postNotificationNameAsync:OWSContactsManagerSignalAccountsDidChangeNotification - object:nil]; - }]; - }); + [localUserProfile updateWithAvatarFileName:fileName dbConnection:self.dbConnection completion:nil]; + [self updateProfileAvatarCache:image filename:fileName]; } - + OWSAssertDebug(backgroundTask); + backgroundTask = nil; }]; [downloadTask resume];