diff --git a/Signal.xcodeproj/project.pbxproj b/Signal.xcodeproj/project.pbxproj index 7072f9334..483e2523f 100644 --- a/Signal.xcodeproj/project.pbxproj +++ b/Signal.xcodeproj/project.pbxproj @@ -154,6 +154,7 @@ 3491D9A121022DB7001EF5A1 /* CDSSigningCertificateTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 3491D9A021022DB7001EF5A1 /* CDSSigningCertificateTest.m */; }; 3496744D2076768700080B5F /* OWSMessageBubbleView.m in Sources */ = {isa = PBXBuildFile; fileRef = 3496744C2076768700080B5F /* OWSMessageBubbleView.m */; }; 3496744F2076ACD000080B5F /* LongTextViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3496744E2076ACCE00080B5F /* LongTextViewController.swift */; }; + 349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */ = {isa = PBXBuildFile; fileRef = 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */; }; 34A55F3720485465002CC6DE /* OWS2FARegistrationViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */; }; 34A910601FFEB114000C4745 /* OWSBackup.m in Sources */ = {isa = PBXBuildFile; fileRef = 34A9105F1FFEB114000C4745 /* OWSBackup.m */; }; 34ABB2C42090C59700C727A6 /* OWSResaveCollectionDBMigration.m in Sources */ = {isa = PBXBuildFile; fileRef = 34ABB2C22090C59600C727A6 /* OWSResaveCollectionDBMigration.m */; }; @@ -789,6 +790,7 @@ 3496744B2076768600080B5F /* OWSMessageBubbleView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSMessageBubbleView.h; sourceTree = ""; }; 3496744C2076768700080B5F /* OWSMessageBubbleView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWSMessageBubbleView.m; sourceTree = ""; }; 3496744E2076ACCE00080B5F /* LongTextViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LongTextViewController.swift; sourceTree = ""; }; + 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OWS111UDAttributesMigration.swift; sourceTree = ""; }; 34A55F3520485464002CC6DE /* OWS2FARegistrationViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OWS2FARegistrationViewController.m; sourceTree = ""; }; 34A55F3620485464002CC6DE /* OWS2FARegistrationViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWS2FARegistrationViewController.h; sourceTree = ""; }; 34A9105E1FFEB113000C4745 /* OWSBackup.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OWSBackup.h; sourceTree = ""; }; @@ -1625,6 +1627,8 @@ 4598198D204E2F28009414F2 /* OWS108CallLoggingPreference.m */, 34D5872E208E2C4100D2255A /* OWS109OutgoingMessageState.h */, 34D5872D208E2C4100D2255A /* OWS109OutgoingMessageState.m */, + 4C858A552130CBEC001B45D3 /* OWS110SortIdMigration.swift */, + 349EA07B2162AEA700F7B17F /* OWS111UDAttributesMigration.swift */, 346129931FD1E30000532771 /* OWSDatabaseMigration.h */, 346129941FD1E30000532771 /* OWSDatabaseMigration.m */, 346129E51FD5C0C600532771 /* OWSDatabaseMigrationRunner.h */, @@ -3254,6 +3258,7 @@ 34AC0A1E211B39EA00997B47 /* ThreadViewHelper.m in Sources */, 34641E182088D7E900E2EDE5 /* OWSScreenLock.swift in Sources */, 346129721FD1D74C00532771 /* SignalKeyingStorage.m in Sources */, + 349EA07C2162AEA800F7B17F /* OWS111UDAttributesMigration.swift in Sources */, 34480B561FD0A7A400BC14EF /* DebugLogger.m in Sources */, 459B775C207BA46C0071D0AB /* OWSQuotedReplyModel.m in Sources */, 34ABB2C42090C59700C727A6 /* OWSResaveCollectionDBMigration.m in Sources */, diff --git a/Signal/src/Models/AccountManager.swift b/Signal/src/Models/AccountManager.swift index e37a475dd..fa1a38221 100644 --- a/Signal/src/Models/AccountManager.swift +++ b/Signal/src/Models/AccountManager.swift @@ -14,8 +14,6 @@ import SignalServiceKit public class AccountManager: NSObject { let textSecureAccountManager: TSAccountManager - let networkManager: TSNetworkManager - let preferences: OWSPreferences var pushManager: PushManager { // dependency injection hack since PushManager has *alot* of dependencies, and would induce a cycle. @@ -23,16 +21,24 @@ public class AccountManager: NSObject { } @objc - public required init(textSecureAccountManager: TSAccountManager, preferences: OWSPreferences) { - self.networkManager = textSecureAccountManager.networkManager + public required init(textSecureAccountManager: TSAccountManager) { self.textSecureAccountManager = textSecureAccountManager - self.preferences = preferences super.init() SwiftSingletons.register(self) } + // MARK: - Singletons + + private var networkManager: TSNetworkManager { + return SSKEnvironment.shared.networkManager + } + + private var preferences: OWSPreferences { + return Environment.shared.preferences + } + // MARK: registration @objc func register(verificationCode: String, @@ -108,9 +114,17 @@ public class AccountManager: NSObject { } func registerForManualMessageFetching() -> Promise { - return Promise { fulfill, reject in - self.textSecureAccountManager.registerForManualMessageFetching(success: fulfill, failure: reject) - } + TSAccountManager.sharedInstance().setIsManualMessageFetchEnabled(true) + + // Try to update the account attributes to reflect this change. + let request = OWSRequestFactory.updateAttributesRequest() + let promise: Promise = self.networkManager.makePromise(request: request) + .then(execute: { (_, _) in + Logger.info("updated server with account attributes to enableManualFetching") + }).catch(execute: { (error) in + Logger.error("failed to update server with account attributes with error: \(error)") + }) + return promise } // MARK: Turn Server @@ -136,5 +150,4 @@ public class AccountManager: NSObject { }) } } - } diff --git a/Signal/src/environment/SignalApp.m b/Signal/src/environment/SignalApp.m index 9f5698df9..5607eee0c 100644 --- a/Signal/src/environment/SignalApp.m +++ b/Signal/src/environment/SignalApp.m @@ -63,8 +63,7 @@ NS_ASSUME_NONNULL_BEGIN OWSAssertDebug(SSKEnvironment.shared.networkManager); OWSAssertDebug(SSKEnvironment.shared.contactsUpdater); - _accountManager = [[AccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance] - preferences:Environment.shared.preferences]; + _accountManager = [[AccountManager alloc] initWithTextSecureAccountManager:[TSAccountManager sharedInstance]]; _notificationsManager = [NotificationsManager new]; SSKEnvironment.shared.notificationsManager = self.notificationsManager; diff --git a/SignalMessaging/environment/VersionMigrations.m b/SignalMessaging/environment/VersionMigrations.m index 6ba53146a..47f117922 100644 --- a/SignalMessaging/environment/VersionMigrations.m +++ b/SignalMessaging/environment/VersionMigrations.m @@ -128,7 +128,7 @@ NS_ASSUME_NONNULL_BEGIN } } -#pragma mark Upgrading to 2.1.3 - Adding VOIP flag on TS Server +#pragma mark - Update Account Attributes + (void)blockingAttributesUpdate { @@ -139,7 +139,7 @@ NS_ASSUME_NONNULL_BEGIN __block BOOL success; - TSRequest *request = [OWSRequestFactory updateAttributesRequestWithManualMessageFetching:NO]; + TSRequest *request = [OWSRequestFactory updateAttributesRequest]; [[TSNetworkManager sharedManager] makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { success = YES; diff --git a/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m b/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m index b8687f422..fcd19cefb 100644 --- a/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m +++ b/SignalMessaging/environment/migrations/OWS103EnableVideoCalling.m @@ -25,7 +25,7 @@ static NSString *const OWS103EnableVideoCallingMigrationId = @"103"; OWSLogWarn(@"running migration..."); if ([TSAccountManager isRegistered]) { dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ - TSRequest *request = [OWSRequestFactory updateAttributesRequestWithManualMessageFetching:NO]; + TSRequest *request = [OWSRequestFactory updateAttributesRequest]; [[TSNetworkManager sharedManager] makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { OWSLogInfo(@"successfully ran"); diff --git a/SignalMessaging/environment/migrations/OWS111UDAttributesMigration.swift b/SignalMessaging/environment/migrations/OWS111UDAttributesMigration.swift new file mode 100644 index 000000000..ae94b22d2 --- /dev/null +++ b/SignalMessaging/environment/migrations/OWS111UDAttributesMigration.swift @@ -0,0 +1,44 @@ +// +// Copyright (c) 2018 Open Whisper Systems. All rights reserved. +// + +import Foundation + +class OWS111UDAttributesMigration: OWSDatabaseMigration { + + // MARK: - Singletons + + private var networkManager: TSNetworkManager { + return SSKEnvironment.shared.networkManager + } + + // MARK: - + + // increment a similar constant for each migration. + @objc + class func migrationId() -> String { + return "111" + } + + override public func runUp(completion: @escaping OWSDatabaseMigrationCompletion) { + Logger.debug("") + BenchAsync(title: "UD Attributes Migration") { completeBenchmark in + self.doMigration { + completeBenchmark() + completion() + } + } + } + + private func doMigration(completion: @escaping OWSDatabaseMigrationCompletion) { + let request = OWSRequestFactory.updateAttributesRequest() + self.networkManager.makePromise(request: request).then(execute: { (_, _) in + self.dbReadWriteConnection().readWrite { transaction in + self.save(with: transaction) + } + }) + .always { + completion() + }.retainUntilComplete() + } +} diff --git a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m index f150e17b9..c47aa6c7b 100644 --- a/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m +++ b/SignalMessaging/environment/migrations/OWSDatabaseMigrationRunner.m @@ -45,6 +45,7 @@ NS_ASSUME_NONNULL_BEGIN [[OWS107LegacySounds alloc] initWithPrimaryStorage:primaryStorage], [[OWS108CallLoggingPreference alloc] initWithPrimaryStorage:primaryStorage], [[OWS109OutgoingMessageState alloc] initWithPrimaryStorage:primaryStorage] + [[OWS111UDAttributesMigration alloc] initWithPrimaryStorage:primaryStorage], ]; } diff --git a/SignalServiceKit/src/Account/TSAccountManager.h b/SignalServiceKit/src/Account/TSAccountManager.h index a9e4ba626..60ce8557b 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.h +++ b/SignalServiceKit/src/Account/TSAccountManager.h @@ -91,9 +91,6 @@ extern NSString *const kNSNotificationName_LocalNumberDidChange; success:(void (^)(void))successBlock failure:(void (^)(NSError *error))failureBlock; -- (void)registerForManualMessageFetchingWithSuccess:(void (^)(void))successBlock - failure:(void (^)(NSError *error))failureBlock; - // Called once registration is complete - meaning the following have succeeded: // - obtained signal server credentials // - uploaded pre-keys @@ -137,6 +134,11 @@ extern NSString *const kNSNotificationName_LocalNumberDidChange; - (NSString *)reregisterationPhoneNumber; - (BOOL)isReregistering; +#pragma mark - Manual Message Fetch + +- (BOOL)isManualMessageFetchEnabled; +- (void)setIsManualMessageFetchEnabled:(BOOL)value; + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Account/TSAccountManager.m b/SignalServiceKit/src/Account/TSAccountManager.m index 3fe05de2a..df9c0cd69 100644 --- a/SignalServiceKit/src/Account/TSAccountManager.m +++ b/SignalServiceKit/src/Account/TSAccountManager.m @@ -11,7 +11,6 @@ #import "OWSRequestFactory.h" #import "TSNetworkManager.h" #import "TSPreKeyManager.h" -#import "TSVerifyCodeRequest.h" #import "YapDatabaseConnection+OWS.h" #import "YapDatabaseTransaction+OWS.h" #import @@ -34,6 +33,7 @@ NSString *const TSAccountManager_LocalRegistrationIdKey = @"TSStorageLocalRegist NSString *const TSAccountManager_UserAccountCollection = @"TSStorageUserAccountCollection"; NSString *const TSAccountManager_ServerAuthToken = @"TSStorageServerAuthToken"; NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignalingKey"; +NSString *const TSAccountManager_ManualMessageFetchKey = @"TSAccountManager_ManualMessageFetchKey"; @interface TSAccountManager () @@ -327,21 +327,6 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling [self registerWithPhoneNumber:number success:successBlock failure:failureBlock smsVerification:NO]; } -- (void)registerForManualMessageFetchingWithSuccess:(void (^)(void))successBlock - failure:(void (^)(NSError *error))failureBlock -{ - TSRequest *request = [OWSRequestFactory updateAttributesRequestWithManualMessageFetching:YES]; - [self.networkManager makeRequest:request - success:^(NSURLSessionDataTask *_Nonnull task, id _Nonnull responseObject) { - OWSLogInfo(@"updated server with account attributes to enableManualFetching"); - successBlock(); - } - failure:^(NSURLSessionDataTask *_Nonnull task, NSError *_Nonnull error) { - OWSLogInfo(@"failed to updat server with account attributes with error: %@", error); - failureBlock(error); - }]; -} - - (void)verifyAccountWithCode:(NSString *)verificationCode pin:(nullable NSString *)pin success:(void (^)(void))successBlock @@ -355,11 +340,11 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling OWSAssertDebug(authToken); OWSAssertDebug(phoneNumber); - TSVerifyCodeRequest *request = [[TSVerifyCodeRequest alloc] initWithVerificationCode:verificationCode - forNumber:phoneNumber - pin:pin - signalingKey:signalingKey - authKey:authToken]; + TSRequest *request = [OWSRequestFactory verifyCodeRequestWithVerificationCode:verificationCode + forNumber:phoneNumber + pin:pin + signalingKey:signalingKey + authKey:authToken]; [self.networkManager makeRequest:request success:^(NSURLSessionDataTask *task, id responseObject) { @@ -604,6 +589,20 @@ NSString *const TSAccountManager_ServerSignalingKey = @"TSStorageServerSignaling inCollection:TSAccountManager_UserAccountCollection]; } +- (BOOL)isManualMessageFetchEnabled +{ + return [self.dbConnection boolForKey:TSAccountManager_ManualMessageFetchKey + inCollection:TSAccountManager_UserAccountCollection + defaultValue:NO]; +} + +- (void)setIsManualMessageFetchEnabled:(BOOL)value +{ + [self.dbConnection setBool:value + forKey:TSAccountManager_ManualMessageFetchKey + inCollection:TSAccountManager_UserAccountCollection]; +} + @end NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Account/TSAttributes.h b/SignalServiceKit/src/Account/TSAttributes.h deleted file mode 100644 index a9168b440..000000000 --- a/SignalServiceKit/src/Account/TSAttributes.h +++ /dev/null @@ -1,18 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -NS_ASSUME_NONNULL_BEGIN - -@interface TSAttributes : NSObject - -+ (NSDictionary *)attributesFromStorageWithManualMessageFetching:(BOOL)isEnabled pin:(nullable NSString *)pin; - -+ (NSDictionary *)attributesWithSignalingKey:(NSString *)signalingKey - serverAuthToken:(NSString *)authToken - manualMessageFetching:(BOOL)isEnabled - pin:(nullable NSString *)pin; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Account/TSAttributes.m b/SignalServiceKit/src/Account/TSAttributes.m deleted file mode 100644 index 5ca669ed2..000000000 --- a/SignalServiceKit/src/Account/TSAttributes.m +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "TSAttributes.h" -#import "TSAccountManager.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation TSAttributes - -+ (NSDictionary *)attributesFromStorageWithManualMessageFetching:(BOOL)isEnabled pin:(nullable NSString *)pin -{ - return [self attributesWithSignalingKey:TSAccountManager.signalingKey - serverAuthToken:TSAccountManager.serverAuthToken - manualMessageFetching:isEnabled - pin:pin]; -} - -+ (NSDictionary *)attributesWithSignalingKey:(NSString *)signalingKey - serverAuthToken:(NSString *)authToken - manualMessageFetching:(BOOL)isEnabled - pin:(nullable NSString *)pin -{ - OWSAssertDebug(signalingKey.length > 0); - OWSAssertDebug(authToken.length > 0); - - NSMutableDictionary *result = [@{ - @"signalingKey" : signalingKey, - @"AuthKey" : authToken, - @"voice" : @(YES), // all Signal-iOS clients support voice - @"video" : @(YES), // all Signal-iOS clients support WebRTC-based voice and video calls. - @"fetchesMessages" : - @(isEnabled), // devices that don't support push must tell the server they fetch messages manually - @"registrationId" : [NSString stringWithFormat:@"%i", [TSAccountManager getOrGenerateRegistrationId]] - } mutableCopy]; - if (pin.length > 0) { - result[@"pin"] = pin; - } - return [result copy]; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Messages/UD/OWSUDManager.swift b/SignalServiceKit/src/Messages/UD/OWSUDManager.swift index f485903ab..f42d34289 100644 --- a/SignalServiceKit/src/Messages/UD/OWSUDManager.swift +++ b/SignalServiceKit/src/Messages/UD/OWSUDManager.swift @@ -26,10 +26,18 @@ public enum OWSUDError: Error { // No-op if this recipient id is already marked as _NOT_ a "UD recipient". @objc func removeUDRecipientId(_ recipientId: String) + // MARK: - Sender Certificate + // We use completion handlers instead of a promise so that message sending // logic can access the certificate data. @objc func ensureSenderCertificateObjC(success:@escaping (Data) -> Void, failure:@escaping (Error) -> Void) + + // MARK: - Unrestricted Access + + @objc func allowUnrestrictedAccess() -> Bool + + @objc func setAllowUnrestrictedAccess(_ value: Bool) } // MARK: - @@ -42,6 +50,7 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { private let kUDRecipientModeCollection = "kUDRecipientModeCollection" private let kUDCollection = "kUDCollection" private let kUDCurrentSenderCertificateKey = "kUDCurrentSenderCertificateKey" + private let kUDUnrestrictedAccessKey = "kUDUnrestrictedAccessKey" @objc public required init(primaryStorage: OWSPrimaryStorage) { @@ -166,4 +175,16 @@ public class OWSUDManagerImpl: NSObject, OWSUDManager { return false } } + + // MARK: - Unrestricted Access + + @objc + public func allowUnrestrictedAccess() -> Bool { + return dbConnection.bool(forKey: kUDUnrestrictedAccessKey, inCollection: kUDRecipientModeCollection, defaultValue: false) + } + + @objc + public func setAllowUnrestrictedAccess(_ value: Bool) { + dbConnection.setBool(value, forKey: kUDUnrestrictedAccessKey, inCollection: kUDRecipientModeCollection) + } } diff --git a/SignalServiceKit/src/Network/API/NetworkManager.swift b/SignalServiceKit/src/Network/API/NetworkManager.swift index 17a8acb1c..c196be0b4 100644 --- a/SignalServiceKit/src/Network/API/NetworkManager.swift +++ b/SignalServiceKit/src/Network/API/NetworkManager.swift @@ -27,7 +27,7 @@ extension NetworkManagerError { } extension TSNetworkManager { - func makePromise(request: TSRequest) -> Promise<(task: URLSessionDataTask, responseObject: Any?)> { + public func makePromise(request: TSRequest) -> Promise<(task: URLSessionDataTask, responseObject: Any?)> { let (promise, fulfill, reject) = Promise<(task: URLSessionDataTask, responseObject: Any?)>.pending() self.makeRequest(request, diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h index c3a9744fa..28b0bdd94 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.h @@ -46,7 +46,7 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo + (TSRequest *)registerForPushRequestWithPushIdentifier:(NSString *)identifier voipIdentifier:(NSString *)voipId; -+ (TSRequest *)updateAttributesRequestWithManualMessageFetching:(BOOL)enableManualMessageFetching; ++ (TSRequest *)updateAttributesRequest; + (TSRequest *)unregisterAccountRequest; @@ -57,6 +57,12 @@ typedef NS_ENUM(NSUInteger, TSVerificationTransport) { TSVerificationTransportVo messages:(NSArray *)messages timeStamp:(uint64_t)timeStamp; ++ (TSRequest *)verifyCodeRequestWithVerificationCode:(NSString *)verificationCode + forNumber:(NSString *)phoneNumber + pin:(nullable NSString *)pin + signalingKey:(NSString *)signalingKey + authKey:(NSString *)authKey; + #pragma mark - Prekeys + (TSRequest *)availablePreKeysCountRequest; diff --git a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m index d8338f658..7dc4206e3 100644 --- a/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m +++ b/SignalServiceKit/src/Network/API/Requests/OWSRequestFactory.m @@ -5,13 +5,18 @@ #import "OWSRequestFactory.h" #import "OWS2FAManager.h" #import "OWSDevice.h" -#import "TSAttributes.h" +#import "ProfileManagerProtocol.h" +#import "SSKEnvironment.h" +#import "TSAccountManager.h" #import "TSConstants.h" #import "TSRequest.h" #import #import #import +#import #import +#import +#import NS_ASSUME_NONNULL_BEGIN @@ -165,15 +170,20 @@ NS_ASSUME_NONNULL_BEGIN }]; } -+ (TSRequest *)updateAttributesRequestWithManualMessageFetching:(BOOL)enableManualMessageFetching ++ (TSRequest *)updateAttributesRequest { NSString *path = [textSecureAccountsAPI stringByAppendingString:textSecureAttributesAPI]; + + NSString *signalingKey = TSAccountManager.signalingKey; + OWSAssertDebug(signalingKey.length > 0); + NSString *authKey = TSAccountManager.serverAuthToken; + OWSAssertDebug(authKey.length > 0); NSString *_Nullable pin = [OWS2FAManager.sharedManager pinCode]; - return [TSRequest - requestWithUrl:[NSURL URLWithString:path] - method:@"PUT" - parameters:[TSAttributes attributesFromStorageWithManualMessageFetching:enableManualMessageFetching - pin:pin]]; + + NSDictionary *accountAttributes = + [self accountAttributesWithPin:pin signalingKey:signalingKey authKey:authKey]; + + return [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:accountAttributes]; } + (TSRequest *)unregisterAccountRequest @@ -205,6 +215,68 @@ NS_ASSUME_NONNULL_BEGIN } } ++ (TSRequest *)verifyCodeRequestWithVerificationCode:(NSString *)verificationCode + forNumber:(NSString *)phoneNumber + pin:(nullable NSString *)pin + signalingKey:(NSString *)signalingKey + authKey:(NSString *)authKey +{ + OWSAssertDebug(verificationCode.length > 0); + OWSAssertDebug(phoneNumber.length > 0); + OWSAssertDebug(signalingKey.length > 0); + OWSAssertDebug(authKey.length > 0); + + NSString *path = [NSString stringWithFormat:@"%@/code/%@", textSecureAccountsAPI, verificationCode]; + + NSMutableDictionary *accountAttributes = + [[self accountAttributesWithPin:pin signalingKey:signalingKey authKey:authKey] mutableCopy]; + [accountAttributes removeObjectForKey:@"AuthKey"]; + + TSRequest *request = + [TSRequest requestWithUrl:[NSURL URLWithString:path] method:@"PUT" parameters:accountAttributes]; + // The "verify code" request handles auth differently. + request.authUsername = phoneNumber; + request.authPassword = authKey; + return request; +} + ++ (NSDictionary *)accountAttributesWithPin:(nullable NSString *)pin + signalingKey:(NSString *)signalingKey + authKey:(NSString *)authKey +{ + OWSAssertDebug(signalingKey.length > 0); + OWSAssertDebug(authKey.length > 0); + uint32_t registrationId = [TSAccountManager getOrGenerateRegistrationId]; + + BOOL isManualMessageFetchEnabled = TSAccountManager.sharedInstance.isManualMessageFetchEnabled; + + OWSAES256Key *profileKey = [SSKEnvironment.shared.profileManager localProfileKey]; + NSError *error; + SMKUDAccessKey *_Nullable udAccessKey = [[SMKUDAccessKey alloc] initWithProfileKey:profileKey.keyData error:&error]; + if (error || !udAccessKey) { + OWSLogError(@"Could not determine UD access key: %@.", error); + } + BOOL allowUnrestrictedUD = [SSKEnvironment.shared.udManager allowUnrestrictedAccess] && udAccessKey != nil; + + NSMutableDictionary *accountAttributes = [@{ + @"signalingKey" : signalingKey, + @"AuthKey" : authKey, + @"voice" : @(YES), // all Signal-iOS clients support voice + @"video" : @(YES), // all Signal-iOS clients support WebRTC-based voice and video calls. + @"fetchesMessages" : @(isManualMessageFetchEnabled), // devices that don't support push must tell the server + // they fetch messages manually + @"registrationId" : [NSString stringWithFormat:@"%i", registrationId], + } mutableCopy]; + if (pin.length > 0) { + accountAttributes[@"pin"] = pin; + } + if (udAccessKey.keyData.length > 0) { + accountAttributes[@"unidentifiedAccessKey"] = udAccessKey.keyData.base64EncodedString; + accountAttributes[@"unrestrictedUnidentifiedAccess"] = @(allowUnrestrictedUD); + } + return [accountAttributes copy]; +} + + (TSRequest *)submitMessageRequestWithRecipient:(NSString *)recipientId messages:(NSArray *)messages timeStamp:(uint64_t)timeStamp diff --git a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h deleted file mode 100644 index 60857cf00..000000000 --- a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.h +++ /dev/null @@ -1,23 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "TSRequest.h" - -NS_ASSUME_NONNULL_BEGIN - -@interface TSVerifyCodeRequest : TSRequest - -@property (nonatomic, readonly) NSString *numberToValidate; - -- (instancetype)init NS_UNAVAILABLE; - -- (TSRequest *)initWithVerificationCode:(NSString *)verificationCode - forNumber:(NSString *)phoneNumber - pin:(nullable NSString *)pin - signalingKey:(NSString *)signalingKey - authKey:(NSString *)authKey; - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m b/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m deleted file mode 100644 index 06d12818d..000000000 --- a/SignalServiceKit/src/Network/API/Requests/TSVerifyCodeRequest.m +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "TSVerifyCodeRequest.h" -#import "TSAccountManager.h" -#import "TSAttributes.h" -#import "TSConstants.h" - -NS_ASSUME_NONNULL_BEGIN - -@implementation TSVerifyCodeRequest - -- (TSRequest *)initWithVerificationCode:(NSString *)verificationCode - forNumber:(NSString *)phoneNumber - pin:(nullable NSString *)pin - signalingKey:(NSString *)signalingKey - authKey:(NSString *)authKey -{ - OWSAssertDebug(verificationCode.length > 0); - OWSAssertDebug(phoneNumber.length > 0); - OWSAssertDebug(signalingKey.length > 0); - OWSAssertDebug(authKey.length > 0); - - NSURL *url = - [NSURL URLWithString:[NSString stringWithFormat:@"%@/code/%@", textSecureAccountsAPI, verificationCode]]; - NSDictionary *parameters = - [TSAttributes attributesWithSignalingKey:signalingKey serverAuthToken:authKey manualMessageFetching:NO pin:pin]; - self = [super initWithURL:url method:@"PUT" parameters:parameters]; - - _numberToValidate = phoneNumber; - - return self; -} - -@end - -NS_ASSUME_NONNULL_END diff --git a/SignalServiceKit/src/Network/API/TSNetworkManager.m b/SignalServiceKit/src/Network/API/TSNetworkManager.m index 46956f211..6b45081af 100644 --- a/SignalServiceKit/src/Network/API/TSNetworkManager.m +++ b/SignalServiceKit/src/Network/API/TSNetworkManager.m @@ -9,7 +9,7 @@ #import "OWSSignalService.h" #import "SSKEnvironment.h" #import "TSAccountManager.h" -#import "TSVerifyCodeRequest.h" +#import "TSRequest.h" #import #import #import @@ -103,56 +103,43 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error); // session manager, so its safe to reconfigure it here. sessionManager.completionQueue = completionQueue; - if ([request isKindOfClass:[TSVerifyCodeRequest class]]) { - // We plant the Authorization parameter ourselves, no need to double add. - [sessionManager.requestSerializer - setAuthorizationHeaderFieldWithUsername:((TSVerifyCodeRequest *)request).numberToValidate - password:[request.parameters objectForKey:@"AuthKey"]]; - NSMutableDictionary *parameters = [request.parameters mutableCopy]; - [parameters removeObjectForKey:@"AuthKey"]; - [sessionManager PUT:request.URL.absoluteString parameters:parameters success:success failure:failure]; + if (request.shouldHaveAuthorizationHeaders) { + [sessionManager.requestSerializer setAuthorizationHeaderFieldWithUsername:request.authUsername + password:request.authPassword]; + } + + // Honor the request's preferences about default cookie handling. + // + // Default is YES. + sessionManager.requestSerializer.HTTPShouldHandleCookies = request.HTTPShouldHandleCookies; + + // Honor the request's headers. + for (NSString *headerField in request.allHTTPHeaderFields) { + NSString *headerValue = request.allHTTPHeaderFields[headerField]; + [sessionManager.requestSerializer setValue:headerValue forHTTPHeaderField:headerField]; + } + + if ([request.HTTPMethod isEqualToString:@"GET"]) { + [sessionManager GET:request.URL.absoluteString + parameters:request.parameters + progress:nil + success:success + failure:failure]; + } else if ([request.HTTPMethod isEqualToString:@"POST"]) { + [sessionManager POST:request.URL.absoluteString + parameters:request.parameters + progress:nil + success:success + failure:failure]; + } else if ([request.HTTPMethod isEqualToString:@"PUT"]) { + [sessionManager PUT:request.URL.absoluteString parameters:request.parameters success:success failure:failure]; + } else if ([request.HTTPMethod isEqualToString:@"DELETE"]) { + [sessionManager DELETE:request.URL.absoluteString + parameters:request.parameters + success:success + failure:failure]; } else { - if (request.shouldHaveAuthorizationHeaders) { - [sessionManager.requestSerializer setAuthorizationHeaderFieldWithUsername:request.authUsername - password:request.authPassword]; - } - - // Honor the request's preferences about default cookie handling. - // - // Default is YES. - sessionManager.requestSerializer.HTTPShouldHandleCookies = request.HTTPShouldHandleCookies; - - // Honor the request's headers. - for (NSString *headerField in request.allHTTPHeaderFields) { - NSString *headerValue = request.allHTTPHeaderFields[headerField]; - [sessionManager.requestSerializer setValue:headerValue forHTTPHeaderField:headerField]; - } - - if ([request.HTTPMethod isEqualToString:@"GET"]) { - [sessionManager GET:request.URL.absoluteString - parameters:request.parameters - progress:nil - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"POST"]) { - [sessionManager POST:request.URL.absoluteString - parameters:request.parameters - progress:nil - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"PUT"]) { - [sessionManager PUT:request.URL.absoluteString - parameters:request.parameters - success:success - failure:failure]; - } else if ([request.HTTPMethod isEqualToString:@"DELETE"]) { - [sessionManager DELETE:request.URL.absoluteString - parameters:request.parameters - success:success - failure:failure]; - } else { - OWSLogError(@"Trying to perform HTTP operation with unknown verb: %@", request.HTTPMethod); - } + OWSLogError(@"Trying to perform HTTP operation with unknown verb: %@", request.HTTPMethod); } } @@ -204,8 +191,14 @@ typedef void (^failureBlock)(NSURLSessionDataTask *task, NSError *error); return ^(NSURLSessionDataTask *_Nullable task, NSError *_Nonnull networkError) { NSInteger statusCode = [task statusCode]; + DDLogInfo(@"statusCode: %zd", statusCode); + DDLogInfo(@"statusCode: %@", task.originalRequest.URL); + DDLogInfo(@"allHTTPHeaderFields: %@", task.originalRequest.allHTTPHeaderFields); + DDLogInfo(@"HTTPBody: %@", task.originalRequest.HTTPBody); + DDLogInfo(@"parameters: %@", request.parameters); + #ifdef DEBUG - [TSNetworkManager logCurlForTask:task]; + [TSNetworkManager logCurlForTask:task]; #endif [OutageDetection.sharedManager reportConnectionFailure]; diff --git a/SignalServiceKit/src/Tests/OWSFakeUDManager.swift b/SignalServiceKit/src/Tests/OWSFakeUDManager.swift index 51da1ad0a..f5442c791 100644 --- a/SignalServiceKit/src/Tests/OWSFakeUDManager.swift +++ b/SignalServiceKit/src/Tests/OWSFakeUDManager.swift @@ -43,6 +43,20 @@ public class OWSFakeUDManager: NSObject, OWSUDManager { } success(certificateData) } + + // MARK: - Unrestricted Access + + private var _allowUnrestrictedAccess = false + + @objc + public func allowUnrestrictedAccess() -> Bool { + return _allowUnrestrictedAccess + } + + @objc + public func setAllowUnrestrictedAccess(_ value: Bool) { + _allowUnrestrictedAccess = value + } } #endif diff --git a/SignalServiceKit/tests/Account/TSAttributesTest.m b/SignalServiceKit/tests/Account/TSAttributesTest.m deleted file mode 100644 index f42145a9e..000000000 --- a/SignalServiceKit/tests/Account/TSAttributesTest.m +++ /dev/null @@ -1,45 +0,0 @@ -// -// Copyright (c) 2018 Open Whisper Systems. All rights reserved. -// - -#import "TSAttributes.h" -#import "SSKBaseTestObjC.h" -#import "TSAccountManager.h" -#import - -@interface TSAttributesTest : SSKBaseTestObjC - -@end - -@implementation TSAttributesTest - -- (void)setUp { - [super setUp]; - // Put setup code here. This method is called before the invocation of each test method in the class. -} - -- (void)tearDown { - // Put teardown code here. This method is called after the invocation of each test method in the class. - [super tearDown]; -} - -- (void)testAttributesWithSignalingKey { - - NSString *registrationId = [NSString stringWithFormat:@"%i", [TSAccountManager getOrGenerateRegistrationId]]; - NSDictionary *expected = @{ - @"AuthKey" : @"fake-server-auth-token", - @"registrationId" : registrationId, - @"signalingKey" : @"fake-signaling-key", - @"video" : @1, - @"voice" : @1 - }; - - NSDictionary *actual = [TSAttributes attributesWithSignalingKey:@"fake-signaling-key" - serverAuthToken:@"fake-server-auth-token" - manualMessageFetching:NO - pin:nil]; - - XCTAssertEqualObjects(expected, actual); -} - -@end