Merge branch 'charlesmchen/blockListVsProfileWhitelist'

pull/1/head
Matthew Chen 7 years ago
commit aa04608e7e

@ -1627,7 +1627,6 @@
4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */,
34D5872E208E2C4100D2255A /* OWS109OutgoingMessageState.h */,
34D5872D208E2C4100D2255A /* OWS109OutgoingMessageState.m */,
4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */,
349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */,
346129931FD1E30000532771 /* OWSDatabaseMigration.h */,
346129941FD1E30000532771 /* OWSDatabaseMigration.m */,

@ -239,9 +239,9 @@ NS_ASSUME_NONNULL_BEGIN
itemWithTitle:@"Request Bogus group info"
actionBlock:^{
OWSLogInfo(@"Requesting bogus group info for thread: %@", thread);
OWSSyncGroupsRequestMessage *syncGroupsRequestMessage =
[[OWSSyncGroupsRequestMessage alloc] initWithThread:thread
groupId:[Randomness generateRandomBytes:16]];
OWSSyncGroupsRequestMessage *syncGroupsRequestMessage = [[OWSSyncGroupsRequestMessage alloc]
initWithThread:thread
groupId:[Randomness generateRandomBytes:kGroupIdLength]];
[SSKEnvironment.shared.messageSender enqueueMessage:syncGroupsRequestMessage
success:^{
OWSLogWarn(@"Successfully sent Request Group Info message.");
@ -3816,7 +3816,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
recipientId,
[TSAccountManager localNumber],
] mutableCopy];
NSData *groupId = [Randomness generateRandomBytes:16];
NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength];
TSGroupModel *groupModel =
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
@ -4309,7 +4309,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
recipientId,
[TSAccountManager localNumber],
] mutableCopy];
NSData *groupId = [Randomness generateRandomBytes:16];
NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength];
TSGroupModel *groupModel =
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];
@ -4348,7 +4348,7 @@ typedef OWSContact * (^OWSContactBlock)(YapDatabaseReadWriteTransaction *transac
recipientId,
[TSAccountManager localNumber],
] mutableCopy];
NSData *groupId = [Randomness generateRandomBytes:16];
NSData *groupId = [Randomness generateRandomBytes:kGroupIdLength];
TSGroupModel *groupModel =
[[TSGroupModel alloc] initWithTitle:groupName memberIds:recipientIds image:nil groupId:groupId];

@ -506,7 +506,7 @@ NS_ASSUME_NONNULL_BEGIN
[[TSGroupModel alloc] initWithTitle:[groupThread.groupModel.groupName stringByAppendingString:@" Copy"]
memberIds:groupThread.groupModel.groupMemberIds
image:groupThread.groupModel.groupImage
groupId:[Randomness generateRandomBytes:16]];
groupId:[Randomness generateRandomBytes:kGroupIdLength]];
thread = [TSGroupThread getOrCreateThreadWithGroupModel:groupModel transaction:transaction];
}];
OWSAssertDebug(thread);

