IdentityKeyStore changes

1) Always accept keys from incoming messages

2) Block sending only if it's a recent change, or if always
   block is enabled

// FREEBIE
pull/1/head
Michael Kirk 8 years ago
parent 0a8c4203ea
commit f2f3acb897

@ -1,19 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSYapDatabaseObject.h"
NS_ASSUME_NONNULL_BEGIN
@interface TSPrivacyPreferences : TSYapDatabaseObject
- (instancetype)init NS_UNAVAILABLE;
+ (instancetype)sharedInstance;
@property BOOL shouldBlockOnIdentityChange;
@end
NS_ASSUME_NONNULL_END

@ -1,48 +0,0 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSPrivacyPreferences.h"
NS_ASSUME_NONNULL_BEGIN
NSString *const TSPrivacyPreferencesSingletonKey = @"TSPrivacyPreferences";
@implementation TSPrivacyPreferences
+ (instancetype)sharedInstance
{
static TSPrivacyPreferences *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [self fetchObjectWithUniqueID:TSPrivacyPreferencesSingletonKey];
if (!sharedInstance) {
sharedInstance = [[self alloc] initDefault];
}
});
return sharedInstance;
}
- (instancetype)initDefault
{
return [self initWithShouldBlockOnIdentityChange:YES];
}
- (instancetype)initWithShouldBlockOnIdentityChange:(BOOL)shouldBlockOnIdentityChange
{
self = [super initWithUniqueId:TSPrivacyPreferencesSingletonKey];
if (!self) {
return self;
}
_shouldBlockOnIdentityChange = shouldBlockOnIdentityChange;
OWSSingletonAssert();
return self;
}
@end
NS_ASSUME_NONNULL_END

