Sync verification state.

// FREEBIE
pull/1/head
Matthew Chen 9 years ago
parent 90d671924f
commit 07ac17fd39

@ -134,7 +134,6 @@ message SyncMessage {
optional State state = 1;
// The e164 phone number of the user.
optional string destination = 2;
// identityKey should be set IFF state is VERIFIED.
optional bytes identityKey = 3;
}

@ -11,7 +11,7 @@ NS_ASSUME_NONNULL_BEGIN
// identityKey should be set IFF verificationState == OWSVerificationStateVerified;
- (void)addVerificationState:(OWSVerificationState)verificationState
identityKey:(NSData * _Nullable)identityKey
identityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId;
// Returns the list of recipient ids referenced in this message.

@ -10,7 +10,7 @@ NS_ASSUME_NONNULL_BEGIN
@interface OWSVerificationStateTuple : NSObject
@property (nonatomic) OWSVerificationState verificationState;
@property (nonatomic, nullable) NSData *identityKey;
@property (nonatomic) NSData *identityKey;
@property (nonatomic) NSString *recipientId;
@end
@ -46,14 +46,12 @@ NS_ASSUME_NONNULL_BEGIN
}
- (void)addVerificationState:(OWSVerificationState)verificationState
identityKey:(NSData * _Nullable)identityKey
identityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId
{
OWSAssert(identityKey.length > 0);
OWSAssert(recipientId.length > 0);
OWSAssert(self.tuples);
OWSAssert((identityKey.length > 0) ==
verificationState == OWSVerificationStateVerified);
OWSVerificationStateTuple *tuple = [OWSVerificationStateTuple new];
tuple.verificationState = verificationState;
@ -70,18 +68,15 @@ NS_ASSUME_NONNULL_BEGIN
for (OWSVerificationStateTuple *tuple in self.tuples) {
OWSSignalServiceProtosSyncMessageVerificationBuilder *verificationBuilder = [OWSSignalServiceProtosSyncMessageVerificationBuilder new];
[verificationBuilder setDestination:tuple.recipientId];
[verificationBuilder setIdentityKey:tuple.identityKey];
switch (tuple.verificationState) {
case OWSVerificationStateDefault:
OWSAssert(!tuple.identityKey);
[verificationBuilder setState:OWSSignalServiceProtosSyncMessageVerificationStateDefault];
break;
case OWSVerificationStateVerified:
OWSAssert(tuple.identityKey.length > 0);
[verificationBuilder setState:OWSSignalServiceProtosSyncMessageVerificationStateVerified];
[verificationBuilder setIdentityKey:tuple.identityKey];
break;
case OWSVerificationStateNoLongerVerified:
OWSAssert(!tuple.identityKey);
[verificationBuilder setState:OWSSignalServiceProtosSyncMessageVerificationStateNoLongerVerified];
break;
}

@ -14,6 +14,7 @@ extern NSString *const TSStorageManagerTrustedKeysCollection;
extern NSString *const kNSNotificationName_IdentityStateDidChange;
@class OWSRecipientIdentity;
@class OWSSignalServiceProtosSyncMessageVerification;
// This class can be safely accessed and used from any thread.
@interface OWSIdentityManager : NSObject <IdentityKeyStore>
@ -43,6 +44,8 @@ extern NSString *const kNSNotificationName_IdentityStateDidChange;
// Will try to send a sync message with all verification states.
- (void)syncAllVerificationStates;
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerification *> *)verifications;
@end
NS_ASSUME_NONNULL_END

@ -214,24 +214,24 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
// it for the first time.
[self saveRemoteIdentity:identityKey recipientId:recipientId];
OWSRecipientIdentity *identity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
OWSRecipientIdentity *recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (identity == nil) {
if (recipientIdentity == nil) {
OWSFail(@"Missing expected identity: %@", recipientId);
return;
}
if (identity.verificationState == verificationState) {
if (recipientIdentity.verificationState == verificationState) {
return;
}
DDLogInfo(@"%@ setVerificationState: %@ (%@ -> %@)",
self.tag,
recipientId,
OWSVerificationStateToString(identity.verificationState),
OWSVerificationStateToString(recipientIdentity.verificationState),
OWSVerificationStateToString(verificationState));
[identity updateWithVerificationState:verificationState];
[recipientIdentity updateWithVerificationState:verificationState];
if (sendSyncMessage) {
[self enqueueSyncMessageForVerificationState:verificationState
@ -440,6 +440,10 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
OWSFail(@"Could not load recipient identity for recipientId: %@", recipientId);
continue;
}
if (recipientIdentity.recipientId.length < 1 || recipientIdentity.identityKey.length < 1) {
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientId);
continue;
}
if (recipientIdentity.verificationState == OWSVerificationStateNoLongerVerified) {
// We don't want to sync "no longer verified" state. Other clients can
// figure this out from the /profile/ endpoint, and this can cause data
@ -448,9 +452,7 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
continue;
}
[message addVerificationState:recipientIdentity.verificationState
identityKey:(recipientIdentity.verificationState == OWSVerificationStateVerified
? recipientIdentity.identityKey
: nil)
identityKey:recipientIdentity.identityKey
recipientId:recipientId];
}
if (message.recipientIds.count > 0) {
@ -476,10 +478,12 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
// Don't bother syncing default state.
return;
}
if (recipientIdentity.recipientId.length < 1 || recipientIdentity.identityKey.length < 1) {
OWSFail(@"Invalid recipient identity for recipientId: %@", recipientIdentity.recipientId);
return;
}
[message addVerificationState:recipientIdentity.verificationState
identityKey:(recipientIdentity.verificationState == OWSVerificationStateVerified
? recipientIdentity.identityKey
: nil)
identityKey:recipientIdentity.identityKey
recipientId:recipientIdentity.recipientId];
}];
if (message.recipientIds.count > 0) {
@ -528,6 +532,147 @@ NSString *const kNSNotificationName_IdentityStateDidChange = @"kNSNotificationNa
});
}
- (void)processIncomingSyncMessage:(NSArray<OWSSignalServiceProtosSyncMessageVerification *> *)verifications
{
for (OWSSignalServiceProtosSyncMessageVerification *verification in verifications) {
NSString *recipientId = [verification destination];
if (recipientId.length < 1) {
OWSFail(@"Verification state sync message missing recipientId.");
continue;
}
NSData *identityKey = [verification identityKey];
if (identityKey.length < 1) {
OWSFail(@"Verification state sync message missing identityKey.");
continue;
}
switch (verification.state) {
case OWSSignalServiceProtosSyncMessageVerificationStateDefault:
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateDefault
recipientId:recipientId
identityKey:identityKey
overwriteOnConflict:NO];
break;
case OWSSignalServiceProtosSyncMessageVerificationStateVerified:
[self tryToApplyVerificationStateFromSyncMessage:OWSVerificationStateVerified
recipientId:recipientId
identityKey:identityKey
overwriteOnConflict:YES];
break;
case OWSSignalServiceProtosSyncMessageVerificationStateNoLongerVerified:
OWSFail(@"Verification state sync message for recipientId: %@ has unexpected value: %@.",
recipientId,
OWSVerificationStateToString(OWSVerificationStateNoLongerVerified));
continue;
}
}
}
- (void)tryToApplyVerificationStateFromSyncMessage:(OWSVerificationState)verificationState
recipientId:(NSString *)recipientId
identityKey:(NSData *)identityKey
overwriteOnConflict:(BOOL)overwriteOnConflict
{
if (recipientId.length < 1) {
OWSFail(@"Verification state sync message missing recipientId.");
return;
}
if (identityKey.length < 1) {
OWSFail(@"Verification state sync message missing identityKey.");
return;
}
@synchronized(self)
{
OWSRecipientIdentity *_Nullable recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (!recipientIdentity) {
// There's no existing recipient identity for this recipient.
// We should probably create one.
if (verificationState == OWSVerificationStateDefault) {
// There's no point in creating a new recipient identity just to
// set its verification state to default.
return;
}
// Ensure a remote identity exists for this key. We may be learning about
// it for the first time.
[self saveRemoteIdentity:identityKey recipientId:recipientId];
recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (recipientIdentity == nil) {
OWSFail(@"Missing expected identity: %@", recipientId);
return;
}
if (![recipientIdentity.recipientId isEqualToString:recipientId]) {
OWSFail(@"recipientIdentity has unexpected recipientId: %@", recipientId);
return;
}
if (![recipientIdentity.identityKey isEqualToData:identityKey]) {
OWSFail(@"recipientIdentity has unexpected identityKey");
return;
}
if (recipientIdentity.verificationState == verificationState) {
return;
}
DDLogInfo(@"%@ setVerificationState: %@ (%@ -> %@)",
self.tag,
recipientId,
OWSVerificationStateToString(recipientIdentity.verificationState),
OWSVerificationStateToString(verificationState));
[recipientIdentity updateWithVerificationState:verificationState];
} else {
// There's an existing recipient identity for this recipient.
// We should update it.
if (![recipientIdentity.recipientId isEqualToString:recipientId]) {
OWSFail(@"recipientIdentity has unexpected recipientId: %@", recipientId);
return;
}
if (![recipientIdentity.identityKey isEqualToData:identityKey]) {
// The conflict case where we receive a verification sync message
// whose identity key disagrees with the local identity key for
// this recipient.
if (!overwriteOnConflict) {
DDLogWarn(@"recipientIdentity has non-matching identityKey");
return;
}
DDLogWarn(@"recipientIdentity has non-matching identityKey; overwriting.");
[self saveRemoteIdentity:identityKey recipientId:recipientId];
recipientIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (recipientIdentity == nil) {
OWSFail(@"Missing expected identity: %@", recipientId);
return;
}
if (![recipientIdentity.recipientId isEqualToString:recipientId]) {
OWSFail(@"recipientIdentity has unexpected recipientId: %@", recipientId);
return;
}
if (![recipientIdentity.identityKey isEqualToData:identityKey]) {
OWSFail(@"recipientIdentity has unexpected identityKey");
return;
}
}
if (recipientIdentity.verificationState == verificationState) {
return;
}
[recipientIdentity updateWithVerificationState:OWSVerificationStateDefault];
}
}
}
#pragma mark - Notifications
- (void)applicationDidBecomeActive:(NSNotification *)notification

@ -695,6 +695,10 @@ NS_ASSUME_NONNULL_BEGIN
[[OWSReadReceiptsProcessor alloc] initWithReadReceiptProtos:syncMessage.read
storageManager:self.storageManager];
[readReceiptsProcessor process];
} else if (syncMessage.verification.count > 0) {
DDLogInfo(@"%@ Received %ld verification state(s)", self.tag, (u_long)syncMessage.verification.count);
[[OWSIdentityManager sharedManager] processIncomingSyncMessage:syncMessage.verification];
} else {
DDLogWarn(@"%@ Ignoring unsupported sync message.", self.tag);
}

Loading…
Cancel
Save