@ -86,7 +86,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)commonInit
{
_groupId = [Randomness generateRandomBytes:16];
_groupId = [Randomness generateRandomBytes:kGroupIdLength];
_messageSender = SSKEnvironment.shared.messageSender;
_contactsViewHelper = [[ContactsViewHelper alloc] initWithDelegate:self];

@ -80,11 +80,11 @@ class ConversationSearcherTest: SignalBaseTest {
SSKEnvironment.shared.contactsManager = ConversationSearcherContactsManager()
self.dbConnection.readWrite { transaction in
let bookModel = TSGroupModel(title: "Book Club", memberIds: [aliceRecipientId, bobRecipientId], image: nil, groupId: Randomness.generateRandomBytes(16))
let bookModel = TSGroupModel(title: "Book Club", memberIds: [aliceRecipientId, bobRecipientId], image: nil, groupId: Randomness.generateRandomBytes(kGroupIdLength))
let bookClubGroupThread = TSGroupThread.getOrCreateThread(with: bookModel, transaction: transaction)
self.bookClubThread = ThreadViewModel(thread: bookClubGroupThread, transaction: transaction)
let snackModel = TSGroupModel(title: "Snack Club", memberIds: [aliceRecipientId], image: nil, groupId: Randomness.generateRandomBytes(16))
let snackModel = TSGroupModel(title: "Snack Club", memberIds: [aliceRecipientId], image: nil, groupId: Randomness.generateRandomBytes(kGroupIdLength))
let snackClubGroupThread = TSGroupThread.getOrCreateThread(with: snackModel, transaction: transaction)
self.snackClubThread = ThreadViewModel(thread: snackClubGroupThread, transaction: transaction)

@ -53,11 +53,7 @@ NS_ASSUME_NONNULL_BEGIN
OWSContactsManager *contactsManager = [[OWSContactsManager alloc] initWithPrimaryStorage:primaryStorage];
ContactsUpdater *contactsUpdater = [ContactsUpdater new];
OWSMessageSender *messageSender = [[OWSMessageSender alloc] initWithPrimaryStorage:primaryStorage];
OWSProfileManager *profileManager = [[OWSProfileManager alloc] initWithPrimaryStorage:primaryStorage
messageSender:messageSender
networkManager:networkManager];
OWSProfileManager *profileManager = [[OWSProfileManager alloc] initWithPrimaryStorage:primaryStorage];
OWSMessageManager *messageManager = [[OWSMessageManager alloc] initWithPrimaryStorage:primaryStorage];
OWSBlockingManager *blockingManager = [[OWSBlockingManager alloc] initWithPrimaryStorage:primaryStorage];
OWSIdentityManager *identityManager = [[OWSIdentityManager alloc] initWithPrimaryStorage:primaryStorage];

@ -8,12 +8,6 @@ import SignalServiceKit
@objc
public class OWS111UDAttributesMigration: OWSDatabaseMigration {
// MARK: - Singletons
private var networkManager: TSNetworkManager {
return SSKEnvironment.shared.networkManager
}
// MARK: -
// increment a similar constant for each migration.

@ -22,9 +22,7 @@ extern const NSUInteger kOWSProfileManager_MaxAvatarDiameter;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage
messageSender:(OWSMessageSender *)messageSender
networkManager:(TSNetworkManager *)networkManager;
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage;
+ (instancetype)sharedManager;

@ -5,15 +5,18 @@
#import "OWSProfileManager.h"
#import "Environment.h"
#import "OWSUserProfile.h"
#import <PromiseKit/AnyPromise.h>
#import <SignalCoreKit/Cryptography.h>
#import <SignalCoreKit/NSData+OWS.h>
#import <SignalCoreKit/NSDate+OWS.h>
#import <SignalCoreKit/NSString+SSK.h>
#import <SignalMessaging/SignalMessaging-Swift.h>
#import <SignalServiceKit/AppContext.h>
#import <SignalServiceKit/AppReadiness.h>
#import <SignalServiceKit/MIMETypeUtil.h>
#import <SignalServiceKit/NSData+Image.h>
#import <SignalServiceKit/NSNotificationCenter+OWS.h>
#import <SignalServiceKit/OWSBlockingManager.h>
#import <SignalServiceKit/OWSFileSystem.h>
#import <SignalServiceKit/OWSMessageSender.h>
#import <SignalServiceKit/OWSPrimaryStorage.h>
@ -27,6 +30,7 @@
#import <SignalServiceKit/TSThread.h>
#import <SignalServiceKit/TSYapDatabaseObject.h>
#import <SignalServiceKit/UIImage+OWS.h>
#import <SignalServiceKit/YapDatabaseConnection+OWS.h>
NS_ASSUME_NONNULL_BEGIN
@ -40,12 +44,11 @@ NSString *const kOWSProfileManager_GroupWhitelistCollection = @"kOWSProfileManag
const NSUInteger kOWSProfileManager_NameDataLength = 26;
const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
typedef void (^ProfileManagerFailureBlock)(NSError *error);
@interface OWSProfileManager ()
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic, readonly) YapDatabaseConnection *dbConnection;
@property (nonatomic, readonly) TSNetworkManager *networkManager;
@property (nonatomic, readonly) OWSIdentityManager *identityManager;
// This property can be accessed on any thread, while synchronized on self.
@property (atomic, readonly) OWSUserProfile *localUserProfile;
@ -72,8 +75,6 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
}
- (instancetype)initWithPrimaryStorage:(OWSPrimaryStorage *)primaryStorage
messageSender:(OWSMessageSender *)messageSender
networkManager:(TSNetworkManager *)networkManager
{
self = [super init];
@ -83,18 +84,18 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
OWSAssertIsOnMainThread();
OWSAssertDebug(primaryStorage);
OWSAssertDebug(messageSender);
OWSAssertDebug(messageSender);
_messageSender = messageSender;
_dbConnection = primaryStorage.newDatabaseConnection;
_networkManager = networkManager;
_profileAvatarImageCache = [NSCache new];
_currentAvatarDownloads = [NSMutableSet new];
OWSSingletonAssert();
[AppReadiness runNowOrWhenAppIsReady:^{
[self rotateLocalProfileKeyIfNecessary];
}];
return self;
}
@ -109,6 +110,10 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
selector:@selector(applicationDidBecomeActive:)
name:OWSApplicationDidBecomeActiveNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(blockListDidChange:)
name:kNSNotificationName_BlockListDidChange
object:nil];
}
#pragma mark - Dependencies
@ -124,7 +129,21 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
- (OWSIdentityManager *)identityManager
{
return [OWSIdentityManager sharedManager];
return SSKEnvironment.shared.identityManager;
}
- (OWSMessageSender *)messageSender {
OWSAssertDebug(SSKEnvironment.shared.messageSender);
return SSKEnvironment.shared.messageSender;
}
- (TSNetworkManager *)networkManager {
return SSKEnvironment.shared.networkManager;
}
- (OWSBlockingManager *)blockingManager {
return SSKEnvironment.shared.blockingManager;
}
#pragma mark - User Profile Accessor
@ -227,7 +246,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
successBlock();
}];
}
failure:^{
failure:^(NSError *error) {
failureBlock();
}];
};
@ -258,11 +277,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
success:^(NSString *_Nullable avatarUrlPath) {
tryToUpdateService(avatarUrlPath, fileName);
}
failure:^{
failure:^(NSError *error) {
failureBlock();
}];
}
failure:^{
failure:^(NSError *error) {
failureBlock();
}];
}
@ -272,7 +291,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
success:^(NSString *_Nullable avatarUrlPath) {
tryToUpdateService(nil, nil);
}
failure:^{
failure:^(NSError *error) {
failureBlock();
}];
} else {
@ -283,8 +302,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
- (void)writeAvatarToDisk:(UIImage *)avatar
success:(void (^)(NSData *data, NSString *fileName))successBlock
failure:(void (^)(void))failureBlock
{
failure:(ProfileManagerFailureBlock)failureBlock {
OWSAssertDebug(avatar);
OWSAssertDebug(successBlock);
OWSAssertDebug(failureBlock);
@ -299,12 +317,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
BOOL success = [data writeToFile:filePath atomically:YES];
OWSAssertDebug(success);
if (success) {
successBlock(data, fileName);
return;
return successBlock(data, fileName);
}
}
}
failureBlock();
failureBlock(OWSErrorWithCodeDescription(OWSErrorCodeAvatarWriteFailed, @"Avatar write failed."));
});
}
@ -334,8 +351,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
// If avatarData is nil, we are clearing the avatar.
- (void)uploadAvatarToService:(NSData *_Nullable)avatarData
success:(void (^)(NSString *_Nullable avatarUrlPath))successBlock
failure:(void (^)(void))failureBlock
{
failure:(ProfileManagerFailureBlock)failureBlock {
OWSAssertDebug(successBlock);
OWSAssertDebug(failureBlock);
OWSAssertDebug(avatarData == nil || avatarData.length > 0);
@ -371,8 +387,8 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
if (![formResponseObject isKindOfClass:[NSDictionary class]]) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidResponse]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSDictionary *responseMap = formResponseObject;
OWSLogError(@"responseObject: %@", formResponseObject);
@ -380,44 +396,44 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
NSString *formAcl = responseMap[@"acl"];
if (![formAcl isKindOfClass:[NSString class]] || formAcl.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidAcl]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSString *formKey = responseMap[@"key"];
if (![formKey isKindOfClass:[NSString class]] || formKey.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidKey]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSString *formPolicy = responseMap[@"policy"];
if (![formPolicy isKindOfClass:[NSString class]] || formPolicy.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidPolicy]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSString *formAlgorithm = responseMap[@"algorithm"];
if (![formAlgorithm isKindOfClass:[NSString class]] || formAlgorithm.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidAlgorithm]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSString *formCredential = responseMap[@"credential"];
if (![formCredential isKindOfClass:[NSString class]] || formCredential.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidCredential]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSString *formDate = responseMap[@"date"];
if (![formDate isKindOfClass:[NSString class]] || formDate.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidDate]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
NSString *formSignature = responseMap[@"signature"];
if (![formSignature isKindOfClass:[NSString class]] || formSignature.length < 1) {
OWSProdFail([OWSAnalyticsEvents profileManagerErrorAvatarUploadFormInvalidSignature]);
failureBlock();
return;
return failureBlock(
OWSErrorWithCodeDescription(OWSErrorCodeAvatarUploadFailed, @"Avatar upload failed."));
}
[self.avatarHTTPManager POST:@""
@ -453,9 +469,9 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
OWSLogInfo(@"successfully uploaded avatar with key: %@", formKey);
successBlock(formKey);
}
failure:^(NSURLSessionDataTask *_Nullable uploadTask, NSError *_Nonnull error) {
failure:^(NSURLSessionDataTask *_Nullable uploadTask, NSError *error) {
OWSLogError(@"uploading avatar failed with error: %@", error);
failureBlock();
return failureBlock(error);
}];
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
@ -466,15 +482,14 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
}
OWSLogError(@"Failed to get profile avatar upload form: %@", error);
failureBlock();
return failureBlock(error);
}];
});
}
- (void)updateServiceWithProfileName:(nullable NSString *)localProfileName
success:(void (^)(void))successBlock
failure:(void (^)(void))failureBlock
{
failure:(ProfileManagerFailureBlock)failureBlock {
OWSAssertDebug(successBlock);
OWSAssertDebug(failureBlock);
@ -488,7 +503,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
}
failure:^(NSURLSessionDataTask *task, NSError *error) {
OWSLogError(@"Failed to update profile with error: %@", error);
failureBlock();
failureBlock(error);
}];
});
}
@ -504,6 +519,210 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
[ProfileFetcherJob runWithRecipientId:localNumber ignoreThrottling:YES];
}
#pragma mark - Profile Key Rotation
- (nullable NSString *)groupKeyForGroupId:(NSData *)groupId {
NSString *groupIdKey = [groupId hexadecimalString];
return groupIdKey;
}
- (nullable NSData *)groupIdForGroupKey:(NSString *)groupKey {
NSMutableData *groupId = [NSMutableData new];
if (groupKey.length % 2 != 0) {
OWSFailDebug(@"Group key has unexpected length: %@ (%lu)", groupKey, (unsigned long)groupKey.length);
return nil;
}
for (NSUInteger i = 0; i + 2 <= groupKey.length; i += 2) {
NSString *_Nullable byteString = [groupKey substringWithRange:NSMakeRange(i, 2)];
if (!byteString) {
OWSFailDebug(@"Couldn't slice group key.");
return nil;
}
unsigned byteValue;
if (![[NSScanner scannerWithString:byteString] scanHexInt:&byteValue]) {
OWSFailDebug(@"Couldn't parse hex byte: %@.", byteString);
return nil;
}
if (byteValue > 0xff) {
OWSFailDebug(@"Invalid hex byte: %@ (%d).", byteString, byteValue);
return nil;
}
uint8_t byte = (uint8_t)(0xff & byteValue);
[groupId appendBytes:&byte length:1];
}
if (groupId.length != kGroupIdLength) {
OWSFailDebug(@"Parsed group id has unexpected length: %@ (%lu)",
groupId.hexadecimalString,
(unsigned long)groupId.length);
return nil;
}
return [groupId copy];
}
- (void)rotateLocalProfileKeyIfNecessary {
[self
rotateLocalProfileKeyIfNecessaryWithSuccess:^{
}
failure:^(NSError *error) {
}];
}
- (void)rotateLocalProfileKeyIfNecessaryWithSuccess:(dispatch_block_t)success
failure:(ProfileManagerFailureBlock)failure {
OWSAssertDebug(AppReadiness.isAppReady);
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
NSMutableSet<NSString *> *whitelistedRecipientIds = [NSMutableSet new];
NSMutableSet<NSData *> *whitelistedGroupIds = [NSMutableSet new];
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
[whitelistedRecipientIds
addObjectsFromArray:[transaction allKeysInCollection:kOWSProfileManager_UserWhitelistCollection]];
NSArray<NSString *> *whitelistedGroupKeys =
[transaction allKeysInCollection:kOWSProfileManager_GroupWhitelistCollection];
for (NSString *groupKey in whitelistedGroupKeys) {
NSData *_Nullable groupId = [self groupIdForGroupKey:groupKey];
if (!groupId) {
OWSFailDebug(@"Couldn't parse group key: %@.", groupKey);
continue;
}
[whitelistedGroupIds addObject:groupId];
TSGroupThread *_Nullable thread = [TSGroupThread threadWithGroupId:groupId transaction:transaction];
if (!thread) {
OWSLogInfo(@"Could not find whitelisted thread: %@", groupId.hexadecimalString);
continue;
}
[whitelistedRecipientIds addObjectsFromArray:thread.recipientIdentifiers];
}
}];
NSString *_Nullable localNumber = [TSAccountManager localNumber];
if (localNumber) {
[whitelistedRecipientIds removeObject:localNumber];
} else {
OWSFailDebug(@"Missing localNumber");
}
NSSet<NSString *> *blockedRecipientIds = [NSSet setWithArray:self.blockingManager.blockedPhoneNumbers];
NSSet<NSData *> *blockedGroupIds = [NSSet setWithArray:self.blockingManager.blockedGroupIds];
// Find the users and groups which are both a) blocked b) may have our current profile key.
NSMutableSet<NSString *> *intersectingRecipientIds = [blockedRecipientIds mutableCopy];
[intersectingRecipientIds intersectSet:whitelistedRecipientIds];
NSMutableSet<NSData *> *intersectingGroupIds = [blockedGroupIds mutableCopy];
[intersectingGroupIds intersectSet:whitelistedGroupIds];
BOOL isProfileKeySharedWithBlocked = (intersectingRecipientIds.count > 0 || intersectingGroupIds.count > 0);
if (!isProfileKeySharedWithBlocked) {
// No need to rotate the profile key.
return success();
}
// Rotate the profile key
// Make copies of the current local profile state.
OWSUserProfile *localUserProfile = self.localUserProfile;
NSString *_Nullable oldProfileName = localUserProfile.profileName;
NSString *_Nullable oldAvatarFileName = localUserProfile.avatarFileName;
NSData *_Nullable oldAvatarData = [self profileAvatarDataForRecipientId:self.tsAccountManager.localNumber];
// Rotate the stored profile key.
AnyPromise *promise = [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self.localUserProfile updateWithProfileKey:[OWSAES256Key generateRandomKey]
dbConnection:self.dbConnection
completion:^{
// The value doesn't matter, we just need any non-NSError value.
resolve(@(1));
}];
}];
// Try to re-upload our profile name, if any.
//
// This may fail.
promise = promise.then(^(id value) {
if (oldProfileName.length < 1) {
return [AnyPromise promiseWithValue:@(1)];
}
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self updateServiceWithProfileName:oldProfileName
success:^{
OWSLogInfo(@"Update to profile name succeeded.");
// The value doesn't matter, we just need any non-NSError value.
resolve(@(1));
}
failure:^(NSError *error) {
resolve(error);
}];
}];
});
// Try to re-upload our profile avatar, if any.
//
// This may fail.
promise = promise.then(^(id value) {
if (oldAvatarData.length < 1 || oldAvatarFileName.length < 1) {
return [AnyPromise promiseWithValue:@(1)];
}
return [AnyPromise promiseWithResolverBlock:^(PMKResolver resolve) {
[self uploadAvatarToService:oldAvatarData
success:^(NSString *_Nullable avatarUrlPath) {
OWSLogInfo(@"Update to profile avatar after profile key rotation succeeded.");
// We need to update the local profile with the avatar state since
// it is cleared during the "avatar update" process.
[self.localUserProfile updateWithAvatarUrlPath:avatarUrlPath
avatarFileName:oldAvatarFileName
dbConnection:self.dbConnection
completion:^{
// The value doesn't matter, we just need any
// non-NSError value.
resolve(@(1));
}];
}
failure:^(NSError *error) {
OWSLogInfo(@"Update to profile avatar after profile key rotation failed.");
resolve(error);
}];
}];
});
// Try to re-upload our profile avatar, if any.
//
// This may fail.
promise = promise.then(^(id value) {
// Remove blocked users and groups from profile whitelist.
//
// This will always succeed.
[self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
[transaction removeObjectsForKeys:intersectingRecipientIds.allObjects
inCollection:kOWSProfileManager_UserWhitelistCollection];
for (NSData *groupId in intersectingGroupIds) {
NSString *groupIdKey = [self groupKeyForGroupId:groupId];
[transaction removeObjectForKey:groupIdKey
inCollection:kOWSProfileManager_GroupWhitelistCollection];
}
}];
return @(1);
});
promise = promise.then(^(id value) {
success();
});
promise = promise.catch(^(NSError *error) {
if ([error isKindOfClass:[NSError class]]) {
failure(error);
} else {
failure(OWSErrorMakeAssertionError(@"Profile key rotation failure missing error."));
}
});
[promise retainUntilComplete];
});
}
#pragma mark - Profile Whitelist
- (void)clearProfileWhitelist
@ -581,6 +800,10 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
{
OWSAssertDebug(recipientId.length > 0);
if ([self.blockingManager isRecipientIdBlocked:recipientId]) {
return NO;
}
__block BOOL result = NO;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
NSNumber *_Nullable oldValue =
@ -594,7 +817,7 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
{
OWSAssertDebug(groupId.length > 0);
NSString *groupIdKey = [groupId hexadecimalString];
NSString *groupIdKey = [self groupKeyForGroupId:groupId];
__block BOOL didChange = NO;
[self.dbConnection asyncReadWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) {
@ -645,7 +868,11 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
{
OWSAssertDebug(groupId.length > 0);
NSString *groupIdKey = [groupId hexadecimalString];
if ([self.blockingManager isGroupIdBlocked:groupId]) {
return NO;
}
NSString *groupIdKey = [self groupKeyForGroupId:groupId];
__block BOOL result = NO;
[self.dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) {
@ -1173,6 +1400,14 @@ const NSUInteger kOWSProfileManager_MaxAvatarDiameter = 640;
// TODO: Sync if necessary.
}
- (void)blockListDidChange:(NSNotification *)notification {
OWSAssertIsOnMainThread();
[AppReadiness runNowOrWhenAppIsReady:^{
[self rotateLocalProfileKeyIfNecessary];
}];
}
@end
NS_ASSUME_NONNULL_END

@ -61,6 +61,10 @@ extern NSString *const kLocalProfileUniqueId;
dbConnection:(YapDatabaseConnection *)dbConnection
completion:(nullable OWSUserProfileCompletion)completion;
- (void)updateWithProfileKey:(OWSAES256Key *)profileKey
dbConnection:(YapDatabaseConnection *)dbConnection
completion:(nullable OWSUserProfileCompletion)completion;
- (void)clearWithProfileKey:(OWSAES256Key *)profileKey
dbConnection:(YapDatabaseConnection *)dbConnection
completion:(nullable OWSUserProfileCompletion)completion;

@ -7,6 +7,8 @@
NS_ASSUME_NONNULL_BEGIN
extern const NSUInteger kGroupIdLength;
@interface TSGroupModel : TSYapDatabaseObject
@property (nonatomic) NSArray<NSString *> *groupMemberIds;

@ -8,6 +8,8 @@
NS_ASSUME_NONNULL_BEGIN
const NSUInteger kGroupIdLength = 16;
@interface TSGroupModel ()
@property (nullable, nonatomic) NSString *groupName;

@ -48,6 +48,9 @@ typedef NS_ENUM(NSInteger, OWSErrorCode) {
OWSErrorCodeMessageRequestFailed = 777421,
OWSErrorCodeMessageResponseFailed = 777422,
OWSErrorCodeInvalidMessage = 777423,
OWSErrorCodeProfileUpdateFailed = 777424,
OWSErrorCodeAvatarWriteFailed = 777425,
OWSErrorCodeAvatarUploadFailed = 777426,
};
extern NSString *const OWSErrorRecipientIdentifierKey;

Loading…
Cancel
Save