@ -81,7 +81,10 @@ NS_ASSUME_NONNULL_BEGIN
// Saving a new identity mutates the session store so it must happen on the sessionStoreQueue
dispatch_async([OWSDispatch sessionStoreQueue], ^{
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey recipientId:self.envelope.source];
[[TSStorageManager sharedManager] saveRemoteIdentity:newKey
recipientId:self.envelope.source
approvedForBlockingUse:YES
approvedForNonBlockingUse:YES];
dispatch_async(dispatch_get_main_queue(), ^{
// Decrypt this and any old messages for the newly accepted key

@ -59,7 +59,10 @@ NSString *TSInvalidRecipientKey = @"TSInvalidRecipientKey";
{
// Saving a new identity mutates the session store so it must happen on the sessionStoreQueue
dispatch_async([OWSDispatch sessionStoreQueue], ^{
[[TSStorageManager sharedManager] saveRemoteIdentity:self.newIdentityKey recipientId:self.recipientId];
[[TSStorageManager sharedManager] saveRemoteIdentity:self.newIdentityKey
recipientId:self.recipientId
approvedForBlockingUse:YES
approvedForNonBlockingUse:YES];
});
}

@ -1,12 +1,13 @@
// Created by Frederic Jacobs.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSYapDatabaseObject.h"
#import "ContactsManagerProtocol.h"
@interface TSGroupModel : TSYapDatabaseObject
@property (nonatomic, strong) NSMutableArray *groupMemberIds;
@property (nonatomic, strong) NSMutableArray<NSString *> *groupMemberIds;
@property (nonatomic, strong) NSString *groupName;
@property (nonatomic, strong) NSData *groupId;
@ -14,7 +15,7 @@
@property (nonatomic, strong) UIImage *groupImage;
- (instancetype)initWithTitle:(NSString *)title
memberIds:(NSMutableArray *)memberIds
memberIds:(NSMutableArray<NSString *> *)memberIds
image:(UIImage *)image
groupId:(NSData *)groupId;

@ -1,5 +1,6 @@
// Created by Frederic Jacobs on 13/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "TSGroupModel.h"
#import "FunctionalUtil.h"
@ -8,7 +9,7 @@
#if TARGET_OS_IOS
- (instancetype)initWithTitle:(NSString *)title
memberIds:(NSMutableArray *)memberIds
memberIds:(NSMutableArray<NSString *> *)memberIds
image:(UIImage *)image
groupId:(NSData *)groupId
{

@ -0,0 +1,13 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@protocol TSPreferences <NSObject>
- (BOOL)isSendingIdentityApprovalRequired;
@end
NS_ASSUME_NONNULL_END

@ -1,5 +1,6 @@
// Created by Michael Kirk on 9/22/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
NS_ASSUME_NONNULL_BEGIN
@ -16,7 +17,7 @@ NS_ASSUME_NONNULL_BEGIN
/**
* Builds a fingerprint combining your current credentials with their most recently accepted credentials.
*/
- (OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId;
- (nullable OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId;
/**
* Builds a fingerprint combining your current credentials with the specified identity key.

@ -1,5 +1,6 @@
// Created by Michael Kirk on 9/22/16.
// Copyright © 2016 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSFingerprintBuilder.h"
#import "ContactsManagerProtocol.h"
@ -33,10 +34,15 @@ NS_ASSUME_NONNULL_BEGIN
return self;
}
- (OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId
- (nullable OWSFingerprint *)fingerprintWithTheirSignalId:(NSString *)theirSignalId
{
NSData *_Nullable theirIdentityKey = [self.storageManager identityKeyForRecipientId:theirSignalId];
if (theirIdentityKey == nil) {
OWSAssert(NO);
return nil;
}
return [self fingerprintWithTheirSignalId:theirSignalId theirIdentityKey:theirIdentityKey];
}

@ -0,0 +1,38 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <SignalServiceKit/TSYapDatabaseObject.h>
NS_ASSUME_NONNULL_BEGIN
@interface OWSRecipientIdentity : TSYapDatabaseObject
@property (nonatomic, readonly) NSString *recipientId;
@property (nonatomic, readonly) NSData *identityKey;
@property (nonatomic, readonly) NSDate *createdAt;
@property (nonatomic, readonly) BOOL wasSeen;
@property (nonatomic, readonly) BOOL isFirstKnownKey;
@property (nonatomic) BOOL approvedForBlockingUse;
@property (nonatomic) BOOL approvedForNonBlockingUse;
- (instancetype)initWithUniqueId:(NSString *)uniqueId NS_UNAVAILABLE;
- (nullable instancetype)initWithCoder:(NSCoder *)coder NS_DESIGNATED_INITIALIZER;
- (instancetype)initWithRecipientId:(NSString *)recipientId
identityKey:(NSData *)identityKey
isFirstKnownKey:(BOOL)isFirstKnownKey
createdAt:(NSDate *)createdAt
approvedForBlockingUse:(BOOL)approvedForBlockingUse
approvedForNonBlockingUse:(BOOL)approvedForNonBlockingUse NS_DESIGNATED_INITIALIZER;
- (void)markAsSeen;
#pragma mark - debug
+ (void)printAllIdentities;
@end
NS_ASSUME_NONNULL_END

@ -0,0 +1,96 @@
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import "OWSRecipientIdentity.h"
#import "TSStorageManager.h"
NS_ASSUME_NONNULL_BEGIN
/**
* 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)initWithRecipientId:(NSString *)recipientId
identityKey:(NSData *)identityKey
isFirstKnownKey:(BOOL)isFirstKnownKey
createdAt:(NSDate *)createdAt
approvedForBlockingUse:(BOOL)approvedForBlockingUse
approvedForNonBlockingUse:(BOOL)approvedForNonBlockingUse
{
self = [super initWithUniqueId:recipientId];
if (!self) {
return self;
}
_recipientId = recipientId;
_identityKey = identityKey;
_isFirstKnownKey = isFirstKnownKey;
_createdAt = createdAt;
_approvedForBlockingUse = approvedForBlockingUse;
_approvedForNonBlockingUse = approvedForNonBlockingUse;
_wasSeen = NO;
return self;
}
- (void)markAsSeen
{
_wasSeen = YES;
}
/**
* Override to disable the object cache to better enforce transaction semantics on the store.
* Note that it's still technically possible to access this collection from a different collection,
* but that should be considered a bug.
*/
+ (YapDatabaseConnection *)dbConnection
{
static dispatch_once_t onceToken;
static YapDatabaseConnection *sharedDBConnection;
dispatch_once(&onceToken, ^{
sharedDBConnection = [TSStorageManager sharedManager].newDatabaseConnection;
sharedDBConnection.objectCacheEnabled = NO;
sharedDBConnection.permittedTransactions = YDB_AnySyncTransaction;
});
return sharedDBConnection;
}
#pragma mark - debug
+ (void)printAllIdentities
{
DDLogInfo(@"%@ ### All Recipient Identities ###", self.tag);
__block int count = 0;
[self enumerateCollectionObjectsUsingBlock:^(id obj, BOOL *stop) {
count++;
if (![obj isKindOfClass:[self class]]) {
DDLogError(@"%@ unexpected object in collection: %@", self.tag, obj);
OWSAssert(NO);
return;
}
OWSRecipientIdentity *recipientIdentity = (OWSRecipientIdentity *)obj;
DDLogInfo(@"%@ Identity %d: %@", self.tag, count, recipientIdentity.debugDescription);
}];
}
#pragma mark - Logging
+ (NSString *)tag
{
return [NSString stringWithFormat:@"[%@]", self.class];
}
- (NSString *)tag
{
return self.class.tag;
}
@end
NS_ASSUME_NONNULL_END

@ -1,18 +1,29 @@
//
// TSStorageManager+IdentityKeyStore.h
// TextSecureKit
//
// Created by Frederic Jacobs on 06/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <AxolotlKit/IdentityKeyStore.h>
#import "TSStorageManager.h"
NS_ASSUME_NONNULL_BEGIN
extern NSString *const TSStorageManagerTrustedKeysCollection;
@interface TSStorageManager (IdentityKeyStore) <IdentityKeyStore>
/**
* Explicitly mark an identity as approved for blocking/nonblocking use
* e.g. in response to a user confirmation action.
*/
- (BOOL)saveRemoteIdentity:(NSData *)identityKey
recipientId:(NSString *)recipientId
approvedForBlockingUse:(BOOL)approvedForBlockingUse
approvedForNonBlockingUse:(BOOL)approvedForNonBlockingUse;
- (void)generateNewIdentityKey;
- (NSData *)identityKeyForRecipientId:(NSString *)recipientId;
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId;
- (void)removeIdentityKeyForRecipient:(NSString *)receipientId;
@end
NS_ASSUME_NONNULL_END

@ -7,19 +7,37 @@
#import "TSContactThread.h"
#import "TSErrorMessage.h"
#import "TSGroupThread.h"
#import "TSPrivacyPreferences.h"
#import "TSPreferences.h"
#import "TSStorageManager+IdentityKeyStore.h"
#import "TSStorageManager+SessionStore.h"
#import "TextSecureKitEnv.h"
#import "OWSRecipientIdentity.h"
#import <25519/Curve25519.h>
#define TSStorageManagerIdentityKeyStoreIdentityKey \
@"TSStorageManagerIdentityKeyStoreIdentityKey" // Key for our identity key
#define TSStorageManagerIdentityKeyStoreCollection @"TSStorageManagerIdentityKeyStoreCollection"
#define TSStorageManagerTrustedKeysCollection @"TSStorageManagerTrustedKeysCollection"
NS_ASSUME_NONNULL_BEGIN
// Storing our own identity key
NSString *const TSStorageManagerIdentityKeyStoreIdentityKey = @"TSStorageManagerIdentityKeyStoreIdentityKey";
NSString *const TSStorageManagerIdentityKeyStoreCollection = @"TSStorageManagerIdentityKeyStoreCollection";
// Storing recipients identity keys
NSString *const TSStorageManagerTrustedKeysCollection = @"TSStorageManagerTrustedKeysCollection";
// Don't trust an identity for sending to unless they've been around for at least this long
const NSTimeInterval kIdentityKeyStoreNonBlockingSecondsThreshold = 5.0;
@implementation TSStorageManager (IdentityKeyStore)
+ (id)sharedIdentityKeyLock
{
static id identityKeyLock;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
identityKeyLock = [NSObject new];
});
return identityKeyLock;
}
- (void)generateNewIdentityKey {
[self setObject:[Curve25519 generateKeyPair]
forKey:TSStorageManagerIdentityKeyStoreIdentityKey
@ -27,12 +45,17 @@
}
- (NSData *)identityKeyForRecipientId:(NSString *)recipientId {
return [self dataForKey:recipientId inCollection:TSStorageManagerTrustedKeysCollection];
- (nullable NSData *)identityKeyForRecipientId:(NSString *)recipientId
{
@synchronized([[self class] sharedIdentityKeyLock])
{
return [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId].identityKey;
}
}
- (ECKeyPair *)identityKeyPair {
- (nullable ECKeyPair *)identityKeyPair
{
return [self keyPairForKey:TSStorageManagerIdentityKeyStoreIdentityKey
inCollection:TSStorageManagerIdentityKeyStoreCollection];
}
@ -41,50 +64,180 @@
return (int)[TSAccountManager getOrGenerateRegistrationId];
}
- (void)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId {
NSData *existingKey = [self identityKeyForRecipientId:recipientId];
if ([existingKey isEqual:identityKey]) {
// Since we need to clear existing sessions when identity changes, we have to exit early
// when the identity key hasn't changed, lest we blow away valid sessions.
DDLogDebug(@"%s no-op since identity hasn't changed for recipient: %@", __PRETTY_FUNCTION__, recipientId);
return;
- (BOOL)saveRemoteIdentity:(NSData *)identityKey recipientId:(NSString *)recipientId
{
NSParameterAssert(identityKey != nil);
NSParameterAssert(recipientId != nil);
@synchronized([[self class] sharedIdentityKeyLock])
{
// If send-blocking is disabled at the time the identity was saved, we want to consider the identity as
// approved for blocking. Otherwise the user will see inexplicable failures when trying to send to this
// identity, if they later enabled send-blocking.
BOOL approvedForBlockingUse = ![TextSecureKitEnv sharedEnv].preferences.isSendingIdentityApprovalRequired;
return [self saveRemoteIdentity:identityKey
recipientId:recipientId
approvedForBlockingUse:approvedForBlockingUse
approvedForNonBlockingUse:NO];
}
}
DDLogInfo(@"%s invalidating any pre-existing sessions for recipientId: %@", __PRETTY_FUNCTION__, recipientId);
[self deleteAllSessionsForContact:recipientId];
- (BOOL)saveRemoteIdentity:(NSData *)identityKey
recipientId:(NSString *)recipientId
approvedForBlockingUse:(BOOL)approvedForBlockingUse
approvedForNonBlockingUse:(BOOL)approvedForNonBlockingUse
{
NSParameterAssert(identityKey != nil);
NSParameterAssert(recipientId != nil);
NSString const *logTag = @"[IdentityKeyStore]";
@synchronized ([[self class] sharedIdentityKeyLock]) {
OWSRecipientIdentity *existingIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
if (existingIdentity == nil) {
DDLogInfo(@"%@ saving first use identity for recipient: %@", logTag, recipientId);
[[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId
identityKey:identityKey
isFirstKnownKey:YES
createdAt:[NSDate new]
approvedForBlockingUse:approvedForBlockingUse
approvedForNonBlockingUse:approvedForNonBlockingUse] save];
return NO;
}
if (![existingIdentity.identityKey isEqual:identityKey]) {
DDLogInfo(@"%@ replacing identity for existing recipient: %@", logTag, recipientId);
[self createIdentityChangeInfoMessageForRecipientId:recipientId];
[[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId
identityKey:identityKey
isFirstKnownKey:NO
createdAt:[NSDate new]
approvedForBlockingUse:approvedForBlockingUse
approvedForNonBlockingUse:approvedForNonBlockingUse] save];
return YES;
}
if ([self isBlockingApprovalRequiredForIdentity:existingIdentity] || [self isNonBlockingApprovalRequiredForIdentity:existingIdentity]) {
existingIdentity.approvedForBlockingUse = approvedForBlockingUse;
existingIdentity.approvedForNonBlockingUse = approvedForNonBlockingUse;
[existingIdentity save];
return NO;
}
DDLogDebug(@"%@ no changes for identity saved for recipient: %@", logTag, recipientId);
return NO;
}
}
DDLogInfo(@"%s saving new identity key for recipientId: %@", __PRETTY_FUNCTION__, recipientId);
[self setObject:identityKey forKey:recipientId inCollection:TSStorageManagerTrustedKeysCollection];
- (BOOL)isTrustedIdentityKey:(NSData *)identityKey
recipientId:(NSString *)recipientId
direction:(TSMessageDirection)direction
{
NSParameterAssert(identityKey != nil);
NSParameterAssert(recipientId != nil);
NSParameterAssert(direction != TSMessageDirectionUnknown);
@synchronized([[self class] sharedIdentityKeyLock])
{
if ([[[self class] localNumber] isEqualToString:recipientId]) {
if ([[self identityKeyPair].publicKey isEqualToData:identityKey]) {
return YES;
} else {
DDLogError(@"%s Wrong identity: %@ for local key: %@",
__PRETTY_FUNCTION__,
identityKey,
[self identityKeyPair].publicKey);
OWSAssert(NO);
return NO;
}
}
switch (direction) {
case TSMessageDirectionIncoming: {
return YES;
}
case TSMessageDirectionOutgoing: {
OWSRecipientIdentity *existingIdentity = [OWSRecipientIdentity fetchObjectWithUniqueID:recipientId];
return [self isTrustedKey:identityKey forSendingToIdentity:existingIdentity];
}
default: {
DDLogError(@"%s unexpected message direction: %ld", __PRETTY_FUNCTION__, (long)direction);
OWSAssert(NO);
return NO;
}
}
}
}
- (BOOL)isTrustedIdentityKey:(NSData *)identityKey recipientId:(NSString *)recipientId {
NSData *existingKey = [self identityKeyForRecipientId:recipientId];
- (BOOL)isTrustedKey:(NSData *)identityKey forSendingToIdentity:(nullable OWSRecipientIdentity *)recipientIdentity
{
NSParameterAssert(identityKey != nil);
@synchronized([[self class] sharedIdentityKeyLock])
{
if (recipientIdentity == nil) {
DDLogDebug(@"%s Trusting on first use for recipient: %@", __PRETTY_FUNCTION__, recipientIdentity.recipientId);
return YES;
}
OWSAssert(recipientIdentity.identityKey != nil);
if (![recipientIdentity.identityKey isEqualToData:identityKey]) {
DDLogWarn(@"%s key mismatch for recipient: %@", __PRETTY_FUNCTION__, recipientIdentity.recipientId);
return NO;
}
if ([self isBlockingApprovalRequiredForIdentity:recipientIdentity]) {
DDLogWarn(@"%s not trusting until blocking approval is granted. recipient: %@",
__PRETTY_FUNCTION__,
recipientIdentity.recipientId);
return NO;
}
if ([self isNonBlockingApprovalRequiredForIdentity:recipientIdentity]) {
DDLogWarn(@"%s not trusting until non-blocking approval is granted. recipient: %@",
__PRETTY_FUNCTION__,
recipientIdentity.recipientId);
return NO;
}
if (!existingKey) {
return YES;
}
}
if ([existingKey isEqualToData:identityKey]) {
return YES;
}
- (BOOL)isBlockingApprovalRequiredForIdentity:(OWSRecipientIdentity *)recipientIdentity
{
NSParameterAssert(recipientIdentity != nil);
OWSAssert([TextSecureKitEnv sharedEnv].preferences != nil);
if (self.privacyPreferences.shouldBlockOnIdentityChange) {
return NO;
}
return !recipientIdentity.isFirstKnownKey &&
[TextSecureKitEnv sharedEnv].preferences.isSendingIdentityApprovalRequired &&
!recipientIdentity.approvedForBlockingUse;
}
DDLogInfo(@"Updating identity key for recipient:%@", recipientId);
[self createIdentityChangeInfoMessageForRecipientId:recipientId];
[self saveRemoteIdentity:identityKey recipientId:recipientId];
return YES;
- (BOOL)isNonBlockingApprovalRequiredForIdentity:(OWSRecipientIdentity *)recipientIdentity
{
NSParameterAssert(recipientIdentity != nil);
return !recipientIdentity.isFirstKnownKey &&
[[NSDate new] timeIntervalSinceDate:recipientIdentity.createdAt] < kIdentityKeyStoreNonBlockingSecondsThreshold &&
!recipientIdentity.approvedForNonBlockingUse;
}
- (void)removeIdentityKeyForRecipient:(NSString *)receipientId {
[self removeObjectForKey:receipientId inCollection:TSStorageManagerTrustedKeysCollection];
- (void)removeIdentityKeyForRecipient:(NSString *)recipientId
{
NSParameterAssert(recipientId != nil);
[[OWSRecipientIdentity fetchObjectWithUniqueID:recipientId] remove];
}
- (void)createIdentityChangeInfoMessageForRecipientId:(NSString *)recipientId
{
NSParameterAssert(recipientId != nil);
TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:recipientId];
OWSAssert(contactThread != nil);
[[TSErrorMessage nonblockingIdentityChangeInThread:contactThread recipientId:recipientId] save];
for (TSGroupThread *groupThread in [TSGroupThread groupThreadsWithRecipientId:recipientId]) {
@ -93,3 +246,5 @@
}
@end
NS_ASSUME_NONNULL_END

@ -10,7 +10,6 @@
@class ECKeyPair;
@class PreKeyRecord;
@class SignedPreKeyRecord;
@class TSPrivacyPreferences;
NS_ASSUME_NONNULL_BEGIN
@ -56,7 +55,6 @@ extern NSString *const TSUIDatabaseConnectionDidUpdateNotification;
- (void)purgeCollection:(NSString *)collection;
@property (nullable, nonatomic, readonly) YapDatabaseConnection *dbConnection;
@property (nonatomic, readonly) TSPrivacyPreferences *privacyPreferences;
@end

@ -15,7 +15,6 @@
#import "TSDatabaseSecondaryIndexes.h"
#import "TSDatabaseView.h"
#import "TSInteraction.h"
#import "TSPrivacyPreferences.h"
#import "TSThread.h"
#import <25519/Randomness.h>
#import <SAMKeychain/SAMKeychain.h>
@ -247,11 +246,6 @@ static NSString *keychainDBPassAccount = @"TSDatabasePass";
return self.database.newConnection;
}
- (TSPrivacyPreferences *)privacyPreferences
{
return [TSPrivacyPreferences sharedInstance];
}
- (BOOL)userSetPassword {
return FALSE;
}

@ -1,5 +1,6 @@
// Created by Frederic Jacobs on 16/11/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
//
#import <Mantle/MTLModel+NSCoding.h>
@ -73,8 +74,8 @@
*
* @return Instance of the object or nil if non-existent
*/
+ (instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID transaction:(YapDatabaseReadTransaction *)transaction;
+ (instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID;
+ (instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID transaction:(YapDatabaseReadTransaction *)transaction NS_SWIFT_NAME(fetch(uniqueId:transaction:));
+ (instancetype)fetchObjectWithUniqueID:(NSString *)uniqueID NS_SWIFT_NAME(fetch(uniqueId:));
/**
* Saves the object with a new YapDatabaseConnection

@ -8,13 +8,15 @@ NS_ASSUME_NONNULL_BEGIN
@class OWSMessageSender;
@protocol NotificationsProtocol;
@protocol OWSCallMessageHandler;
@protocol TSPreferences;
@interface TextSecureKitEnv : NSObject
- (instancetype)initWithCallMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
contactsManager:(id<ContactsManagerProtocol>)contactsManager
messageSender:(OWSMessageSender *)messageSender
notificationsManager:(id<NotificationsProtocol>)notificationsManager NS_DESIGNATED_INITIALIZER;
notificationsManager:(id<NotificationsProtocol>)notificationsManager
preferences:(id<TSPreferences>)preferences NS_DESIGNATED_INITIALIZER;
- (instancetype)init NS_UNAVAILABLE;
@ -25,6 +27,7 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic, readonly) id<ContactsManagerProtocol> contactsManager;
@property (nonatomic, readonly) OWSMessageSender *messageSender;
@property (nonatomic, readonly) id<NotificationsProtocol> notificationsManager;
@property (nonatomic, readonly) id<TSPreferences> preferences;
@end

@ -13,12 +13,14 @@ static TextSecureKitEnv *TextSecureKitEnvSharedInstance;
@synthesize callMessageHandler = _callMessageHandler,
contactsManager = _contactsManager,
messageSender = _messageSender,
notificationsManager = _notificationsManager;
notificationsManager = _notificationsManager,
preferences = _preferences;
- (instancetype)initWithCallMessageHandler:(id<OWSCallMessageHandler>)callMessageHandler
contactsManager:(id<ContactsManagerProtocol>)contactsManager
messageSender:(OWSMessageSender *)messageSender
notificationsManager:(id<NotificationsProtocol>)notificationsManager
preferences:(nonnull id<TSPreferences>)preferences
{
self = [super init];
if (!self) {
@ -29,6 +31,7 @@ static TextSecureKitEnv *TextSecureKitEnvSharedInstance;
_contactsManager = contactsManager;
_messageSender = messageSender;
_notificationsManager = notificationsManager;
_preferences = preferences;
return self;
}
@ -73,6 +76,12 @@ static TextSecureKitEnv *TextSecureKitEnvSharedInstance;
return _notificationsManager;
}
- (id<TSPreferences>)preferences
{
NSAssert(_preferences, @"Trying to access preferences before it's set.");
return _preferences;
}
@end
NS_ASSUME_NONNULL_END

Loading…
Cancel
Save