mirror of https://github.com/oxen-io/session-ios
				
				
				
			
			You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
	
	
		
			185 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Objective-C
		
	
			
		
		
	
	
			185 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			Objective-C
		
	
| //
 | |
| //  Copyright (c) 2018 Open Whisper Systems. All rights reserved.
 | |
| //
 | |
| 
 | |
| #import "OWSRecipientIdentity.h"
 | |
| #import "OWSIdentityManager.h"
 | |
| #import "OWSPrimaryStorage+SessionStore.h"
 | |
| #import "OWSPrimaryStorage.h"
 | |
| #import <SignalCoreKit/Cryptography.h>
 | |
| #import <SignalUtilitiesKit/SignalUtilitiesKit-Swift.h>
 | |
| #import <YapDatabase/YapDatabase.h>
 | |
| 
 | |
| NS_ASSUME_NONNULL_BEGIN
 | |
| 
 | |
| NSString *OWSVerificationStateToString(OWSVerificationState verificationState)
 | |
| {
 | |
|     switch (verificationState) {
 | |
|         case OWSVerificationStateDefault:
 | |
|             return @"OWSVerificationStateDefault";
 | |
|         case OWSVerificationStateVerified:
 | |
|             return @"OWSVerificationStateVerified";
 | |
|         case OWSVerificationStateNoLongerVerified:
 | |
|             return @"OWSVerificationStateNoLongerVerified";
 | |
|     }
 | |
| }
 | |
| 
 | |
| SNProtoVerifiedState OWSVerificationStateToProtoState(OWSVerificationState verificationState)
 | |
| {
 | |
|     switch (verificationState) {
 | |
|         case OWSVerificationStateDefault:
 | |
|             return SNProtoVerifiedStateDefault;
 | |
|         case OWSVerificationStateVerified:
 | |
|             return SNProtoVerifiedStateVerified;
 | |
|         case OWSVerificationStateNoLongerVerified:
 | |
|             return SNProtoVerifiedStateUnverified;
 | |
|     }
 | |
| }
 | |
| 
 | |
| SNProtoVerified *_Nullable BuildVerifiedProtoWithRecipientId(NSString *destinationRecipientId,
 | |
|     NSData *identityKey,
 | |
|     OWSVerificationState verificationState,
 | |
|     NSUInteger paddingBytesLength)
 | |
