From dfdd0a197418fe9bef6128eebaad06aa63a87c6b Mon Sep 17 00:00:00 2001 From: Frederic Jacobs Date: Mon, 16 Feb 2015 10:27:08 +0100 Subject: [PATCH] Support for `remoteRegistrationId`. 1) Supporting `remoteRegistrationId` on sending messages. Now showing warning before sending the message if key conflict exists. Fixes #574 2) Upgrading dependencies: adapting to new libPhoneNumber API. 3) Fixes race condition in database code. 4) Fixing ordering bug. Hopefully once and for good. --- Podfile | 8 +- Podfile.lock | 52 +++++------ Pods | 2 +- Signal.xcodeproj/project.pbxproj | 32 +++++-- Signal/src/AppDelegate.m | 4 +- Signal/src/phone/PhoneNumber.m | 11 +-- .../src/textsecure/Account/TSAccountManager.m | 8 +- Signal/src/textsecure/Contacts/TSThread.h | 12 +-- Signal/src/textsecure/Contacts/TSThread.m | 41 +++++---- .../TSInvalidIdentityKeyErrorMessage.h | 16 ++++ .../TSInvalidIdentityKeyErrorMessage.m | 21 +++++ ...InvalidIdentityKeyReceivingErrorMessage.h} | 7 +- ...InvalidIdentityKeyReceivingErrorMessage.m} | 12 +-- .../TSInvalidIdentityKeySendingErrorMessage.h | 24 ++++++ .../TSInvalidIdentityKeySendingErrorMessage.m | 86 +++++++++++++++++++ .../TSErrorMessage_privateConstructor.h | 7 +- .../src/textsecure/Messages/TSInteraction.m | 8 +- .../Messages/TSMessagesManager+sendMessages.m | 49 +++++++++-- .../textsecure/Messages/TSMessagesManager.h | 5 +- .../textsecure/Messages/TSMessagesManager.m | 29 ++++--- .../src/textsecure/Messages/TSServerMessage.h | 3 +- .../src/textsecure/Messages/TSServerMessage.m | 13 +-- .../API/Requests/TSRegisterPrekeysRequest.h | 5 +- .../API/Requests/TSRegisterPrekeysRequest.m | 10 ++- .../src/textsecure/Storage/TSDatabaseView.m | 10 +-- Signal/src/textsecure/Util/Cryptography.m | 3 - Signal/src/util/PhoneNumberUtil.h | 6 ++ Signal/src/util/PhoneNumberUtil.m | 17 +++- .../RegistrationViewController.m | 2 +- .../UITests/SignalsViewController.m | 2 + 30 files changed, 378 insertions(+), 127 deletions(-) create mode 100644 Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h create mode 100644 Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m rename Signal/src/textsecure/Messages/{TSInvalidIdentityKeyErrorMessage.h => InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h} (68%) rename Signal/src/textsecure/Messages/{TSInvalidIdentityKeyErrorMessage.m => InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m} (88%) create mode 100644 Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h create mode 100644 Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m diff --git a/Podfile b/Podfile index ea2982f3c..82207a915 100644 --- a/Podfile +++ b/Podfile @@ -5,13 +5,13 @@ inhibit_all_warnings! link_with ["Signal", "SignalTests"] pod 'SocketRocket', :git => 'https://github.com/FredericJacobs/SocketRocket.git', :commit => '73d8a19' -pod 'OpenSSL', '~> 1.0.200' -pod 'libPhoneNumber-iOS', '~> 0.7' -pod 'AxolotlKit', '~> 0.5' +pod 'OpenSSL', '~> 1.0.200' +pod 'libPhoneNumber-iOS', '~> 0.8.2' +pod 'AxolotlKit', '~> 0.6.2' pod 'PastelogKit', '~> 1.2' pod 'TwistedOakCollapsingFutures','~> 1.0' pod 'YapDatabase/SQLCipher' -pod 'AFNetworking', '~> 2.5' +pod 'AFNetworking', '~> 2.5.1' pod 'Mantle', '~> 1.5' pod 'SSKeychain' pod 'JSQMessagesViewController', :git => 'https://github.com/WhisperSystems/JSQMessagesViewController', :branch => 'JSignalQ' diff --git a/Podfile.lock b/Podfile.lock index 6578bd0b4..d626639bb 100644 --- a/Podfile.lock +++ b/Podfile.lock @@ -1,31 +1,31 @@ PODS: - 25519 (1.8) - - AFNetworking (2.5.0): - - AFNetworking/NSURLConnection (= 2.5.0) - - AFNetworking/NSURLSession (= 2.5.0) - - AFNetworking/Reachability (= 2.5.0) - - AFNetworking/Security (= 2.5.0) - - AFNetworking/Serialization (= 2.5.0) - - AFNetworking/UIKit (= 2.5.0) - - AFNetworking/NSURLConnection (2.5.0): + - AFNetworking (2.5.1): + - AFNetworking/NSURLConnection (= 2.5.1) + - AFNetworking/NSURLSession (= 2.5.1) + - AFNetworking/Reachability (= 2.5.1) + - AFNetworking/Security (= 2.5.1) + - AFNetworking/Serialization (= 2.5.1) + - AFNetworking/UIKit (= 2.5.1) + - AFNetworking/NSURLConnection (2.5.1): - AFNetworking/Reachability - AFNetworking/Security - AFNetworking/Serialization - - AFNetworking/NSURLSession (2.5.0): + - AFNetworking/NSURLSession (2.5.1): - AFNetworking/Reachability - AFNetworking/Security - AFNetworking/Serialization - - AFNetworking/Reachability (2.5.0) - - AFNetworking/Security (2.5.0) - - AFNetworking/Serialization (2.5.0) - - AFNetworking/UIKit (2.5.0): + - AFNetworking/Reachability (2.5.1) + - AFNetworking/Security (2.5.1) + - AFNetworking/Serialization (2.5.1) + - AFNetworking/UIKit (2.5.1): - AFNetworking/NSURLConnection - AFNetworking/NSURLSession - APDropDownNavToolbar (1.1) - - AxolotlKit (0.5): + - AxolotlKit (0.6.2): - 25519 (~> 1.8) - HKDFKit (~> 0.0.3) - - ProtocolBuffers (~> 1.9.2) + - ProtocolBuffers (~> 1.9.7) - CocoaLumberjack (1.9.2): - CocoaLumberjack/Extensions (= 1.9.2) - CocoaLumberjack/Core (1.9.2) @@ -34,10 +34,10 @@ PODS: - DJWActionSheet (1.0.4) - FFCircularProgressView (0.5) - HKDFKit (0.0.3) - - JSQMessagesViewController (6.1.1): - - JSQSystemSoundPlayer (~> 2.0.0) + - JSQMessagesViewController (6.1.3): + - JSQSystemSoundPlayer (~> 2.0.1) - JSQSystemSoundPlayer (2.0.1) - - libPhoneNumber-iOS (0.7.6) + - libPhoneNumber-iOS (0.8.2) - Mantle (1.5.4): - Mantle/extobjc (= 1.5.4) - Mantle/extobjc (1.5.4) @@ -62,13 +62,13 @@ PODS: - YapDatabase/common DEPENDENCIES: - - AFNetworking (~> 2.5) + - AFNetworking (~> 2.5.1) - APDropDownNavToolbar (from `https://github.com/corbett/APDropDownNavToolbar.git`, branch `master`) - - AxolotlKit (~> 0.5) + - AxolotlKit (~> 0.6.2) - DJWActionSheet - FFCircularProgressView (>= 0.1) - JSQMessagesViewController (from `https://github.com/WhisperSystems/JSQMessagesViewController`, branch `JSignalQ`) - - libPhoneNumber-iOS (~> 0.7) + - libPhoneNumber-iOS (~> 0.8.2) - Mantle (~> 1.5) - OpenSSL (~> 1.0.200) - PastelogKit (~> 1.2) @@ -97,7 +97,7 @@ CHECKOUT OPTIONS: :commit: cf63307d5e3833b16caa9a07f3b5ea06359913f9 :git: https://github.com/corbett/APDropDownNavToolbar.git JSQMessagesViewController: - :commit: 26fb5cbcf4a2bf15b6f384d29028b15a5e1a62f5 + :commit: bfb0c58785b33fa30ac3c88ef38477e49a674912 :git: https://github.com/WhisperSystems/JSQMessagesViewController SocketRocket: :commit: 73d8a19 @@ -105,16 +105,16 @@ CHECKOUT OPTIONS: SPEC CHECKSUMS: 25519: 601ffb5d258aa33d642062d6fa4096db210e02e7 - AFNetworking: 0f54cb5d16ce38c1b76948faffb8d5fb705021c7 + AFNetworking: 8bee59492a6ff15d69130efa4d0dc67e0094a52a APDropDownNavToolbar: 62131873890d3a30a2fdc98ffdda180a11e49aa4 - AxolotlKit: eec4d036d5b021258dc8b6b0212f3c04edeaf15b + AxolotlKit: c8d6fdd73754aa6432a106ae73f4c24385e253da CocoaLumberjack: 205769c032b5fef85b92472046bcc8b7e7c8a817 DJWActionSheet: d88b302d7c29523e1e9fb9b62cfac46f59bb90d9 FFCircularProgressView: 723b7a84c412b5d9d2a5531bc716b99965ad7192 HKDFKit: 5998cf1bbb611e7ecc6bd3eaaef8c7a7da7be949 - JSQMessagesViewController: 554430bbaeb0b2dbed8d4aaa2bdf64559e67f353 + JSQMessagesViewController: 4cc4ff3b26599e8743166b7e8e908528c8f01a80 JSQSystemSoundPlayer: 55528c699a283aae2220d3ae7b8b527d2ecef4b4 - libPhoneNumber-iOS: d4316d494d4997c40a6059faf35a970d7f4eb1c0 + libPhoneNumber-iOS: 2b5a6aeb7fd720ae856f133aea9937336bd47819 Mantle: d5fbaf30fbc58031223af13812c060e15934a1fe OpenSSL: 4c7be3eca71139f52984542d8c4c0752154d26c3 PastelogKit: 8bab71b1d187617a83e7124cffe9eb1a600e6695 diff --git a/Pods b/Pods index cf26bdeb6..70c45af29 160000 --- a/Pods +++ b/Pods @@ -1 +1 @@ -Subproject commit cf26bdeb6884a541de1b72146d01b96a217cc8c9 +Subproject commit 70c45af296f1ca37139e06f1c1850e3a42ca1383 diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index df1e53038..7db1f76df 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -305,6 +305,9 @@ B60FB9AD1A46F831006A5A66 /* UIImage+contentTypes.m in Sources */ = {isa = PBXBuildFile; fileRef = B60FB9AC1A46F831006A5A66 /* UIImage+contentTypes.m */; }; B60FB9B01A4711D4006A5A66 /* TSAttachmentEncryptionResult.m in Sources */ = {isa = PBXBuildFile; fileRef = B60FB9AF1A4711D4006A5A66 /* TSAttachmentEncryptionResult.m */; }; B62D53F71A23CCAD009AAF82 /* TSMessageAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */; }; + B62EFBEC1A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B62EFBE71A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.m */; }; + B62EFBED1A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B62EFBE91A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.m */; }; + B62EFBEE1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B62EFBEB1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.m */; }; B633C5801A1D190B0059AC12 /* archive@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C4FE1A1D190B0059AC12 /* archive@2x.png */; }; B633C5831A1D190B0059AC12 /* backspace.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C5011A1D190B0059AC12 /* backspace.png */; }; B633C5841A1D190B0059AC12 /* backspace@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = B633C5021A1D190B0059AC12 /* backspace@2x.png */; }; @@ -365,7 +368,6 @@ B68112ED1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m in Sources */ = {isa = PBXBuildFile; fileRef = B68112EC1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m */; }; B684A46D19C3446200B11029 /* PushManagerTest.m in Sources */ = {isa = PBXBuildFile; fileRef = B684A46C19C3446200B11029 /* PushManagerTest.m */; }; B6850E5A1995A4710068E715 /* whisperFake.cer in Resources */ = {isa = PBXBuildFile; fileRef = B6850E591995A4710068E715 /* whisperFake.cer */; }; - B68B0E8A1A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = B68B0E891A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m */; }; B692BF071A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m in Sources */ = {isa = PBXBuildFile; fileRef = B692BF061A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m */; }; B69CD25119773E79005CE69A /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = B69CD25019773E79005CE69A /* XCTest.framework */; }; B6A3EB4B1A423B3800B2236B /* TSAttachmentAdapter.m in Sources */ = {isa = PBXBuildFile; fileRef = B6A3EB4A1A423B3800B2236B /* TSAttachmentAdapter.m */; }; @@ -908,6 +910,12 @@ B60FB9AF1A4711D4006A5A66 /* TSAttachmentEncryptionResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSAttachmentEncryptionResult.m; sourceTree = ""; }; B62D53F51A23CCAD009AAF82 /* TSMessageAdapter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSMessageAdapter.h; sourceTree = ""; }; B62D53F61A23CCAD009AAF82 /* TSMessageAdapter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSMessageAdapter.m; sourceTree = ""; }; + B62EFBE61A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyErrorMessage.h; sourceTree = ""; }; + B62EFBE71A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyErrorMessage.m; sourceTree = ""; }; + B62EFBE81A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyReceivingErrorMessage.h; sourceTree = ""; }; + B62EFBE91A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyReceivingErrorMessage.m; sourceTree = ""; }; + B62EFBEA1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeySendingErrorMessage.h; sourceTree = ""; }; + B62EFBEB1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeySendingErrorMessage.m; sourceTree = ""; }; B633C4FE1A1D190B0059AC12 /* archive@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "archive@2x.png"; sourceTree = ""; }; B633C5011A1D190B0059AC12 /* backspace.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = backspace.png; sourceTree = ""; }; B633C5021A1D190B0059AC12 /* backspace@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "backspace@2x.png"; sourceTree = ""; }; @@ -993,8 +1001,6 @@ B68112EC1A4DA30300BA82FF /* JSQMessagesCollectionViewCell+menuBarItems.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "JSQMessagesCollectionViewCell+menuBarItems.m"; path = "views/JSQMessagesCollectionViewCell+menuBarItems.m"; sourceTree = ""; }; B684A46C19C3446200B11029 /* PushManagerTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = PushManagerTest.m; path = Signal/test/push/PushManagerTest.m; sourceTree = SOURCE_ROOT; }; B6850E591995A4710068E715 /* whisperFake.cer */ = {isa = PBXFileReference; lastKnownFileType = file; path = whisperFake.cer; sourceTree = ""; }; - B68B0E881A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSInvalidIdentityKeyErrorMessage.h; sourceTree = ""; }; - B68B0E891A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSInvalidIdentityKeyErrorMessage.m; sourceTree = ""; }; B68B0E8D1A542AD700DE8A02 /* TSErrorMessage_privateConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSErrorMessage_privateConstructor.h; sourceTree = ""; }; B692BF051A76EF0F002786DA /* TSDatabaseSecondaryIndexes.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TSDatabaseSecondaryIndexes.h; sourceTree = ""; }; B692BF061A76EF0F002786DA /* TSDatabaseSecondaryIndexes.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = TSDatabaseSecondaryIndexes.m; sourceTree = ""; }; @@ -2132,6 +2138,19 @@ name = TSMessageAdapters; sourceTree = ""; }; + B62EFBE51A91352F0072ADD3 /* InvalidKeyMessages */ = { + isa = PBXGroup; + children = ( + B62EFBE61A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.h */, + B62EFBE71A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.m */, + B62EFBE81A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.h */, + B62EFBE91A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.m */, + B62EFBEA1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.h */, + B62EFBEB1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.m */, + ); + path = InvalidKeyMessages; + sourceTree = ""; + }; B633C4FD1A1D190B0059AC12 /* Images */ = { isa = PBXGroup; children = ( @@ -2347,6 +2366,7 @@ isa = PBXGroup; children = ( B6FAAAE91A41C7CC007FEC1D /* Attachement */, + B62EFBE51A91352F0072ADD3 /* InvalidKeyMessages */, B6B096011A1D25ED008BFAA6 /* IncomingPushMessageSignal.pb.h */, B6B096021A1D25ED008BFAA6 /* IncomingPushMessageSignal.pb.m */, B6B096051A1D25ED008BFAA6 /* TSCall.h */, @@ -2354,8 +2374,6 @@ B6B096071A1D25ED008BFAA6 /* TSErrorMessage.h */, B68B0E8D1A542AD700DE8A02 /* TSErrorMessage_privateConstructor.h */, B6B096081A1D25ED008BFAA6 /* TSErrorMessage.m */, - B68B0E881A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.h */, - B68B0E891A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m */, B6B0960B1A1D25ED008BFAA6 /* TSIncomingMessage.h */, B6B0960C1A1D25ED008BFAA6 /* TSIncomingMessage.m */, B6B0960D1A1D25ED008BFAA6 /* TSInfoMessage.h */, @@ -3104,6 +3122,7 @@ B60C16651988999D00E97A6C /* VersionMigrations.m in Sources */, 76EB062A18170B33006006FC /* BadState.m in Sources */, B97940271832BD2400BD66CB /* UIUtil.m in Sources */, + B62EFBEC1A91352F0072ADD3 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, B6B096861A1D25ED008BFAA6 /* SecurityUtils.m in Sources */, 76EB05BE18170B33006006FC /* ConfirmPacket.m in Sources */, 76EB058618170B33006006FC /* PreferencesUtil.m in Sources */, @@ -3116,7 +3135,7 @@ 76EB05EC18170B33006006FC /* CallState.m in Sources */, 76EB05D218170B33006006FC /* ZrtpInitiator.m in Sources */, 76EB05E018170B33006006FC /* NetworkStream.m in Sources */, - B68B0E8A1A54284100DE8A02 /* TSInvalidIdentityKeyErrorMessage.m in Sources */, + B62EFBEE1A91352F0072ADD3 /* TSInvalidIdentityKeySendingErrorMessage.m in Sources */, B6B0968A1A1D25ED008BFAA6 /* TSStorageManager+SessionStore.m in Sources */, FCFA64B71A24F6730007FB87 /* UIFont+OWS.m in Sources */, B6B096891A1D25ED008BFAA6 /* TSStorageManager+PreKeyStore.m in Sources */, @@ -3288,6 +3307,7 @@ BFB074C719A5611000F2947C /* FutureUtil.m in Sources */, FCD274E21A5AFD8000202277 /* PrivacySettingsTableViewController.m in Sources */, 76EB057218170B33006006FC /* RecentCall.m in Sources */, + B62EFBED1A91352F0072ADD3 /* TSInvalidIdentityKeyReceivingErrorMessage.m in Sources */, 76EB060418170B33006006FC /* PhoneNumberDirectoryFilter.m in Sources */, B97CBFA818860EA3008E0DE9 /* CountryCodeViewController.m in Sources */, B6B1013C196D213F007E3930 /* SignalKeyingStorage.m in Sources */, diff --git a/Signal/src/AppDelegate.m b/Signal/src/AppDelegate.m index 1f6ebcadc..357451903 100644 --- a/Signal/src/AppDelegate.m +++ b/Signal/src/AppDelegate.m @@ -97,8 +97,6 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; [DebugLogger.sharedInstance enableFileLogging]; } - [[TSStorageManager sharedManager] setupDatabase]; - self.notificationTracker = [NotificationTracker notificationTracker]; CategorizingLogger* logger = [CategorizingLogger categorizingLogger]; @@ -107,6 +105,8 @@ static NSString* const kCallSegue = @"2.0_6.0_Call_Segue"; [Environment.getCurrent.phoneDirectoryManager startUntilCancelled:nil]; [Environment.getCurrent.contactsManager doAfterEnvironmentInitSetup]; + [[TSStorageManager sharedManager] setupDatabase]; + [self performUpdateCheck]; // this call must be made after environment has been initialized because in general upgrade may depend on environment diff --git a/Signal/src/phone/PhoneNumber.m b/Signal/src/phone/PhoneNumber.m index f6b32f614..40f2b9cc0 100644 --- a/Signal/src/phone/PhoneNumber.m +++ b/Signal/src/phone/PhoneNumber.m @@ -3,8 +3,9 @@ #import "Util.h" #import "PreferencesUtil.h" #import "Environment.h" -#import "NBPhoneNumber.h" +#import "PhoneNumberUtil.h" #import "NBAsYouTypeFormatter.h" +#import "NBPhoneNumber.h" static NSString *const RPDefaultsKeyPhoneNumberString = @"RPDefaultsKeyPhoneNumberString"; static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneNumberCanonical"; @@ -15,7 +16,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN require(text != nil); require(regionCode != nil); - NBPhoneNumberUtil *phoneUtil = NBPhoneNumberUtil.sharedInstance; + NBPhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedInstance].nbPhoneNumberUtil; NSError* parseError = nil; NBPhoneNumber *number = [phoneUtil parse:text @@ -73,7 +74,7 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN +(NSString*) regionCodeFromCountryCodeString:(NSString*) countryCodeString { - NBPhoneNumberUtil* phoneUtil = NBPhoneNumberUtil.sharedInstance; + NBPhoneNumberUtil* phoneUtil = [PhoneNumberUtil sharedInstance].nbPhoneNumberUtil; NSString* regionCode = [phoneUtil getRegionCodeForCountryCode:@([[countryCodeString substringFromIndex:1] integerValue])]; return regionCode; } @@ -136,11 +137,11 @@ static NSString *const RPDefaultsKeyPhoneNumberCanonical = @"RPDefaultsKeyPhoneN } -(BOOL)isValid { - return [NBPhoneNumberUtil.sharedInstance isValidNumber:phoneNumber]; + return [[PhoneNumberUtil sharedInstance].nbPhoneNumberUtil isValidNumber:phoneNumber]; } -(NSString *)localizedDescriptionForUser { - NBPhoneNumberUtil *phoneUtil = NBPhoneNumberUtil.sharedInstance; + NBPhoneNumberUtil *phoneUtil = [PhoneNumberUtil sharedInstance].nbPhoneNumberUtil; NSError* formatError = nil; NSString* pretty = [phoneUtil format:phoneNumber diff --git a/Signal/src/textsecure/Account/TSAccountManager.m b/Signal/src/textsecure/Account/TSAccountManager.m index d107541bb..d69d5808d 100644 --- a/Signal/src/textsecure/Account/TSAccountManager.m +++ b/Signal/src/textsecure/Account/TSAccountManager.m @@ -6,6 +6,8 @@ // Copyright (c) 2014 Open Whisper Systems. All rights reserved. // +#include + #import "Constraints.h" #import "NSData+Base64.h" #import "NSData+hexString.h" @@ -55,11 +57,11 @@ registrationID = [[transaction objectForKey:TSStorageLocalRegistrationId inCollection:TSStorageUserAccountCollection] intValue]; }]; - if (!registrationID) { - int localIdentifier = random()%16380; + if (!registrationID ) { + uint32_t localIdentifier = arc4random_uniform(16380); [dbConn readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { - [transaction setObject:[NSNumber numberWithInt:localIdentifier] + [transaction setObject:[NSNumber numberWithUnsignedInt:localIdentifier] forKey:TSStorageLocalRegistrationId inCollection:TSStorageUserAccountCollection]; }]; diff --git a/Signal/src/textsecure/Contacts/TSThread.h b/Signal/src/textsecure/Contacts/TSThread.h index 046383f0d..8d5f2bb90 100644 --- a/Signal/src/textsecure/Contacts/TSThread.h +++ b/Signal/src/textsecure/Contacts/TSThread.h @@ -9,6 +9,8 @@ #import #import "TSYapDatabaseObject.h" +@class TSInteraction; + typedef NS_ENUM(NSInteger, TSLastActionType) { TSLastActionNone, @@ -61,17 +63,15 @@ typedef NS_ENUM(NSInteger, TSLastActionType) { - (UIImage*)image; -@property (getter=isBlocked) BOOL blocked; -@property (nonatomic) NSString* latestMessageId; -@property NSDate *archivalDate; -@property (nonatomic) NSDate *creationDate; - - (NSDate*)lastMessageDate; - - (NSString*)lastMessageLabel; +- (void)updateWithLastMessage:(TSInteraction*)lastMessage transaction:(YapDatabaseReadWriteTransaction*)transaction; + - (TSLastActionType)lastAction; - (BOOL)hasUnreadMessages; +@property NSDate *archivalDate; + @end diff --git a/Signal/src/textsecure/Contacts/TSThread.m b/Signal/src/textsecure/Contacts/TSThread.m index 8509f10c2..397a8a373 100644 --- a/Signal/src/textsecure/Contacts/TSThread.m +++ b/Signal/src/textsecure/Contacts/TSThread.m @@ -7,7 +7,6 @@ // #import "TSThread.h" -#import "Environment.h" #import "ContactsManager.h" #import "TSInteraction.h" #import "TSStorageManager.h" @@ -18,6 +17,14 @@ #import "TSInfoMessage.h" #import "TSErrorMessage.h" +@interface TSThread () + +@property (nonatomic, retain) NSDate *creationDate; +@property (nonatomic, retain) NSDate *lastMessageDate; +@property (nonatomic, copy ) NSString *latestMessageId; + +@end + @implementation TSThread + (NSString *)collection{ @@ -28,9 +35,9 @@ self = [super initWithUniqueId:uniqueId]; if (self) { - _blocked = NO; _latestMessageId = nil; - _creationDate = [NSDate date]; + _lastMessageDate = nil; + _creationDate = [NSDate date]; } return self; @@ -41,22 +48,10 @@ return FALSE; } -- (NSDate*)lastMessageDate{ - __block NSDate *date; - - if (self.latestMessageId) { - [[TSStorageManager sharedManager].dbConnection readWithBlock:^(YapDatabaseReadTransaction *transaction) { - date = [TSInteraction fetchObjectWithUniqueID:self.latestMessageId transaction:transaction].date; - }]; - - if (date) { - return date; - } - else { - return [NSDate date]; - } - } - else { +- (NSDate *)lastMessageDate{ + if (_lastMessageDate) { + return _lastMessageDate; + } else { return _creationDate; } } @@ -139,6 +134,14 @@ return hasUnread; } +- (void)updateWithLastMessage:(TSInteraction*)lastMessage transaction:(YapDatabaseReadWriteTransaction*)transaction { + if (!_lastMessageDate || [lastMessage.date timeIntervalSinceDate:self.lastMessageDate] > 0) { + _latestMessageId = lastMessage.uniqueId; + _lastMessageDate = lastMessage.date; + [self saveWithTransaction:transaction]; + } +} + - (NSString *)name{ NSAssert(FALSE, @"Should be implemented in subclasses"); return nil; diff --git a/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h new file mode 100644 index 000000000..4cbfac1b8 --- /dev/null +++ b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.h @@ -0,0 +1,16 @@ +// +// TSInvalidIdentityKeyErrorMessage.h +// Signal +// +// Created by Frederic Jacobs on 15/02/15. +// Copyright (c) 2015 Open Whisper Systems. All rights reserved. +// + +#import "TSErrorMessage.h" + +@interface TSInvalidIdentityKeyErrorMessage : TSErrorMessage + +- (void)acceptNewIdentityKey; +- (NSString*)newIdentityKey; + +@end diff --git a/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m new file mode 100644 index 000000000..ded20b1f1 --- /dev/null +++ b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyErrorMessage.m @@ -0,0 +1,21 @@ +// +// TSInvalidIdentityKeyErrorMessage.m +// Signal +// +// Created by Frederic Jacobs on 15/02/15. +// Copyright (c) 2015 Open Whisper Systems. All rights reserved. +// + +#import "TSInvalidIdentityKeyErrorMessage.h" + +@implementation TSInvalidIdentityKeyErrorMessage + +- (void)acceptNewIdentityKey{ + NSAssert(NO, @"Method needs to be implemented in subclasses of TSInvalidIdentityKeyErrorMessage."); +} +- (NSString*)newIdentityKey{ + NSAssert(NO, @"Method needs to be implemented in subclasses of TSInvalidIdentityKeyErrorMessage."); + return nil; +} + +@end diff --git a/Signal/src/textsecure/Messages/TSInvalidIdentityKeyErrorMessage.h b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h similarity index 68% rename from Signal/src/textsecure/Messages/TSInvalidIdentityKeyErrorMessage.h rename to Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h index fa23b0d54..b54b5c216 100644 --- a/Signal/src/textsecure/Messages/TSInvalidIdentityKeyErrorMessage.h +++ b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.h @@ -6,13 +6,10 @@ // Copyright (c) 2014 Open Whisper Systems. All rights reserved. // -#import "TSErrorMessage.h" +#import "TSInvalidIdentityKeyErrorMessage.h" -@interface TSInvalidIdentityKeyErrorMessage : TSErrorMessage +@interface TSInvalidIdentityKeyReceivingErrorMessage : TSInvalidIdentityKeyErrorMessage + (instancetype)untrustedKeyWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction; -- (void)acceptNewIdentityKey; -- (NSString*)newIdentityKey; - @end diff --git a/Signal/src/textsecure/Messages/TSInvalidIdentityKeyErrorMessage.m b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m similarity index 88% rename from Signal/src/textsecure/Messages/TSInvalidIdentityKeyErrorMessage.m rename to Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m index 0de3657f5..d02453b86 100644 --- a/Signal/src/textsecure/Messages/TSInvalidIdentityKeyErrorMessage.m +++ b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeyReceivingErrorMessage.m @@ -9,7 +9,7 @@ #import #import -#import "TSInvalidIdentityKeyErrorMessage.h" +#import "TSInvalidIdentityKeyReceivingErrorMessage.h" #import "TSErrorMessage_privateConstructor.h" #import "TSDatabaseView.h" #import "TSStorageManager.h" @@ -19,7 +19,7 @@ #import "TSMessagesManager.h" #import "TSFingerprintGenerator.h" -@implementation TSInvalidIdentityKeyErrorMessage +@implementation TSInvalidIdentityKeyReceivingErrorMessage - (instancetype)initForUnknownIdentityKeyWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread incomingPushSignal:(NSData*)signal{ self = [self initWithTimestamp:timestamp inThread:thread failedMessageType:TSErrorMessageWrongTrustedIdentityKey]; @@ -33,7 +33,7 @@ + (instancetype)untrustedKeyWithSignal:(IncomingPushMessageSignal*)preKeyMessage withTransaction:(YapDatabaseReadWriteTransaction*)transaction{ TSContactThread *contactThread = [TSContactThread getOrCreateThreadWithContactId:preKeyMessage.source transaction:transaction]; - TSInvalidIdentityKeyErrorMessage *errorMessage = [[self alloc] initForUnknownIdentityKeyWithTimestamp:preKeyMessage.timestamp inThread:contactThread incomingPushSignal:preKeyMessage.data]; + TSInvalidIdentityKeyReceivingErrorMessage *errorMessage = [[self alloc] initForUnknownIdentityKeyWithTimestamp:preKeyMessage.timestamp inThread:contactThread incomingPushSignal:preKeyMessage.data]; return errorMessage; } @@ -60,7 +60,7 @@ DDLogVerbose(@"Interaction type: %@", interaction.description); if ([interaction isKindOfClass:[TSInvalidIdentityKeyErrorMessage class]]) { - TSInvalidIdentityKeyErrorMessage *invalidKeyMessage = (TSInvalidIdentityKeyErrorMessage*)interaction; + TSInvalidIdentityKeyErrorMessage *invalidKeyMessage = (TSInvalidIdentityKeyReceivingErrorMessage*)interaction; IncomingPushMessageSignal *invalidMessageSignal = [IncomingPushMessageSignal parseFromData:invalidKeyMessage.pushSignal]; PreKeyWhisperMessage *pkwm = [[PreKeyWhisperMessage alloc] initWithData:invalidMessageSignal.message]; NSData *newKeyCandidate = [pkwm.identityKey removeKeyType]; @@ -73,7 +73,7 @@ }]; - for (TSInvalidIdentityKeyErrorMessage *errorMessage in messagesToDecrypt) { + for (TSInvalidIdentityKeyReceivingErrorMessage *errorMessage in messagesToDecrypt) { [[TSMessagesManager sharedManager] handleMessageSignal:[IncomingPushMessageSignal parseFromData:errorMessage.pushSignal]]; @@ -85,7 +85,7 @@ } - (NSString *)newIdentityKey{ - if (self.errorType != TSErrorMessageWrongTrustedIdentityKey || !self.pushSignal) { + if (!self.pushSignal) { return @""; } diff --git a/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h new file mode 100644 index 000000000..243f6e52e --- /dev/null +++ b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.h @@ -0,0 +1,24 @@ +// +// TSInvalidIdentityKeySendingErrorMessage.h +// Signal +// +// Created by Frederic Jacobs on 15/02/15. +// Copyright (c) 2015 Open Whisper Systems. All rights reserved. +// + +#import "TSInvalidIdentityKeyErrorMessage.h" + +@class PreKeyBundle; + +@interface TSInvalidIdentityKeySendingErrorMessage : TSInvalidIdentityKeyErrorMessage + +#define TSInvalidPreKeyBundleKey @"TSInvalidPreKeyBundleKey" +#define TSInvalidRecipientKey @"TSInvalidRecipientKey" + ++ (instancetype)untrustedKeyWithOutgoingMessage:(TSOutgoingMessage*)outgoingMessage + inThread:(TSThread*)thread + forRecipient:(NSString*)recipientId + preKeyBundle:(PreKeyBundle*)preKeyBundle + withTransaction:(YapDatabaseReadWriteTransaction*)transaction; + +@end diff --git a/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m new file mode 100644 index 000000000..132653535 --- /dev/null +++ b/Signal/src/textsecure/Messages/InvalidKeyMessages/TSInvalidIdentityKeySendingErrorMessage.m @@ -0,0 +1,86 @@ +// +// TSInvalidIdentityKeySendingErrorMessage.m +// Signal +// +// Created by Frederic Jacobs on 15/02/15. +// Copyright (c) 2015 Open Whisper Systems. All rights reserved. +// + +#import "TSOutgoingMessage.h" + +#import + +#import "NSDate+millisecondTimeStamp.h" +#import "PreKeyBundle+jsonDict.h" +#import "TSInvalidIdentityKeySendingErrorMessage.h" +#import "TSFingerprintGenerator.h" +#import "TSErrorMessage_privateConstructor.h" +#import "TSStorageManager+IdentityKeyStore.h" +#import "TSMessagesManager+sendMessages.h" + +@interface TSInvalidIdentityKeySendingErrorMessage() + +@property (nonatomic, readonly) PreKeyBundle *preKeyBundle; +@property (nonatomic, readonly) NSString *recipientId; +@property (nonatomic, readonly) NSString *messageId; + +@end + +@implementation TSInvalidIdentityKeySendingErrorMessage + +- (instancetype)initWithOutgoingMessage:(TSOutgoingMessage*)message + inThread:(TSThread*)thread + forRecipient:(NSString*)recipientId + preKeyBundle:(PreKeyBundle*)preKeyBundle + transaction:(YapDatabaseReadWriteTransaction*)transaction +{ + self = [super initWithTimestamp:message.timestamp inThread:thread failedMessageType:TSErrorMessageWrongTrustedIdentityKey]; + + if (self) { + _messageId = message.uniqueId; + _preKeyBundle = preKeyBundle; + _recipientId = recipientId; + } + + return self; +} + ++ (instancetype)untrustedKeyWithOutgoingMessage:(TSOutgoingMessage*)outgoingMessage + inThread:(TSThread*)thread + forRecipient:(NSString*)recipientId + preKeyBundle:(PreKeyBundle*)preKeyBundle + withTransaction:(YapDatabaseReadWriteTransaction*)transaction +{ + TSInvalidIdentityKeySendingErrorMessage *message = [[self alloc] initWithOutgoingMessage:outgoingMessage inThread:thread forRecipient:recipientId preKeyBundle:preKeyBundle transaction:transaction]; + return message; +} + +- (void)acceptNewIdentityKey { + [[TSStorageManager sharedManager] saveRemoteIdentity:[self newKey] recipientId:_recipientId]; + + __block TSOutgoingMessage *message; + __block TSThread *thread; + + [[TSStorageManager sharedManager].newDatabaseConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + thread = [TSContactThread fetchObjectWithUniqueID:self.uniqueThreadId transaction:transaction]; + message = [TSOutgoingMessage fetchObjectWithUniqueID:_messageId transaction:transaction]; + + [self removeWithTransaction:transaction]; + }]; + + if (message) { + [[TSMessagesManager sharedManager] sendMessage:message inThread:thread]; + } +} + +- (NSString*)newIdentityKey { + NSData *identityKey = [self newKey]; + + return [TSFingerprintGenerator getFingerprintForDisplay:identityKey]; +} + +- (NSData*)newKey { + return [self.preKeyBundle.identityKey removeKeyType]; +} + +@end diff --git a/Signal/src/textsecure/Messages/TSErrorMessage_privateConstructor.h b/Signal/src/textsecure/Messages/TSErrorMessage_privateConstructor.h index a68933dd4..f7a02519c 100644 --- a/Signal/src/textsecure/Messages/TSErrorMessage_privateConstructor.h +++ b/Signal/src/textsecure/Messages/TSErrorMessage_privateConstructor.h @@ -12,6 +12,11 @@ - (instancetype)initWithTimestamp:(uint64_t)timestamp inThread:(TSThread *)thread failedMessageType:(TSErrorMessageType)errorMessageType NS_DESIGNATED_INITIALIZER; -@property NSData *pushSignal; +@property NSData *pushSignal; + +@property NSDictionary *pendingOutgoingMessage; + +#define TSPendingOutgoingMessageKey @"TSPendingOutgoingMessageKey" +#define TSPendingOutgoingMessageRecipientKey @"TSPendingOutgoingMessageRecipientKey" @end diff --git a/Signal/src/textsecure/Messages/TSInteraction.m b/Signal/src/textsecure/Messages/TSInteraction.m index 54636486f..435ca5626 100644 --- a/Signal/src/textsecure/Messages/TSInteraction.m +++ b/Signal/src/textsecure/Messages/TSInteraction.m @@ -108,11 +108,9 @@ const struct TSMessageEdges TSMessageEdges = { TSThread *fetchedThread = [TSThread fetchObjectWithUniqueID:self.uniqueThreadId transaction:transaction]; - - if (!fetchedThread.latestMessageId || [self.date timeIntervalSinceDate:fetchedThread.lastMessageDate] > 0) { - fetchedThread.latestMessageId = self.uniqueId; - } - [fetchedThread saveWithTransaction:transaction]; + + + [fetchedThread updateWithLastMessage:self transaction:transaction]; } @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m b/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m index 0c6d16337..3bea9a911 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager+sendMessages.m @@ -120,6 +120,7 @@ dispatch_queue_t sendingQueue() { } failure:^(NSURLSessionDataTask *task, NSError *error) { NSHTTPURLResponse *response = (NSHTTPURLResponse *)task.response; long statuscode = response.statusCode; + NSData *responseData = error.userInfo[AFNetworkingOperationFailingURLResponseDataErrorKey]; switch (statuscode) { case 404:{ @@ -135,10 +136,23 @@ dispatch_queue_t sendingQueue() { // Mismatched devices DDLogError(@"Missing some devices"); break; - case 410: + case 410:{ // staledevices DDLogWarn(@"Stale devices"); + + if (!responseData) { + DDLogWarn(@"Stale devices but server didn't specify devices in response."); + return; + } + + [self handleStaleDevicesWithResponse:responseData recipientId:recipient.uniqueId]; + + dispatch_async(sendingQueue(), ^{ + [self sendMessage:message toRecipient:recipient inThread:thread withAttemps:remainingAttempts]; + }); + break; + } default: [self sendMessage:message toRecipient:recipient inThread:thread withAttemps:remainingAttempts]; break; @@ -169,7 +183,7 @@ dispatch_queue_t sendingQueue() { } } @catch (NSException *exception) { - [self processException:exception outgoingMessage:message]; + [self processException:exception outgoingMessage:message inThread:thread]; return; } } @@ -180,7 +194,7 @@ dispatch_queue_t sendingQueue() { - (NSDictionary*)encryptedMessageWithPlaintext:(NSData*)plainText toRecipient:(NSString*)identifier deviceId:(NSNumber*)deviceNumber keyingStorage:(TSStorageManager*)storage{ if (![storage containsSession:identifier deviceId:[deviceNumber intValue]]) { - dispatch_semaphore_t sema = dispatch_semaphore_create(0); + __block dispatch_semaphore_t sema = dispatch_semaphore_create(0); __block PreKeyBundle *bundle; [[TSNetworkManager sharedManager] queueAuthenticatedRequest:[[TSRecipientPrekeyRequest alloc] initWithRecipient:identifier deviceId:[deviceNumber stringValue]] success:^(NSURLSessionDataTask *task, id responseObject) { @@ -201,7 +215,15 @@ dispatch_queue_t sendingQueue() { identityKeyStore:storage recipientId:identifier deviceId:[deviceNumber intValue]]; - [builder processPrekeyBundle:bundle]; + @try { + [builder processPrekeyBundle:bundle]; + } + @catch (NSException *exception) { + if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { + @throw [NSException exceptionWithName:UntrustedIdentityKeyException reason:nil userInfo:@{TSInvalidPreKeyBundleKey:bundle, TSInvalidRecipientKey:identifier}]; + } + @throw exception; + } } } @@ -220,7 +242,8 @@ dispatch_queue_t sendingQueue() { TSServerMessage *serverMessage = [[TSServerMessage alloc] initWithType:messageType destination:identifier device:[deviceNumber intValue] - body:serializedMessage]; + body:serializedMessage + registrationId:cipher.remoteRegistrationId]; return [MTLJSONAdapter JSONDictionaryFromModel:serverMessage]; @@ -322,4 +345,20 @@ dispatch_queue_t sendingQueue() { return [builder.build data]; } +- (void)handleStaleDevicesWithResponse:(NSData*)responseData recipientId:(NSString*)identifier { + dispatch_async(sendingQueue(), ^{ + NSDictionary *serialization = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:nil]; + NSArray *devices = serialization[@"staleDevices"]; + + if (!([devices count] > 0)) { + return; + } + + for (NSUInteger i = 0; i < [devices count]; i++) { + int deviceNumber = [devices[i] intValue]; + [[TSStorageManager sharedManager] deleteSessionForContact:identifier deviceId:deviceNumber]; + } + }); +} + @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager.h b/Signal/src/textsecure/Messages/TSMessagesManager.h index 471fcd78c..905f18595 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager.h +++ b/Signal/src/textsecure/Messages/TSMessagesManager.h @@ -10,6 +10,7 @@ #import "IncomingPushMessageSignal.pb.h" #import "TSIncomingMessage.h" #import "TSOutgoingMessage.h" +#import "TSInvalidIdentityKeySendingErrorMessage.h" @interface TSMessagesManager : NSObject @@ -19,11 +20,11 @@ - (void)handleMessageSignal:(IncomingPushMessageSignal*)messageSignal; -- (void)processException:(NSException*)exception outgoingMessage:(TSOutgoingMessage*)message; +- (void)processException:(NSException*)exception outgoingMessage:(TSOutgoingMessage*)message inThread:(TSThread*)thread; - (void)handleReceivedMessage:(IncomingPushMessageSignal*)message withContent:(PushMessageContent*)content attachments:(NSArray*)attachments; - (void)handleReceivedMessage:(IncomingPushMessageSignal*)message withContent:(PushMessageContent*)content attachments:(NSArray*)attachments completionBlock:(void (^)(NSString* messageIdentifier))completionBlock ; --(void)handleSendToMyself:(TSOutgoingMessage*)outgoingMessage; +- (void)handleSendToMyself:(TSOutgoingMessage*)outgoingMessage; @end diff --git a/Signal/src/textsecure/Messages/TSMessagesManager.m b/Signal/src/textsecure/Messages/TSMessagesManager.m index d1afc0f1d..c2dfb9bcd 100644 --- a/Signal/src/textsecure/Messages/TSMessagesManager.m +++ b/Signal/src/textsecure/Messages/TSMessagesManager.m @@ -19,7 +19,7 @@ #import "TSIncomingMessage.h" #import "TSErrorMessage.h" -#import "TSInvalidIdentityKeyErrorMessage.h" +#import "TSInvalidIdentityKeyReceivingErrorMessage.h" #import "TSInfoMessage.h" #import "TSStorageManager+keyingMaterial.h" @@ -278,11 +278,11 @@ } else if(content.group.type==PushMessageContentGroupContextTypeQuit) { NSString *nameString = [[Environment.getCurrent contactsManager] nameStringForPhoneIdentifier:message.source]; - + if (!nameString) { nameString = message.source; } - + NSString* updateGroupInfo = [NSString stringWithFormat:@"%@ has left group",nameString]; NSMutableArray *newGroupMembers = [NSMutableArray arrayWithArray:gThread.groupModel.groupMemberIds]; [newGroupMembers removeObject:message.source]; @@ -360,7 +360,7 @@ } else if ([exception.name isEqualToString:InvalidVersionException]){ errorMessage = [TSErrorMessage invalidVersionWithSignal:signal withTransaction:transaction]; } else if ([exception.name isEqualToString:UntrustedIdentityKeyException]){ - errorMessage = [TSInvalidIdentityKeyErrorMessage untrustedKeyWithSignal:signal withTransaction:transaction]; + errorMessage = [TSInvalidIdentityKeyReceivingErrorMessage untrustedKeyWithSignal:signal withTransaction:transaction]; } else { errorMessage = [TSErrorMessage corruptedMessageWithSignal:signal withTransaction:transaction]; } @@ -369,15 +369,24 @@ }]; } -- (void)processException:(NSException*)exception outgoingMessage:(TSOutgoingMessage*)message{ +- (void)processException:(NSException*)exception outgoingMessage:(TSOutgoingMessage*)message inThread:(TSThread*)thread { DDLogWarn(@"Got exception: %@", exception.description); - if(message.groupMetaMessage==TSGroupMessageNone) { - // Only update this with exception if it is not a group message as group messages may except for one group send but not another and the UI doesn't know how to handle that - [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + + [self.dbConnection readWriteWithBlock:^(YapDatabaseReadWriteTransaction *transaction) { + TSErrorMessage *errorMessage; + + if ([exception.name isEqualToString:UntrustedIdentityKeyException]) { + errorMessage = [TSInvalidIdentityKeySendingErrorMessage untrustedKeyWithOutgoingMessage:message inThread:thread forRecipient:exception.userInfo[TSInvalidRecipientKey] preKeyBundle:exception.userInfo[TSInvalidPreKeyBundleKey] withTransaction:transaction]; + message.messageState = TSOutgoingMessageStateUnsent; + [message saveWithTransaction:transaction]; + } else if (message.groupMetaMessage==TSGroupMessageNone) { + // Only update this with exception if it is not a group message as group messages may except for one group send but not another and the UI doesn't know how to handle that [message setMessageState:TSOutgoingMessageStateUnsent]; [message saveWithTransaction:transaction]; - }]; - } + } + + [errorMessage saveWithTransaction:transaction]; + }]; } - (void)notifyUserForIncomingMessage:(TSIncomingMessage*)message from:(NSString*)name{ diff --git a/Signal/src/textsecure/Messages/TSServerMessage.h b/Signal/src/textsecure/Messages/TSServerMessage.h index 2e6e30f1a..da82d6315 100644 --- a/Signal/src/textsecure/Messages/TSServerMessage.h +++ b/Signal/src/textsecure/Messages/TSServerMessage.h @@ -14,6 +14,7 @@ - (instancetype)initWithType:(TSWhisperMessageType)type destination:(NSString*)destination device:(int)deviceId - body:(NSData*)data; + body:(NSData*)body + registrationId:(int)registrationId; @end diff --git a/Signal/src/textsecure/Messages/TSServerMessage.m b/Signal/src/textsecure/Messages/TSServerMessage.m index 5d380056c..b4747db19 100644 --- a/Signal/src/textsecure/Messages/TSServerMessage.m +++ b/Signal/src/textsecure/Messages/TSServerMessage.m @@ -16,6 +16,7 @@ @property int type; @property NSString *destination; @property int destinationDeviceId; +@property int destinationRegistrationId; @property NSString *body; @end @@ -30,14 +31,16 @@ destination:(NSString*)destination device:(int)deviceId body:(NSData*)body + registrationId:(int)registrationId { self = [super init]; - + if (self) { - _type = type; - _destination = destination; - _destinationDeviceId = deviceId; - _body = [body base64EncodedString]; + _type = type; + _destination = destination; + _destinationDeviceId = deviceId; + _destinationRegistrationId = registrationId; + _body = [body base64EncodedString]; } return self; diff --git a/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.h b/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.h index b90afd082..1ffbbaa9f 100644 --- a/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.h +++ b/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.h @@ -13,6 +13,9 @@ @interface TSRegisterPrekeysRequest : TSRequest -- (id)initWithPrekeyArray:(NSArray*)prekeys identityKey:(NSData*)identityKeyPublic signedPreKeyRecord:(SignedPreKeyRecord*)signedRecord preKeyLastResort:(PreKeyRecord*)lastResort; +- (id)initWithPrekeyArray:(NSArray*)prekeys + identityKey:(NSData*)identityKeyPublic + signedPreKeyRecord:(SignedPreKeyRecord*)signedRecord + preKeyLastResort:(PreKeyRecord*)lastResort; @end diff --git a/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.m b/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.m index c537b3efa..e57847f54 100644 --- a/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.m +++ b/Signal/src/textsecure/Network/API/Requests/TSRegisterPrekeysRequest.m @@ -14,6 +14,8 @@ #import #import +#import "TSStorageManager+IdentityKeyStore.h" + @implementation TSRegisterPrekeysRequest - (id)initWithPrekeyArray:(NSArray*)prekeys identityKey:(NSData*)identityKeyPublic signedPreKeyRecord:(SignedPreKeyRecord*)signedRecord preKeyLastResort:(PreKeyRecord*)lastResort { @@ -26,8 +28,12 @@ for (PreKeyRecord *preKey in prekeys) { [serializedPrekeyList addObject:[self dictionaryFromPreKey:preKey]]; } - - NSDictionary *serializedKeyRegistrationParameters = @{@"preKeys": serializedPrekeyList, @"lastResortKey":[self dictionaryFromPreKey:lastResort], @"signedPreKey":[self dictionaryFromSignedPreKey:signedRecord] , @"identityKey":publicIdentityKey}; + + NSDictionary *serializedKeyRegistrationParameters = @{@"preKeys": serializedPrekeyList, + @"lastResortKey":[self dictionaryFromPreKey:lastResort], + @"signedPreKey":[self dictionaryFromSignedPreKey:signedRecord] , + @"identityKey":publicIdentityKey + }; self.parameters = [serializedKeyRegistrationParameters mutableCopy]; diff --git a/Signal/src/textsecure/Storage/TSDatabaseView.m b/Signal/src/textsecure/Storage/TSDatabaseView.m index ec69dfcd9..08bbff3fc 100644 --- a/Signal/src/textsecure/Storage/TSDatabaseView.m +++ b/Signal/src/textsecure/Storage/TSDatabaseView.m @@ -66,7 +66,7 @@ NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionNa YapDatabaseViewGrouping *viewGrouping = [YapDatabaseViewGrouping withObjectBlock:^NSString *(NSString *collection, NSString *key, id object) { if ([object isKindOfClass:[TSThread class]]){ TSThread *thread = (TSThread*)object; - if (thread.archivalDate&&[thread.latestMessageId length]>0) { + if (thread.archivalDate) { return ([self threadShouldBeInInbox:thread])?TSInboxGroup:TSArchiveGroup; } else if(thread.archivalDate) { @@ -82,7 +82,7 @@ NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionNa YapDatabaseViewSorting *viewSorting = [self threadSorting]; YapDatabaseViewOptions *options = [[YapDatabaseViewOptions alloc] init]; - options.isPersistent = YES; + options.isPersistent = NO; options.allowedCollections = [[YapWhitelistBlacklist alloc] initWithWhitelist:[NSSet setWithObject:[TSThread collection]]]; YapDatabaseView *databaseView = [[YapDatabaseView alloc] initWithGrouping:viewGrouping @@ -148,12 +148,12 @@ NSString *TSUnreadDatabaseViewExtensionName = @"TSUnreadDatabaseViewExtensionNa TSThread *thread1 = (TSThread*)object1; TSThread *thread2 = (TSThread*)object2; - return [thread2.lastMessageDate compare:thread1.lastMessageDate]; + return [thread1.lastMessageDate compare:thread2.lastMessageDate]; } } - return NSOrderedSame; + + return NSOrderedSame; }]; - } + (YapDatabaseViewSorting*)messagesSorting { diff --git a/Signal/src/textsecure/Util/Cryptography.m b/Signal/src/textsecure/Util/Cryptography.m index 537445ed8..18b2f28ad 100755 --- a/Signal/src/textsecure/Util/Cryptography.m +++ b/Signal/src/textsecure/Util/Cryptography.m @@ -36,9 +36,6 @@ return randomBytes; } - - - #pragma mark SHA1 +(NSString*)truncatedSHA1Base64EncodedWithoutPadding:(NSString*)string{ diff --git a/Signal/src/util/PhoneNumberUtil.h b/Signal/src/util/PhoneNumberUtil.h index bee6208f7..dc59ef73e 100644 --- a/Signal/src/util/PhoneNumberUtil.h +++ b/Signal/src/util/PhoneNumberUtil.h @@ -1,7 +1,13 @@ #import #import "PhoneNumber.h" +#import "NBPhoneNumberUtil.h" @interface PhoneNumberUtil : NSObject + +MacrosSingletonInterface + +@property (nonatomic, retain) NBPhoneNumberUtil *nbPhoneNumberUtil; + + (NSString *)callingCodeFromCountryCode:(NSString *)code; + (NSString *)countryNameFromCountryCode:(NSString *)code; + (NSArray *)countryCodesForSearchTerm:(NSString *)searchTerm; diff --git a/Signal/src/util/PhoneNumberUtil.m b/Signal/src/util/PhoneNumberUtil.m index f188a2aa7..7d41b8c51 100644 --- a/Signal/src/util/PhoneNumberUtil.m +++ b/Signal/src/util/PhoneNumberUtil.m @@ -1,10 +1,21 @@ #import "PhoneNumberUtil.h" #import "ContactsManager.h" -#import "NBPhoneNumberUtil.h" #import "Util.h" @implementation PhoneNumberUtil +MacrosSingletonImplemention + +- (instancetype)init { + self = [super init]; + + if (self) { + _nbPhoneNumberUtil = [[NBPhoneNumberUtil alloc] init]; + } + + return self; +} + // country code -> country name + (NSString *)countryNameFromCountryCode:(NSString *)code { NSDictionary *countryCodeComponent = @{NSLocaleCountryCode: code}; @@ -16,7 +27,7 @@ // country code -> calling code + (NSString *)callingCodeFromCountryCode:(NSString *)code { - NSNumber *callingCode = [NBPhoneNumberUtil.sharedInstance getCountryCodeForRegion:code]; + NSNumber *callingCode = [[[self sharedInstance] nbPhoneNumberUtil] getCountryCodeForRegion:code]; return [NSString stringWithFormat:@"%@%@", COUNTRY_CODE_PREFIX, callingCode]; } @@ -43,7 +54,7 @@ // normalizes a phone number, so parentheses and spaces are stripped + (NSString*) normalizePhoneNumber:(NSString *) number { - return [NBPhoneNumberUtil.sharedInstance normalizePhoneNumber:number]; + return [[[self sharedInstance] nbPhoneNumberUtil] normalizePhoneNumber:number]; } // black magic diff --git a/Signal/src/view controllers/RegistrationViewController.m b/Signal/src/view controllers/RegistrationViewController.m index 6a2cdd735..a11af2248 100644 --- a/Signal/src/view controllers/RegistrationViewController.m +++ b/Signal/src/view controllers/RegistrationViewController.m @@ -70,7 +70,7 @@ static NSString *const kCodeSentSegue = @"codeSent"; - (void)populateDefaultCountryNameAndCode { NSLocale *locale = NSLocale.currentLocale; NSString *countryCode = [locale objectForKey:NSLocaleCountryCode]; - NSNumber *cc = [NBPhoneNumberUtil.sharedInstance getCountryCodeForRegion:countryCode]; + NSNumber *cc = [[PhoneNumberUtil sharedInstance].nbPhoneNumberUtil getCountryCodeForRegion:countryCode]; [_countryCodeButton setTitle:[NSString stringWithFormat:@"%@%@",COUNTRY_CODE_PREFIX, cc] forState:UIControlStateNormal]; [_countryNameButton setTitle:[PhoneNumberUtil countryNameFromCountryCode:countryCode] forState:UIControlStateNormal]; diff --git a/Signal/src/view controllers/UITests/SignalsViewController.m b/Signal/src/view controllers/UITests/SignalsViewController.m index aedc8352f..c254e7ab6 100644 --- a/Signal/src/view controllers/UITests/SignalsViewController.m +++ b/Signal/src/view controllers/UITests/SignalsViewController.m @@ -262,6 +262,8 @@ static NSString* const kShowSignupFlowSegue = @"showSignupFlow"; -(void) changeToGrouping:(NSString*)grouping { self.threadMappings = [[YapDatabaseViewMappings alloc] initWithGroups:@[grouping] view:TSThreadDatabaseViewExtensionName]; + [self.threadMappings setIsReversed:YES forGroup:grouping]; + [self.uiDatabaseConnection readWithBlock:^(YapDatabaseReadTransaction *transaction){ [self.threadMappings updateWithTransaction:transaction]; }];