WIP: adapt to verification proto changes

// FREEBIE
This commit is contained in:
Michael Kirk 2017-06-21 20:19:23 -04:00
parent f526a372c9
commit 48b3f498a9
5 changed files with 172 additions and 139 deletions

View file

@ -9,12 +9,15 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSVerificationStateSyncMessage : OWSOutgoingSyncMessage @interface OWSVerificationStateSyncMessage : OWSOutgoingSyncMessage
- (void)addVerificationState:(OWSVerificationState)verificationState - (instancetype)initWithVerificationState:(OWSVerificationState)verificationState
identityKey:(NSData *)identityKey identityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId; verificationForRecipientId:(NSString *)recipientId;
// Returns the list of recipient ids referenced in this message. //// Returns the list of recipient ids referenced in this message.
- (NSArray<NSString *> *)recipientIds; //- (NSArray<NSString *> *)recipientIds;
// This is a clunky name, but we want to differentiate it from `recipientIdentifier` inherited from `TSOutgoingMessage`
@property (nonatomic, readonly) NSString *verificationForRecipientId;
@end @end

View file

@ -9,99 +9,125 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface OWSVerificationStateTuple : NSObject //@interface OWSVerificationStateTuple : NSObject
//
@property (nonatomic) OWSVerificationState verificationState; //@property (nonatomic) OWSVerificationState verificationState;
@property (nonatomic) NSData *identityKey; //@property (nonatomic) NSData *identityKey;
@property (nonatomic) NSString *recipientId; //@property (nonatomic) NSString *recipientId;
//
@end //@end
//
#pragma mark - //#pragma mark -
//
@implementation OWSVerificationStateTuple //@implementation OWSVerificationStateTuple
//
@end //@end
#pragma mark - #pragma mark -
@interface OWSVerificationStateSyncMessage () @interface OWSVerificationStateSyncMessage ()
@property (nonatomic, readonly) NSMutableArray<OWSVerificationStateTuple *> *tuples; //@property (nonatomic, readonly) NSMutableArray<OWSVerificationStateTuple *> *tuples;
@property (nonatomic, readonly) OWSVerificationState verificationState;
@property (nonatomic, readonly) NSData *identityKey;
@end @end
#pragma mark - #pragma mark -
@implementation OWSVerificationStateSyncMessage @implementation OWSVerificationStateSyncMessage
//
//- (instancetype)init
//{
// self = [super init];
// if (!self) {
// return self;
// }
//
// _tuples = [NSMutableArray new];
//
// return self;
//}
- (instancetype)init - (instancetype)initWithVerificationState:(OWSVerificationState)verificationState
identityKey:(NSData *)identityKey
verificationForRecipientId:(NSString *)verificationForRecipientId
{ {
OWSAssert(identityKey.length == kIdentityKeyLength);
OWSAssert(verificationForRecipientId.length > 0);
// we only sync user's marking as un/verified. Never sync the conflicted state, the sibling device
// will figure that out on it's own.
OWSAssert(verificationState != OWSVerificationStateNoLongerVerified);
self = [super init]; self = [super init];
if (!self) { if (!self) {
return self; return self;
} }
_tuples = [NSMutableArray new]; _verificationState = verificationState;
_identityKey = identityKey;
_verificationForRecipientId = verificationForRecipientId;
return self; return self;
} }
- (void)addVerificationState:(OWSVerificationState)verificationState
identityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId
{
OWSAssert(identityKey.length == kIdentityKeyLength);
OWSAssert(recipientId.length > 0);
OWSAssert(self.tuples);
OWSVerificationStateTuple *tuple = [OWSVerificationStateTuple new];
tuple.verificationState = verificationState;
tuple.identityKey = identityKey;
tuple.recipientId = recipientId;
[self.tuples addObject:tuple];
}
- (OWSSignalServiceProtosSyncMessage *)buildSyncMessage - (OWSSignalServiceProtosSyncMessage *)buildSyncMessage
{ {
OWSAssert(self.tuples.count > 0); // OWSAssert(self.tuples.count > 0);
OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new]; OWSSignalServiceProtosSyncMessageBuilder *syncMessageBuilder = [OWSSignalServiceProtosSyncMessageBuilder new];
for (OWSVerificationStateTuple *tuple in self.tuples) {
OWSSignalServiceProtosSyncMessageVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosSyncMessageVerifiedBuilder new]; // for (OWSVerificationStateTuple *tuple in self.tuples) {
verifiedBuilder.destination = tuple.recipientId; // OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
verifiedBuilder.identityKey = tuple.identityKey; // verifiedBuilder.destination = tuple.recipientId;
switch (tuple.verificationState) { // verifiedBuilder.identityKey = tuple.identityKey;
// switch (tuple.verificationState) {
// case OWSVerificationStateDefault:
// verifiedBuilder.state = OWSSignalServiceProtosVerifiedStateDefault;
// break;
// case OWSVerificationStateVerified:
// verifiedBuilder.state = OWSSignalServiceProtosVerifiedStateVerified;
// break;
// case OWSVerificationStateNoLongerVerified:
// verifiedBuilder.state = OWSSignalServiceProtosVerifiedStateUnverified;
// break;
// }
// [syncMessageBuilder addVerified:[verifiedBuilder build]];
// }
//
OWSSignalServiceProtosVerifiedBuilder *verifiedBuilder = [OWSSignalServiceProtosVerifiedBuilder new];
verifiedBuilder.destination = self.verificationForRecipientId;
verifiedBuilder.identityKey = self.identityKey;
verifiedBuilder.state = ^{
switch (self.verificationState) {
case OWSVerificationStateDefault: case OWSVerificationStateDefault:
verifiedBuilder.state = OWSSignalServiceProtosSyncMessageVerifiedStateDefault; return OWSSignalServiceProtosVerifiedStateDefault;
break;
case OWSVerificationStateVerified: case OWSVerificationStateVerified:
verifiedBuilder.state = OWSSignalServiceProtosSyncMessageVerifiedStateVerified; return OWSSignalServiceProtosVerifiedStateVerified;
break;
case OWSVerificationStateNoLongerVerified: case OWSVerificationStateNoLongerVerified:
verifiedBuilder.state = OWSSignalServiceProtosSyncMessageVerifiedStateUnverified; return OWSSignalServiceProtosVerifiedStateUnverified;
break;
}
[syncMessageBuilder addVerified:[verifiedBuilder build]];
} }
}();
// Add 1-512 bytes of random padding bytes. // Add 1-512 bytes of random padding bytes.
size_t paddingLengthBytes = arc4random_uniform(512) + 1; size_t paddingLengthBytes = arc4random_uniform(512) + 1;
[syncMessageBuilder setPadding:[Cryptography generateRandomBytes:paddingLengthBytes]]; syncMessageBuilder.padding = [Cryptography generateRandomBytes:paddingLengthBytes];
return [syncMessageBuilder build]; return [syncMessageBuilder build];
} }
- (NSArray<NSString *> *)recipientIds //- (NSArray<NSString *> *)recipientIds
{ //{
NSMutableArray<NSString *> *result = [NSMutableArray new]; // NSMutableArray<NSString *> *result = [NSMutableArray new];
for (OWSVerificationStateTuple *tuple in self.tuples) { // for (OWSVerificationStateTuple *tuple in self.tuples) {
OWSAssert(tuple.recipientId.length > 0); // OWSAssert(tuple.recipientId.length > 0);
[result addObject:tuple.recipientId]; // [result addObject:tuple.recipientId];
} // }
//
return [result copy]; // return [result copy];
} //}
@end @end

