diff --git a/Podfile b/Podfile index 55d7dcd08..4de5fa3a0 100644 --- a/Podfile +++ b/Podfile @@ -3,10 +3,10 @@ source 'https://github.com/CocoaPods/Specs.git' target 'Signal' do pod 'SocketRocket', :git => 'https://github.com/facebook/SocketRocket.git' - pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git' - #pod 'AxolotlKit', path: '../SignalProtocolKit' - pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git' - #pod 'SignalServiceKit', path: '../SignalServiceKit' + #pod 'AxolotlKit', git: 'https://github.com/WhisperSystems/SignalProtocolKit.git' + pod 'AxolotlKit', path: '../SignalProtocolKit' + #pod 'SignalServiceKit', git: 'https://github.com/WhisperSystems/SignalServiceKit.git' + pod 'SignalServiceKit', path: '../SignalServiceKit' pod 'OpenSSL' pod 'JSQMessagesViewController', git: 'https://github.com/WhisperSystems/JSQMessagesViewController.git', branch: 'mkirk/position-edit-menu' #pod 'JSQMessagesViewController' path: '../JSQMessagesViewController' diff --git a/Podfile.lock b/Podfile.lock index 73abf539f..eb9ebbc47 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -109,35 +109,29 @@ PODS: - YapDatabase/SQLCipher/Core DEPENDENCIES: - - AxolotlKit (from `https://github.com/WhisperSystems/SignalProtocolKit.git`) + - AxolotlKit (from `../SignalProtocolKit`) - JSQMessagesViewController (from `https://github.com/WhisperSystems/JSQMessagesViewController.git`, branch `mkirk/position-edit-menu`) - OpenSSL - PureLayout - Reachability - - SignalServiceKit (from `https://github.com/WhisperSystems/SignalServiceKit.git`) + - SignalServiceKit (from `../SignalServiceKit`) - SocketRocket (from `https://github.com/facebook/SocketRocket.git`) EXTERNAL SOURCES: AxolotlKit: - :git: https://github.com/WhisperSystems/SignalProtocolKit.git + :path: "../SignalProtocolKit" JSQMessagesViewController: :branch: mkirk/position-edit-menu :git: https://github.com/WhisperSystems/JSQMessagesViewController.git SignalServiceKit: - :git: https://github.com/WhisperSystems/SignalServiceKit.git + :path: "../SignalServiceKit" SocketRocket: :git: https://github.com/facebook/SocketRocket.git CHECKOUT OPTIONS: - AxolotlKit: - :commit: bce663486ac34c70594deae8260b3cd29dd086e9 - :git: https://github.com/WhisperSystems/SignalProtocolKit.git JSQMessagesViewController: :commit: 7054e4b13ee5bcd6d524adb6dc9a726e8c466308 :git: https://github.com/WhisperSystems/JSQMessagesViewController.git - SignalServiceKit: - :commit: 0a8c4203ead4e283e930236e37f243c022af5c07 - :git: https://github.com/WhisperSystems/SignalServiceKit.git SocketRocket: :commit: 877ac7438be3ad0b45ef5ca3969574e4b97112bf :git: https://github.com/facebook/SocketRocket.git @@ -164,6 +158,6 @@ SPEC CHECKSUMS: UnionFind: c33be5adb12983981d6e827ea94fc7f9e370f52d YapDatabase: cd911121580ff16675f65ad742a9eb0ab4d9e266 -PODFILE CHECKSUM: 48e80d7f1e049bbf544a689fdfdf33e8196c640a +PODFILE CHECKSUM: dc5ed308ade575a81ccadf5c485990530353c4ee COCOAPODS: 1.2.1 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 94b3cae64..4670bcd0a 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -141,12 +141,14 @@ 45847E871E4283C30080EAB3 /* Intents.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 45847E861E4283C30080EAB3 /* Intents.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 45855F371D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */; }; 45855F381D9498A40084F340 /* OWSContactAvatarBuilder.m in Sources */ = {isa = PBXBuildFile; fileRef = 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */; }; + 4585C4601ED4FD0400896AEA /* OWS104CreateRecipientIdentities.m in Sources */ = {isa = PBXBuildFile; fileRef = 4585C45F1ED4FD0400896AEA /* OWS104CreateRecipientIdentities.m */; }; 458967111DC117CC00E9DD21 /* AccountManagerTest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458967101DC117CC00E9DD21 /* AccountManagerTest.swift */; }; 458DE9D61DEE3FD00071BB03 /* PeerConnectionClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */; }; 458DE9D91DEE7B360071BB03 /* OWSWebRTCDataProtos.pb.m in Sources */ = {isa = PBXBuildFile; fileRef = 458DE9D81DEE7B360071BB03 /* OWSWebRTCDataProtos.pb.m */; }; 458E38371D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38361D668EBF0094BD24 /* OWSDeviceProvisioningURLParser.m */; }; 458E383A1D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 458E38391D6699FA0094BD24 /* OWSDeviceProvisioningURLParserTest.m */; }; 459311FC1D75C948008DD4F0 /* OWSDeviceTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */; }; + 459B1C671ED480BB00506A04 /* MarkIdentityAsSeenJob.swift in Sources */ = {isa = PBXBuildFile; fileRef = 459B1C661ED480BB00506A04 /* MarkIdentityAsSeenJob.swift */; }; 45A6DAD61EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; 45A6DAD71EBBF85500893231 /* ReminderView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45A6DAD51EBBF85500893231 /* ReminderView.swift */; }; 45AE48511E0732D6004D96C2 /* TurnServerInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */; }; @@ -553,6 +555,8 @@ 45847E861E4283C30080EAB3 /* Intents.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Intents.framework; path = System/Library/Frameworks/Intents.framework; sourceTree = SDKROOT; }; 45855F351D9498A40084F340 /* OWSContactAvatarBuilder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSContactAvatarBuilder.h; sourceTree = ""; }; 45855F361D9498A40084F340 /* OWSContactAvatarBuilder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSContactAvatarBuilder.m; sourceTree = ""; }; + 4585C45E1ED4FD0400896AEA /* OWS104CreateRecipientIdentities.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = OWS104CreateRecipientIdentities.h; path = Migrations/OWS104CreateRecipientIdentities.h; sourceTree = ""; }; + 4585C45F1ED4FD0400896AEA /* OWS104CreateRecipientIdentities.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = OWS104CreateRecipientIdentities.m; path = Migrations/OWS104CreateRecipientIdentities.m; sourceTree = ""; }; 4589670F1DC117CC00E9DD21 /* SignalTests-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SignalTests-Bridging-Header.h"; sourceTree = ""; }; 458967101DC117CC00E9DD21 /* AccountManagerTest.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = AccountManagerTest.swift; path = Models/AccountManagerTest.swift; sourceTree = ""; }; 458DE9D51DEE3FD00071BB03 /* PeerConnectionClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PeerConnectionClient.swift; sourceTree = ""; }; @@ -565,6 +569,7 @@ 459311FB1D75C948008DD4F0 /* OWSDeviceTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSDeviceTableViewCell.m; sourceTree = ""; }; 4597E94E1D8313C100040CDE /* sq */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = sq; path = translations/sq.lproj/Localizable.strings; sourceTree = ""; }; 4597E94F1D8313CB00040CDE /* bg */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = bg; path = translations/bg.lproj/Localizable.strings; sourceTree = ""; }; + 459B1C661ED480BB00506A04 /* MarkIdentityAsSeenJob.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = MarkIdentityAsSeenJob.swift; path = Jobs/MarkIdentityAsSeenJob.swift; sourceTree = ""; }; 45A6DAD51EBBF85500893231 /* ReminderView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ReminderView.swift; sourceTree = ""; }; 45AE48501E0732D6004D96C2 /* TurnServerInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TurnServerInfo.swift; sourceTree = ""; }; 45B201741DAECBFD00C461E0 /* Signal-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Signal-Bridging-Header.h"; sourceTree = ""; }; @@ -1067,6 +1072,8 @@ 45387B031E36D650005D00B3 /* OWS102MoveLoggingPreferenceToUserDefaults.m */, 450573FC1E78A06D00615BB4 /* OWS103EnableVideoCalling.h */, 450573FD1E78A06D00615BB4 /* OWS103EnableVideoCalling.m */, + 4585C45E1ED4FD0400896AEA /* OWS104CreateRecipientIdentities.h */, + 4585C45F1ED4FD0400896AEA /* OWS104CreateRecipientIdentities.m */, ); name = Migrations; sourceTree = ""; @@ -1139,6 +1146,7 @@ 451DE9FC1DC1A28200810E42 /* SyncPushTokensJob.swift */, 45D231761DC7E8F10034FA89 /* SessionResetJob.swift */, 452ECA4C1E087E7200E2F016 /* MessageFetcherJob.swift */, + 459B1C661ED480BB00506A04 /* MarkIdentityAsSeenJob.swift */, ); name = Jobs; sourceTree = ""; @@ -2085,6 +2093,7 @@ 76EB062618170B33006006FC /* Queue.m in Sources */, D221A09A169C9E5E00537ABF /* main.m in Sources */, 345671011E89A5F1006EE662 /* ThreadUtil.m in Sources */, + 4585C4601ED4FD0400896AEA /* OWS104CreateRecipientIdentities.m in Sources */, 45843D1F1D2236B30013E85A /* OWSContactsSearcher.m in Sources */, 450873C31D9D5149006B54F2 /* OWSExpirationTimerView.m in Sources */, B6258B331C29E2E60014138E /* NotificationsManager.m in Sources */, @@ -2105,6 +2114,7 @@ 45C681C61D305C9E0050903A /* OWSDisplayedMessageCollectionViewCell.m in Sources */, 34F3089F1ECA580B00BB7697 /* OWSUnreadIndicatorCell.m in Sources */, 34B3F8861E8DF1700035BE1A /* NotificationSettingsOptionsViewController.m in Sources */, + 459B1C671ED480BB00506A04 /* MarkIdentityAsSeenJob.swift in Sources */, 452ECA4D1E087E7200E2F016 /* MessageFetcherJob.swift in Sources */, 452EA0971EA662330078744B /* AttachmentPointerAdapter.swift in Sources */, 34DFCB851E8E04B500053165 /* AddToBlockListViewController.m in Sources */, diff --git a/Signal.xcodeproj/xcshareddata/xcschemes/Signal.xcscheme b/Signal.xcodeproj/xcshareddata/xcschemes/Signal.xcscheme index 6154f07a1..c74cfaba0 100644 --- a/Signal.xcodeproj/xcshareddata/xcschemes/Signal.xcscheme +++ b/Signal.xcodeproj/xcshareddata/xcschemes/Signal.xcscheme @@ -28,7 +28,7 @@ buildForAnalyzing = "YES"> diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 5a4047aeb..11bb86009 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -201,7 +201,8 @@ static NSString *const kURLHostVerifyPrefix = @"verify"; [[TextSecureKitEnv alloc] initWithCallMessageHandler:[Environment getCurrent].callMessageHandler contactsManager:[Environment getCurrent].contactsManager messageSender:[Environment getCurrent].messageSender - notificationsManager:[Environment getCurrent].notificationsManager]; + notificationsManager:[Environment getCurrent].notificationsManager + preferences:[Environment getCurrent].preferences]; [TextSecureKitEnv setSharedEnv:sharedEnv]; [[TSStorageManager sharedManager] setupDatabase]; diff --git a/Signal/src/Jobs/MarkIdentityAsSeenJob.swift b/Signal/src/Jobs/MarkIdentityAsSeenJob.swift new file mode 100644 index 000000000..6fb6d08ae --- /dev/null +++ b/Signal/src/Jobs/MarkIdentityAsSeenJob.swift @@ -0,0 +1,51 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +import Foundation + +@objc +class MarkIdentityAsSeenJob: NSObject { + let TAG = "[MarkIdentityAsSeenJob]" + + private let thread: TSThread + + public class func run(thread: TSThread) { + MarkIdentityAsSeenJob(thread: thread).run() + } + + init(thread: TSThread) { + self.thread = thread + } + + public func run() { + switch self.thread { + case let contactThread as TSContactThread: + markAsSeenIfNecessary(recipientId: contactThread.contactIdentifier()) + case let groupThread as TSGroupThread: + groupThread.groupModel.groupMemberIds?.forEach { memberId in + guard let recipientId = memberId as? String else { + Logger.error("\(TAG) unexecpted type in group members.") + assertionFailure("\(TAG) unexecpted type in group members.") + return + } + + markAsSeenIfNecessary(recipientId: recipientId) + } + default: + assertionFailure("Unexpected thread type: \(self.thread)") + } + } + + private func markAsSeenIfNecessary(recipientId: String) { + guard let identity = OWSRecipientIdentity.fetch(uniqueId: recipientId) else { + Logger.verbose("\(TAG) no existing identity for recipient: \(recipientId). No messages with them yet?") + return + } + if !identity.wasSeen { + Logger.info("\(TAG) marking identity as seen for recipient: \(recipientId)") + identity.markAsSeen() + identity.save() + } + } +} diff --git a/Signal/src/Signal-Bridging-Header.h b/Signal/src/Signal-Bridging-Header.h index fda5f8fb7..f33721a18 100644 --- a/Signal/src/Signal-Bridging-Header.h +++ b/Signal/src/Signal-Bridging-Header.h @@ -56,6 +56,7 @@ #import #import #import +#import #import #import #import @@ -68,6 +69,7 @@ #import #import #import +#import #import #import #import diff --git a/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m b/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m index aa1602024..7bd1c6361 100644 --- a/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m +++ b/Signal/src/ViewControllers/DebugUI/DebugUITableViewController.m @@ -42,7 +42,11 @@ NS_ASSUME_NONNULL_BEGIN addSection:[OWSTableSection sectionWithTitle:@"Session State" items:@[ - [OWSTableItem itemWithTitle:@"Print all sessions" + [OWSTableItem itemWithTitle:@"Log All Recipient Identities" + actionBlock:^{ + [OWSRecipientIdentity printAllIdentities]; + }], + [OWSTableItem itemWithTitle:@"Log All Sessions" actionBlock:^{ dispatch_async([OWSDispatch sessionStoreQueue], ^{ [[TSStorageManager sharedManager] printAllSessions]; @@ -76,7 +80,6 @@ NS_ASSUME_NONNULL_BEGIN messageSender:[Environment getCurrent].messageSender storageManager:[TSStorageManager sharedManager]]; }] - ]]]; [contents addSection:[DebugUIContacts section]]; diff --git a/Signal/src/ViewControllers/MessagesViewController.m b/Signal/src/ViewControllers/MessagesViewController.m index 8401cab28..2409328b7 100644 --- a/Signal/src/ViewControllers/MessagesViewController.m +++ b/Signal/src/ViewControllers/MessagesViewController.m @@ -751,6 +751,7 @@ typedef enum : NSUInteger { // all messages as read. [self ensureThreadOffersAndIndicators]; + // TODO: Why are we marking as read here? Shouldn't our repeating 1-sec read timer be sufficient? [self markAllMessagesAsRead]; [self.uiDatabaseConnection beginLongLivedReadTransaction]; @@ -1177,11 +1178,16 @@ typedef enum : NSUInteger { - (void)startReadTimer { self.readTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self - selector:@selector(markAllMessagesAsRead) + selector:@selector(readTimerDidFire) userInfo:nil repeats:YES]; } +- (void)readTimerDidFire +{ + [self markAllMessagesAsRead]; +} + - (void)cancelReadTimer { [self.readTimer invalidate]; } @@ -1205,6 +1211,7 @@ typedef enum : NSUInteger { _callOnOpen = NO; } [self updateNavigationBarSubtitleLabel]; + [MarkIdentityAsSeenJob runWithThread:self.thread]; } - (void)viewWillDisappear:(BOOL)animated { @@ -1523,6 +1530,8 @@ typedef enum : NSUInteger { [[OWSFingerprintBuilder alloc] initWithStorageManager:self.storageManager contactsManager:self.contactsManager]; OWSFingerprint *fingerprint = [builder fingerprintWithTheirSignalId:theirSignalId theirIdentityKey:theirIdentityKey]; + + // TODO: Why are we marking as read here? Shouldn't our repeating 1-sec read timer be sufficient? [self markAllMessagesAsRead]; NSString *contactName = [self.contactsManager displayNameForPhoneIdentifier:theirSignalId]; @@ -2552,11 +2561,31 @@ typedef enum : NSUInteger { [self tappedUnknownContactBlockOfferMessage:(OWSUnknownContactBlockOfferMessage *)message]; } else if (message.errorType == TSErrorMessageInvalidMessage) { [self tappedCorruptedMessage:message]; + } else if (message.errorType == TSErrorMessageNonBlockingIdentityChange) { + [self tappedNonBlockingIdentityChangeForRecipientId:message.recipientId]; } else { DDLogWarn(@"%@ Unhandled tap for error message:%@", self.tag, message); } } +- (void)tappedNonBlockingIdentityChangeForRecipientId:(NSString *)signalId +{ + NSParameterAssert(signalId != nil); + + OWSFingerprintBuilder *fingerprintBuilder = + [[OWSFingerprintBuilder alloc] initWithStorageManager:self.storageManager contactsManager:self.contactsManager]; + + OWSFingerprint *fingerprint = [fingerprintBuilder fingerprintWithTheirSignalId:signalId]; + + FingerprintViewController *fingerprintViewController = + [[UIStoryboard main] instantiateViewControllerWithIdentifier:@"FingerprintViewController"]; + + NSString *contactName = [self.contactsManager displayNameForPhoneIdentifier:signalId]; + [fingerprintViewController configureWithThread:self.thread fingerprint:fingerprint contactName:contactName]; + + [self presentViewController:fingerprintViewController animated:YES completion:nil]; +} + - (void)handleInfoMessageTap:(TSInfoMessage *)message { if ([message isKindOfClass:[OWSAddToContactsOfferMessage class]]) { diff --git a/Signal/src/ViewControllers/OversizeTextMessageViewController.swift b/Signal/src/ViewControllers/OversizeTextMessageViewController.swift index db35ff158..949242f9e 100644 --- a/Signal/src/ViewControllers/OversizeTextMessageViewController.swift +++ b/Signal/src/ViewControllers/OversizeTextMessageViewController.swift @@ -38,7 +38,7 @@ class OversizeTextMessageViewController: UIViewController { assert(false) return nil } - guard let attachment = TSAttachment.fetch(withUniqueID:attachmentID) as? TSAttachmentStream else { + guard let attachment = TSAttachment.fetch(uniqueId: attachmentID) as? TSAttachmentStream else { Logger.error("\(TAG) could not load attachment.") assert(false) return nil diff --git a/Signal/src/ViewControllers/PrivacySettingsTableViewController.m b/Signal/src/ViewControllers/PrivacySettingsTableViewController.m index 525659bd0..a68243cab 100644 --- a/Signal/src/ViewControllers/PrivacySettingsTableViewController.m +++ b/Signal/src/ViewControllers/PrivacySettingsTableViewController.m @@ -18,7 +18,7 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { PrivacySettingsTableViewControllerSectionIndexCalling, PrivacySettingsTableViewControllerSectionIndexCallKit, PrivacySettingsTableViewControllerSectionIndexHistoryLog, - PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange, + PrivacySettingsTableViewControllerSectionIndexBlockSendingOnIdentityChange, PrivacySettingsTableViewControllerSectionIndex_Count // meta section to track how many sections }; @@ -38,8 +38,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { @property (nonatomic) UITableViewCell *callsHideIPAddressCell; @property (nonatomic) UISwitch *callsHideIPAddressSwitch; -@property (nonatomic, strong) UITableViewCell *blockOnIdentityChangeCell; -@property (nonatomic, strong) UISwitch *blockOnIdentityChangeSwitch; +@property (nonatomic, strong) UITableViewCell *sendingIdentityApprovalRequiredCell; +@property (nonatomic, strong) UISwitch *isSendingIdentityApprovalRequiredSwitch; @property (nonatomic, strong) UITableViewCell *clearHistoryLogCell; @@ -116,16 +116,16 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { self.clearHistoryLogCell.textLabel.text = NSLocalizedString(@"SETTINGS_CLEAR_HISTORY", @""); self.clearHistoryLogCell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; - // Block Identity on KeyChange - self.blockOnIdentityChangeCell = [UITableViewCell new]; - self.blockOnIdentityChangeCell.textLabel.text - = NSLocalizedString(@"SETTINGS_BLOCK_ON_IDENTITY_CHANGE_TITLE", @"Table cell label"); - self.blockOnIdentityChangeSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; - self.blockOnIdentityChangeCell.accessoryView = self.blockOnIdentityChangeSwitch; - [self.blockOnIdentityChangeSwitch setOn:[Environment.preferences shouldBlockOnIdentityChange]]; - [self.blockOnIdentityChangeSwitch addTarget:self - action:@selector(didToggleBlockOnIdentityChangeSwitch:) - forControlEvents:UIControlEventValueChanged]; + // Block Sending on Key Change + self.sendingIdentityApprovalRequiredCell = [UITableViewCell new]; + self.sendingIdentityApprovalRequiredCell.textLabel.text + = NSLocalizedString(@"SETTINGS_BLOCK_SENDING_ON_IDENTITY_CHANGE_TITLE", @"Table cell label"); + self.isSendingIdentityApprovalRequiredSwitch = [[UISwitch alloc] initWithFrame:CGRectZero]; + self.sendingIdentityApprovalRequiredCell.accessoryView = self.isSendingIdentityApprovalRequiredSwitch; + [self.isSendingIdentityApprovalRequiredSwitch setOn:[Environment.preferences isSendingIdentityApprovalRequired]]; + [self.isSendingIdentityApprovalRequiredSwitch addTarget:self + action:@selector(didToggleisSendingIdentityApprovalRequiredSwitch:) + forControlEvents:UIControlEventValueChanged]; } #pragma mark - Table view data source @@ -149,7 +149,7 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { return [Environment getCurrent].preferences.isCallKitEnabled ? 2 : 1; case PrivacySettingsTableViewControllerSectionIndexHistoryLog: return 1; - case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: + case PrivacySettingsTableViewControllerSectionIndexBlockSendingOnIdentityChange: return 1; default: return 0; @@ -168,7 +168,7 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { return ([UIDevice currentDevice].supportsCallKit ? NSLocalizedString(@"SETTINGS_SECTION_CALL_KIT_DESCRIPTION", @"Settings table section footer.") : nil); - case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: + case PrivacySettingsTableViewControllerSectionIndexBlockSendingOnIdentityChange: return NSLocalizedString( @"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL", @"User settings section footer, a detailed explanation"); default: @@ -193,8 +193,8 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { } case PrivacySettingsTableViewControllerSectionIndexHistoryLog: return self.clearHistoryLogCell; - case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: - return self.blockOnIdentityChangeCell; + case PrivacySettingsTableViewControllerSectionIndexBlockSendingOnIdentityChange: + return self.sendingIdentityApprovalRequiredCell; default: { DDLogError(@"%@ Requested unknown table view cell for row at indexPath: %@", self.tag, indexPath); return [UITableViewCell new]; @@ -211,7 +211,7 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { return NSLocalizedString(@"SETTINGS_SECTION_TITLE_CALLING", @"settings topic header for table section"); case PrivacySettingsTableViewControllerSectionIndexHistoryLog: return NSLocalizedString(@"SETTINGS_HISTORYLOG_TITLE", @"Section header"); - case PrivacySettingsTableViewControllerSectionIndexBlockOnIdentityChange: + case PrivacySettingsTableViewControllerSectionIndexBlockSendingOnIdentityChange: return NSLocalizedString(@"SETTINGS_PRIVACY_VERIFICATION_TITLE", @"Section header"); default: return nil; @@ -263,11 +263,11 @@ typedef NS_ENUM(NSInteger, PrivacySettingsTableViewControllerSectionIndex) { [Environment.preferences setScreenSecurity:enabled]; } -- (void)didToggleBlockOnIdentityChangeSwitch:(UISwitch *)sender +- (void)didToggleisSendingIdentityApprovalRequiredSwitch:(UISwitch *)sender { - BOOL enabled = self.blockOnIdentityChangeSwitch.isOn; - DDLogInfo(@"%@ toggled blockOnIdentityChange: %@", self.tag, enabled ? @"ON" : @"OFF"); - [Environment.preferences setShouldBlockOnIdentityChange:enabled]; + BOOL enabled = self.isSendingIdentityApprovalRequiredSwitch.isOn; + DDLogInfo(@"%@ toggled isSendingIdentityApprovalRequired: %@", self.tag, enabled ? @"ON" : @"OFF"); + [Environment.preferences setIsSendingIdentityApprovalRequired:enabled]; } - (void)didToggleCallsHideIPAddressSwitch:(UISwitch *)sender diff --git a/Signal/src/contact/SystemContactsFetcher.swift b/Signal/src/contact/SystemContactsFetcher.swift index 651bcaabf..b79c89c05 100644 --- a/Signal/src/contact/SystemContactsFetcher.swift +++ b/Signal/src/contact/SystemContactsFetcher.swift @@ -362,7 +362,6 @@ class SystemContactsFetcher: NSObject { AssertIsOnMainThread() guard !systemContactsHaveBeenRequestedAtLeastOnce else { - Logger.debug("\(TAG) already requested system contacts") completion?(nil) return } diff --git a/Signal/src/environment/ExperienceUpgradeFinder.swift b/Signal/src/environment/ExperienceUpgradeFinder.swift index b9bdcfdfd..053677961 100644 --- a/Signal/src/environment/ExperienceUpgradeFinder.swift +++ b/Signal/src/environment/ExperienceUpgradeFinder.swift @@ -32,7 +32,7 @@ class ExperienceUpgradeFinder: NSObject { // MARK: - Instance Methods public func allUnseen(transaction: YapDatabaseReadTransaction) -> [ExperienceUpgrade] { - return allExperienceUpgrades.filter { ExperienceUpgrade.fetch(withUniqueID: $0.uniqueId, transaction: transaction) == nil } + return allExperienceUpgrades.filter { ExperienceUpgrade.fetch(uniqueId: $0.uniqueId, transaction: transaction) == nil } } public func markAllAsSeen(transaction: YapDatabaseReadWriteTransaction) { diff --git a/Signal/src/environment/Migrations/OWS101ExistingUsersBlockOnIdentityChange.m b/Signal/src/environment/Migrations/OWS101ExistingUsersBlockOnIdentityChange.m index 8fdd7f591..df1bfba0b 100644 --- a/Signal/src/environment/Migrations/OWS101ExistingUsersBlockOnIdentityChange.m +++ b/Signal/src/environment/Migrations/OWS101ExistingUsersBlockOnIdentityChange.m @@ -1,8 +1,8 @@ -// Created by Michael Kirk on 11/8/16. -// Copyright © 2016 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #import "OWS101ExistingUsersBlockOnIdentityChange.h" -#import #import NS_ASSUME_NONNULL_BEGIN @@ -19,10 +19,11 @@ static NSString *const OWS101ExistingUsersBlockOnIdentityChangeMigrationId = @"1 - (void)runUpWithTransaction:(YapDatabaseReadWriteTransaction *)transaction { - DDLogWarn(@"[OWS101ExistingUsersBlockOnIdentityChange] Opting existing user into 'blocking' on identity changes."); - TSPrivacyPreferences *preferences = [TSPrivacyPreferences sharedInstance]; - preferences.shouldBlockOnIdentityChange = YES; - [preferences saveWithTransaction:transaction]; + DDLogWarn(@"[OWS101ExistingUsersBlockOnIdentityChange] has been obviated."); + // DDLogWarn(@"[OWS101ExistingUsersBlockOnIdentityChange] Opting existing user into 'blocking' on identity + // changes."); TSPrivacyPreferences *preferences = [TSPrivacyPreferences sharedInstance]; + // preferences.shouldBlockOnIdentityChange = YES; + // [preferences saveWithTransaction:transaction]; } @end diff --git a/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.h b/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.h new file mode 100644 index 000000000..46d1d6c2f --- /dev/null +++ b/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.h @@ -0,0 +1,13 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "OWSDatabaseMigration.h" + +NS_ASSUME_NONNULL_BEGIN + +@interface OWS104CreateRecipientIdentities : OWSDatabaseMigration + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m b/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m new file mode 100644 index 000000000..086bb6803 --- /dev/null +++ b/Signal/src/environment/Migrations/OWS104CreateRecipientIdentities.m @@ -0,0 +1,77 @@ +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// + +#import "OWS104CreateRecipientIdentities.h" +#import +#import +#import +#import + +NS_ASSUME_NONNULL_BEGIN + +// Increment a similar constant for every future DBMigration +static NSString *const OWS104CreateRecipientIdentitiesMigrationId = @"104"; + +/** + * New SN behavaior requires tracking additional state - not just the identity key data. + * So we wrap the key, along with the new meta-data in an OWSRecipientIdentity. + */ +@implementation OWS104CreateRecipientIdentities + ++ (NSString *)migrationId +{ + return OWS104CreateRecipientIdentitiesMigrationId; +} + +// Overriding runUp instead of runUpWithTransaction in order to implement a blocking migration. +- (void)runUp +{ + [[OWSRecipientIdentity dbConnection] readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { + NSMutableDictionary *identityKeys = [NSMutableDictionary new]; + + [transaction + enumerateKeysAndObjectsInCollection:TSStorageManagerTrustedKeysCollection + usingBlock:^( + NSString *_Nonnull recipientId, id _Nonnull object, BOOL *_Nonnull stop) { + if (![object isKindOfClass:[NSData class]]) { + DDLogError( + @"%@ Unexpected object in trusted keys collection key: %@ object: %@", + self.tag, + recipientId, + object); + OWSAssert(NO); + return; + } + NSData *identityKey = (NSData *)object; + [identityKeys setObject:identityKey forKey:recipientId]; + }]; + + [identityKeys enumerateKeysAndObjectsUsingBlock:^( + NSString *_Nonnull recipientId, NSData *_Nonnull identityKey, BOOL *_Nonnull stop) { + DDLogInfo(@"%@ Migrating identity key for recipient: %@", self.tag, recipientId); + [[[OWSRecipientIdentity alloc] initWithRecipientId:recipientId + identityKey:identityKey + isFirstKnownKey:NO + createdAt:[NSDate dateWithTimeIntervalSince1970:0] + approvedForBlockingUse:YES + approvedForNonBlockingUse:NO] saveWithTransaction:transaction]; + }]; + }]; +} + +#pragma mark - Logging + ++ (NSString *)tag +{ + return [NSString stringWithFormat:@"[%@]", self.class]; +} + +- (NSString *)tag +{ + return self.class.tag; +} + +@end + +NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigration.h b/Signal/src/environment/Migrations/OWSDatabaseMigration.h index 58bc174ff..c4ffe42d5 100644 --- a/Signal/src/environment/Migrations/OWSDatabaseMigration.h +++ b/Signal/src/environment/Migrations/OWSDatabaseMigration.h @@ -1,5 +1,6 @@ -// Created by Michael Kirk on 9/28/16. -// Copyright © 2016 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #include @@ -13,20 +14,12 @@ NS_ASSUME_NONNULL_BEGIN @property (nonatomic, readonly) TSStorageManager *storageManager; -/** - * Run an asynchronous migration. Prefer this to the blocking variant whenever possible as the migration runner will - * block launching, and potentially crash apps e.g. if a view is being populated. - */ +// Prefer nonblocking (async) migrations by overriding `runUpWithTransaction:` in a subclass. +// Blocking migrations running too long will crash the app, effectively bricking install +// because the user will never get past it. +// If you must write a launch-blocking migration, override runUp. - (void)runUp; -/** - * Run a synchronous migration. - * TODO: there's currently no tooling in the migration runner to run BlockingMigrations, as we don't have any yet. - * Try to avoid this whenever possible as the migration runner will block launching, and potentially crash apps - * e.g. if a view is being populated. - */ -- (void)runUpWithBlockingMigration; - @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigration.m b/Signal/src/environment/Migrations/OWSDatabaseMigration.m index 244528c6b..f3660a49d 100644 --- a/Signal/src/environment/Migrations/OWSDatabaseMigration.m +++ b/Signal/src/environment/Migrations/OWSDatabaseMigration.m @@ -1,5 +1,6 @@ -// Created by Michael Kirk on 9/28/16. -// Copyright © 2016 Open Whisper Systems. All rights reserved. +// +// Copyright (c) 2017 Open Whisper Systems. All rights reserved. +// #import "OWSDatabaseMigration.h" #import @@ -63,19 +64,6 @@ NS_ASSUME_NONNULL_BEGIN }]; } -/** - * Try to avoid using this. - */ -- (void)runUpWithBlockingMigration -{ - [self.storageManager.newDatabaseConnection - readWriteWithBlock:^(YapDatabaseReadWriteTransaction *_Nonnull transaction) { - [self runUpWithTransaction:transaction]; - }]; - DDLogInfo(@"Completed migration %@", self.uniqueId); - [self save]; -} - @end NS_ASSUME_NONNULL_END diff --git a/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m b/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m index 38ac8b7f3..9b684f753 100644 --- a/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m +++ b/Signal/src/environment/Migrations/OWSDatabaseMigrationRunner.m @@ -4,9 +4,10 @@ #import "OWSDatabaseMigrationRunner.h" #import "OWS100RemoveTSRecipientsMigration.h" -#import "OWS101ExistingUsersBlockOnIdentityChange.h" +//#import "OWS101ExistingUsersBlockOnIdentityChange.h" #import "OWS102MoveLoggingPreferenceToUserDefaults.h" #import "OWS103EnableVideoCalling.h" +#import "OWS104CreateRecipientIdentities.h" NS_ASSUME_NONNULL_BEGIN @@ -28,9 +29,11 @@ NS_ASSUME_NONNULL_BEGIN { return @[ [[OWS100RemoveTSRecipientsMigration alloc] initWithStorageManager:self.storageManager], - [[OWS101ExistingUsersBlockOnIdentityChange alloc] initWithStorageManager:self.storageManager], + // Old nonblocking migration is no longer necessary. + // [[OWS101ExistingUsersBlockOnIdentityChange alloc] initWithStorageManager:self.storageManager], [[OWS102MoveLoggingPreferenceToUserDefaults alloc] initWithStorageManager:self.storageManager], - [[OWS103EnableVideoCalling alloc] initWithStorageManager:self.storageManager] + [[OWS103EnableVideoCalling alloc] initWithStorageManager:self.storageManager], + [[OWS104CreateRecipientIdentities alloc] initWithStorageManager:self.storageManager] ]; } diff --git a/Signal/src/environment/PropertyListPreferences.h b/Signal/src/environment/PropertyListPreferences.h index de8a7819a..30680d1f0 100644 --- a/Signal/src/environment/PropertyListPreferences.h +++ b/Signal/src/environment/PropertyListPreferences.h @@ -2,6 +2,8 @@ // Copyright (c) 2017 Open Whisper Systems. All rights reserved. // +#import + NS_ASSUME_NONNULL_BEGIN /** @@ -17,7 +19,7 @@ typedef NS_ENUM(NSUInteger, NotificationType) { extern NSString *const PropertyListPreferencesSignalDatabaseCollection; extern NSString *const PropertyListPreferencesKeyEnableDebugLog; -@interface PropertyListPreferences : NSObject +@interface PropertyListPreferences : NSObject #pragma mark - Helpers @@ -82,8 +84,7 @@ extern NSString *const PropertyListPreferencesKeyEnableDebugLog; #pragma mark - Block on Identity Change -- (BOOL)shouldBlockOnIdentityChange; -- (void)setShouldBlockOnIdentityChange:(BOOL)value; +- (void)setIsSendingIdentityApprovalRequired:(BOOL)value; #pragma mark - Push Tokens diff --git a/Signal/src/environment/PropertyListPreferences.m b/Signal/src/environment/PropertyListPreferences.m index f7c805aab..ef1d3ffaf 100644 --- a/Signal/src/environment/PropertyListPreferences.m +++ b/Signal/src/environment/PropertyListPreferences.m @@ -4,7 +4,6 @@ #import "PropertyListPreferences.h" #import "TSStorageHeaders.h" -#import NS_ASSUME_NONNULL_BEGIN @@ -27,6 +26,7 @@ NSString *const PropertyListPreferencesKeyCallKitPrivacyEnabled = @"CallKitPriva NSString *const PropertyListPreferencesKeyCallsHideIPAddress = @"CallsHideIPAddress"; NSString *const PropertyListPreferencesKeyHasDeclinedNoContactsView = @"hasDeclinedNoContactsView"; NSString *const PropertyListPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNagVersion"; +NSString *const PropertyListPreferencesKeyIsSendingIdentityApprovalRequired = @"IsSendingIdentityApprovalRequired"; @implementation PropertyListPreferences @@ -67,11 +67,6 @@ NSString *const PropertyListPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNag inCollection:PropertyListPreferencesSignalDatabaseCollection]; } -- (TSPrivacyPreferences *)tsPrivacyPreferences -{ - return [TSPrivacyPreferences sharedInstance]; -} - #pragma mark - Specific Preferences - (NSTimeInterval)getCachedOrDefaultDesiredBufferDepth @@ -305,15 +300,19 @@ NSString *const PropertyListPreferencesKeyIOSUpgradeNagVersion = @"iOSUpgradeNag #pragma mark - Block on Identity Change -- (BOOL)shouldBlockOnIdentityChange +- (BOOL)isSendingIdentityApprovalRequired { - return self.tsPrivacyPreferences.shouldBlockOnIdentityChange; + NSNumber *preference = [self tryGetValueForKey:PropertyListPreferencesKeyIsSendingIdentityApprovalRequired]; + if (preference) { + return [preference boolValue]; + } else { + return NO; + } } -- (void)setShouldBlockOnIdentityChange:(BOOL)value +- (void)setIsSendingIdentityApprovalRequired:(BOOL)value { - self.tsPrivacyPreferences.shouldBlockOnIdentityChange = value; - [self.tsPrivacyPreferences save]; + [self setValueForKey:PropertyListPreferencesKeyIsSendingIdentityApprovalRequired toValue:@(value)]; } #pragma mark - Push Tokens diff --git a/Signal/src/views/OWSBezierPathView.m b/Signal/src/views/OWSBezierPathView.m index 9ee6f98fa..ca60c0ca9 100644 --- a/Signal/src/views/OWSBezierPathView.m +++ b/Signal/src/views/OWSBezierPathView.m @@ -102,6 +102,7 @@ return [NSString stringWithFormat:@"[%@]", self.class]; } +// TODO rename to logTag, tag is an existing UIView method. - (NSString *)tag { return self.class.tag; diff --git a/Signal/translations/en.lproj/Localizable.strings b/Signal/translations/en.lproj/Localizable.strings index 65a15d39c..4e94cb32d 100644 --- a/Signal/translations/en.lproj/Localizable.strings +++ b/Signal/translations/en.lproj/Localizable.strings @@ -470,7 +470,7 @@ "ERROR_MESSAGE_NON_BLOCKING_IDENTITY_CHANGE" = "Safety number changed."; /* Shown when signal users safety numbers changed, embeds the user's {{name or phone number}} */ -"ERROR_MESSAGE_NON_BLOCKING_IDENTITY_CHANGE_FORMAT" = "ERROR_MESSAGE_NON_BLOCKING_IDENTITY_CHANGE_FORMAT"; +"ERROR_MESSAGE_NON_BLOCKING_IDENTITY_CHANGE_FORMAT" = "Your safety number with %@ has changed."; /* No comment provided by engineer. */ "ERROR_MESSAGE_UNKNOWN_ERROR" = "An unknown error occurred."; @@ -1139,10 +1139,10 @@ "SETTINGS_BLOCK_LIST_TITLE" = "Blocked"; /* User settings section footer, a detailed explanation */ -"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL" = "Requires your approval before communicating with someone who has a new safety number, commonly from a reinstall of Signal."; +"SETTINGS_BLOCK_ON_IDENITY_CHANGE_DETAIL" = "When a contact's safety number changes, it often means they simply reinstalled Signal. However, you may wish to verify their safety number before responding to ensure privacy."; /* Table cell label */ -"SETTINGS_BLOCK_ON_IDENTITY_CHANGE_TITLE" = "Require Approval on Change"; +"SETTINGS_BLOCK_SENDING_ON_IDENTITY_CHANGE_TITLE" = "Responding Requires Approval"; /* Accessibility hint for the settings button */ "SETTINGS_BUTTON_ACCESSIBILITY" = "Settings"; @@ -1199,7 +1199,7 @@ "SETTINGS_PRIVACY_TITLE" = "Privacy"; /* Section header */ -"SETTINGS_PRIVACY_VERIFICATION_TITLE" = "Safety Numbers Approval"; +"SETTINGS_PRIVACY_VERIFICATION_TITLE" = "When Safety Numbers Change"; /* No comment provided by engineer. */ "SETTINGS_SCREEN_SECURITY" = "Enable Screen Security";