| {
 | |
|     OWSCAssertDebug(identityKey.length == kIdentityKeyLength);
 | |
|     OWSCAssertDebug(destinationRecipientId.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.
 | |
|     OWSCAssertDebug(verificationState != OWSVerificationStateNoLongerVerified);
 | |
| 
 | |
|     SNProtoVerifiedBuilder *verifiedBuilder = [SNProtoVerified builderWithDestination:destinationRecipientId];
 | |
|     verifiedBuilder.identityKey = identityKey;
 | |
|     verifiedBuilder.state = OWSVerificationStateToProtoState(verificationState);
 | |
| 
 | |
|     if (paddingBytesLength > 0) {
 | |
|         // We add the same amount of padding in the VerificationStateSync message and it's coresponding NullMessage so
 | |
|         // that the sync message is indistinguishable from an outgoing Sent transcript corresponding to the NullMessage.
 | |
|         // We pad the NullMessage so as to obscure it's content. The sync message (like all sync messages) will be
 | |
|         // *additionally* padded by the superclass while being sent. The end result is we send a NullMessage of a
 | |
|         // non-distinct size, and a verification sync which is ~1-512 bytes larger then that.
 | |
|         verifiedBuilder.nullMessage = [Cryptography generateRandomBytes:paddingBytesLength];
 | |
|     }
 | |
| 
 | |
|     NSError *error;
 | |
|     SNProtoVerified *_Nullable verifiedProto = [verifiedBuilder buildAndReturnError:&error];
 | |
|     if (error || !verifiedProto) {
 | |
|         OWSCFailDebug(@"%@ could not build protobuf: %@", @"[BuildVerifiedProtoWithRecipientId]", error);
 | |
|         return nil;
 | |
|     }
 | |
|     return verifiedProto;
 | |
| }
 | |
| 
 | |
| @interface OWSRecipientIdentity ()
 | |
| 
 | |
| @property (atomic) OWSVerificationState verificationState;
 | |
| 
 | |
| @end
 | |
| 
 | |
| /**
 | |
|  * Record for a recipients identity key and some meta data around it used to make trust decisions.
 | |
|  *
 | |
|  * NOTE: Instances of this class MUST only be retrieved/persisted via it's internal `dbConnection`,
 | |
|  *       which makes some special accomodations to enforce consistency.
 | |
|  */
 | |
| @implementation OWSRecipientIdentity
 | |
| 
 | |
| - (instancetype)initWithCoder:(NSCoder *)coder
 | |
| {
 | |
|     self = [super initWithCoder:coder];
 | |
| 
 | |
|     if (self) {
 | |
|         if (![coder decodeObjectForKey:@"verificationState"]) {
 | |
|             _verificationState = OWSVerificationStateDefault;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| - (instancetype)initWithRecipientId:(NSString *)recipientId
 | |
|                         identityKey:(NSData *)identityKey
 | |
|                     isFirstKnownKey:(BOOL)isFirstKnownKey
 | |
|                           createdAt:(NSDate *)createdAt
 | |
|                   verificationState:(OWSVerificationState)verificationState
 | |
| {
 | |
|     self = [super initWithUniqueId:recipientId];
 | |
|     if (!self) {
 | |
|         return self;
 | |
|     }
 | |
|     
 | |
|     _recipientId = recipientId;
 | |
|     _identityKey = identityKey;
 | |
|     _isFirstKnownKey = isFirstKnownKey;
 | |
|     _createdAt = createdAt;
 | |
|     _verificationState = verificationState;
 | |
| 
 | |
|     return self;
 | |
| }
 | |
| 
 | |
| - (void)updateWithVerificationState:(OWSVerificationState)verificationState
 | |
|                         transaction:(YapDatabaseReadWriteTransaction *)transaction
 | |
| {
 | |
|     OWSAssertDebug(transaction);
 | |
| 
 | |
|     // Ensure changes are persisted without clobbering any work done on another thread or instance.
 | |
|     [self updateWithChangeBlock:^(OWSRecipientIdentity *_Nonnull obj) {
 | |
|         obj.verificationState = verificationState;
 | |
|     }
 | |
|                     transaction:transaction];
 | |
| }
 | |
| 
 | |
| - (void)updateWithChangeBlock:(void (^)(OWSRecipientIdentity *obj))changeBlock
 | |
|                   transaction:(YapDatabaseReadWriteTransaction *)transaction
 | |
| {
 | |
|     OWSAssertDebug(transaction);
 | |
| 
 | |
|     changeBlock(self);
 | |
| 
 | |
|     OWSRecipientIdentity *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
 | |
|     if (latest == nil) {
 | |
|         [self saveWithTransaction:transaction];
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     changeBlock(latest);
 | |
|     [latest saveWithTransaction:transaction];
 | |
| }
 | |
| 
 | |
| - (void)updateWithChangeBlock:(void (^)(OWSRecipientIdentity *obj))changeBlock
 | |
| {
 | |
|     changeBlock(self);
 | |
| 
 | |
|     [LKStorage writeSyncWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) {
 | |
|         OWSRecipientIdentity *latest = [[self class] fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
 | |
|         if (latest == nil) {
 | |
|             [self saveWithTransaction:transaction];
 | |
|             return;
 | |
|         }
 | |
|         
 | |
|         changeBlock(latest);
 | |
|         [latest saveWithTransaction:transaction];
 | |
|     }];
 | |
| }
 | |
| 
 | |
| #pragma mark - debug
 | |
| 
 | |
| + (void)printAllIdentities
 | |
| {
 | |
|     OWSLogInfo(@"### All Recipient Identities ###");
 | |
|     __block int count = 0;
 | |
|     [self enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) {
 | |
|         count++;
 | |
|         if (![obj isKindOfClass:[self class]]) {
 | |
|             OWSFailDebug(@"unexpected object in collection: %@", obj);
 | |
|             return;
 | |
|         }
 | |
|         OWSRecipientIdentity *recipientIdentity = (OWSRecipientIdentity *)obj;
 | |
| 
 | |
|         OWSLogInfo(@"Identity %d: %@", count, recipientIdentity.debugDescription);
 | |
|     }];
 | |
| }
 | |
| 
 | |
| @end
 | |
| 
 | |
| NS_ASSUME_NONNULL_END
 |