View file

@ -17,7 +17,7 @@ extern NSString *const kNSNotificationName_IdentityStateDidChange;
extern const NSUInteger kIdentityKeyLength; extern const NSUInteger kIdentityKeyLength;
@class OWSRecipientIdentity; @class OWSRecipientIdentity;
@class OWSSignalServiceProtosSyncMessageVerified; @class OWSSignalServiceProtosVerified;
// This class can be safely accessed and used from any thread. // This class can be safely accessed and used from any thread.
@interface OWSIdentityManager : NSObject <IdentityKeyStore> @interface OWSIdentityManager : NSObject <IdentityKeyStore>
@ -49,7 +49,7 @@ extern const NSUInteger kIdentityKeyLength;
// Will try to send a sync message with all verification states. // Will try to send a sync message with all verification states.
- (void)syncAllVerificationStates; - (void)syncAllVerificationStates;
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerified *> *)verifieds; - (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified;
@end @end

View file

@ -455,7 +455,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
}]; }];
}]; }];
OWSVerificationStateSyncMessage *message = [OWSVerificationStateSyncMessage new]; NSMutableArray<OWSVerificationStateSyncMessage *> *messages = [NSMutableArray new];
for (NSString *recipientId in recipientIds) { for (NSString *recipientId in recipientIds) {
OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId]; OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (!recipientIdentity) { if (!recipientIdentity) {
@ -483,13 +483,17 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
recipientId); recipientId);
continue; continue;
} }
[message addVerificationState:recipientIdentity.verificationState OWSVerificationStateSyncMessage *message = [[OWSVerificationStateSyncMessage alloc]
initWithVerificationState:recipientIdentity.verificationState
identityKey:identityKey identityKey:identityKey
recipientId:recipientId]; verificationForRecipientId:recipientIdentity.recipientId];
[messages addObject:message];
} }
if (message.recipientIds.count > 0) { if (messages.count > 0) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
for (OWSVerificationStateSyncMessage *message in messages) {
[self sendSyncVerificationStateMessage:message]; [self sendSyncVerificationStateMessage:message];
}
}); });
} }
} }
@ -501,8 +505,8 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(self) @synchronized(self)
{ {
OWSVerificationStateSyncMessage *message =
[OWSVerificationStateSyncMessage new]; NSMutableArray<OWSVerificationStateSyncMessage *> *messages = [NSMutableArray new];
[OWSRecipientIdentity enumerateCollectionObjectsUsingBlock:^(OWSRecipientIdentity *recipientIdentity, BOOL *stop) { [OWSRecipientIdentity enumerateCollectionObjectsUsingBlock:^(OWSRecipientIdentity *recipientIdentity, BOOL *stop) {
OWSAssert(recipientIdentity); OWSAssert(recipientIdentity);
OWSAssert(recipientIdentity.recipientId.length > 0); OWSAssert(recipientIdentity.recipientId.length > 0);
@ -523,13 +527,17 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
return; return;
} }
[message addVerificationState:recipientIdentity.verificationState OWSVerificationStateSyncMessage *message = [[OWSVerificationStateSyncMessage alloc]
initWithVerificationState:recipientIdentity.verificationState
identityKey:identityKey identityKey:identityKey
recipientId:recipientIdentity.recipientId]; verificationForRecipientId:recipientIdentity.recipientId];
[messages addObject:message];
}]; }];
if (message.recipientIds.count > 0) { if (messages.count > 0) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
for (OWSVerificationStateSyncMessage *message in messages) {
[self sendSyncVerificationStateMessage:message]; [self sendSyncVerificationStateMessage:message];
}
}); });
} }
} }
@ -539,7 +547,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
- (void)sendSyncVerificationStateMessage:(OWSVerificationStateSyncMessage *)message - (void)sendSyncVerificationStateMessage:(OWSVerificationStateSyncMessage *)message
{ {
OWSAssert(message); OWSAssert(message);
OWSAssert(message.recipientIds.count > 0); OWSAssert(message.verificationForRecipientId.length > 0);
OWSAssert([NSThread isMainThread]); OWSAssert([NSThread isMainThread]);
[self.messageSender sendMessage:message [self.messageSender sendMessage:message
@ -547,7 +555,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
DDLogInfo(@"%@ Successfully sent verification state sync message", self.tag); DDLogInfo(@"%@ Successfully sent verification state sync message", self.tag);
// Record that this verification state was successfully synced. // Record that this verification state was successfully synced.
[self clearSyncMessageForRecipientIds:message.recipientIds]; [self clearSyncMessageForRecipientId:message.verificationForRecipientId];
} }
failure:^(NSError *error) { failure:^(NSError *error) {
DDLogError(@"%@ Failed to send verification state sync message with error: %@", self.tag, error); DDLogError(@"%@ Failed to send verification state sync message with error: %@", self.tag, error);
@ -557,67 +565,63 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
- (void)clearSyncMessageForRecipientId:(NSString *)recipientId - (void)clearSyncMessageForRecipientId:(NSString *)recipientId
{ {
OWSAssert(recipientId.length > 0); OWSAssert(recipientId.length > 0);
//
[self clearSyncMessageForRecipientIds:@[recipientId]]; // [self clearSyncMessageForRecipientIds:@[recipientId]];
} //}
//
- (void)clearSyncMessageForRecipientIds:(NSArray<NSString *> *)recipientIds //- (void)clearSyncMessageForRecipientIds:(NSArray<NSString *> *)recipientIds
{ //{
OWSAssert(recipientIds.count > 0); // OWSAssert(recipientIds.count > 0);
//
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ // dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
@synchronized(self) // @synchronized(self)
{ // {
for (NSString *recipientId in recipientIds) { // for (NSString *recipientId in recipientIds) {
[self.storageManager removeObjectForKey:recipientId [self.storageManager removeObjectForKey:recipientId
inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages]; inCollection:OWSIdentityManager_QueuedVerificationStateSyncMessages];
} // }
} // }
}); // });
} }
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerified *> *)verifieds - (void)processIncomingSyncMessage:(OWSSignalServiceProtosVerified *)verified
{ {
for (OWSSignalServiceProtosSyncMessageVerified *verified in verifieds) {
NSString *recipientId = verified.destination; NSString *recipientId = verified.destination;
if (recipientId.length < 1) { if (recipientId.length < 1) {
OWSFail(@"Verification state sync message missing recipientId."); OWSFail(@"Verification state sync message missing recipientId.");
continue; return;
} }
NSData *rawIdentityKey = verified.identityKey; NSData *rawIdentityKey = verified.identityKey;
if (rawIdentityKey.length != kIdentityKeyLength) { if (rawIdentityKey.length != kIdentityKeyLength) {
OWSFail(@"Verification state sync message for recipient: %@ with malformed identityKey: %@", OWSFail(@"Verification state sync message for recipient: %@ with malformed identityKey: %@",
recipientId, recipientId,
rawIdentityKey); rawIdentityKey);
continue; return;
} }
NSData *identityKey = [rawIdentityKey removeKeyType]; NSData *identityKey = [rawIdentityKey removeKeyType];
switch (verified.state) { switch (verified.state) {
case OWSSignalServiceProtosSyncMessageVerifiedStateDefault: case OWSSignalServiceProtosVerifiedStateDefault:
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault
recipientId:recipientId recipientId:recipientId
identityKey:identityKey identityKey:identityKey
overwriteOnConflict:NO]; overwriteOnConflict:NO];
break; break;
case OWSSignalServiceProtosSyncMessageVerifiedStateVerified: case OWSSignalServiceProtosVerifiedStateVerified:
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified [self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified
recipientId:recipientId recipientId:recipientId
identityKey:identityKey identityKey:identityKey
overwriteOnConflict:YES]; overwriteOnConflict:YES];
break; break;
case OWSSignalServiceProtosSyncMessageVerifiedStateUnverified: case OWSSignalServiceProtosVerifiedStateUnverified:
OWSFail(@"Verification state sync message for recipientId: %@ has unexpected value: %@.", OWSFail(@"Verification state sync message for recipientId: %@ has unexpected value: %@.",
recipientId, recipientId,
OWSVerificationStateToString(OWSVerificationStateNoLongerVerified)); OWSVerificationStateToString(OWSVerificationStateNoLongerVerified));
continue; return;
} }
}
if (verifieds.count > 0) {
[self fireIdentityStateChangeNotification]; [self fireIdentityStateChangeNotification];
} }
}
- (void)tryToApplyVerificationStateFromSyncMessage:(OWSVerificationState)verificationState - (void)tryToApplyVerificationStateFromSyncMessage:(OWSVerificationState)verificationState
recipientId:(NSString *)recipientId recipientId:(NSString *)recipientId

View file

@ -219,8 +219,9 @@ NS_ASSUME_NONNULL_BEGIN
[description appendString:@"Blocked"]; [description appendString:@"Blocked"];
} else if (syncMessage.read.count > 0) { } else if (syncMessage.read.count > 0) {
[description appendString:@"ReadReceipt"]; [description appendString:@"ReadReceipt"];
} else if (syncMessage.verified.count > 0){ } else if (syncMessage.hasVerified) {
NSString *verifiedString = [NSString stringWithFormat:@"Verifications: (%lu)", (unsigned long)syncMessage.verified.count]; NSString *verifiedString =
[NSString stringWithFormat:@"Verification for: %@", syncMessage.verified.destination];
[description appendString:verifiedString]; [description appendString:verifiedString];
} else { } else {
// Shouldn't happen // Shouldn't happen
@ -687,9 +688,8 @@ NS_ASSUME_NONNULL_BEGIN
[[OWSReadReceiptsProcessor alloc] initWithReadReceiptProtos:syncMessage.read [[OWSReadReceiptsProcessor alloc] initWithReadReceiptProtos:syncMessage.read
storageManager:self.storageManager]; storageManager:self.storageManager];
[readReceiptsProcessor process]; [readReceiptsProcessor process];
} else if (syncMessage.verified.count > 0) { } else if (syncMessage.hasVerified) {
DDLogInfo(@"%@ Received %ld verification state(s)", self.tag, (u_long)syncMessage.verified.count); DDLogInfo(@"%@ Received verification state for %@", self.tag, syncMessage.verified.destination);
[[OWSIdentityManager sharedManager] processIncomingSyncMessage:syncMessage.verified]; [[OWSIdentityManager sharedManager] processIncomingSyncMessage:syncMessage.verified];
} else { } else {
DDLogWarn(@"%@ Ignoring unsupported sync message.", self.tag); DDLogWarn(@"%@ Ignoring unsupported sync message.", self.tag);