Moving away from custom HTTP stack

This commit is contained in:
Frederic Jacobs 2014-10-06 01:28:45 +02:00
parent 510831d701
commit d05791e699
28 changed files with 17973 additions and 4955 deletions

View File

@ -7,6 +7,6 @@ pod 'UICKeyChainStore', :podspec => 'Podspecs/UICKeyChainStore.podspec
pod 'OpenSSL', '~> 1.0.109'
pod 'MMDrawerController', '~> 0.5.7'
pod 'libPhoneNumber-iOS', '~> 0.7'
pod 'PastelogKit', '~> 1.1'
pod 'PastelogKit', '~> 1.2'
pod 'AFNetworking', '~> 2.4.1'
pod 'TwistedOakCollapsingFutures','~> 1.0'

View File

@ -39,7 +39,7 @@ PODS:
- MMDrawerController/Subclass (0.5.7):
- MMDrawerController/Core
- OpenSSL (1.0.109)
- PastelogKit (1.1):
- PastelogKit (1.2):
- CocoaLumberjack (~> 1.9)
- TwistedOakCollapsingFutures (1.0.0):
- UnionFind (~> 1.0)
@ -51,7 +51,7 @@ DEPENDENCIES:
- libPhoneNumber-iOS (~> 0.7)
- MMDrawerController (~> 0.5.7)
- OpenSSL (~> 1.0.109)
- PastelogKit (~> 1.1)
- PastelogKit (~> 1.2)
- TwistedOakCollapsingFutures (~> 1.0)
- UICKeyChainStore (from `Podspecs/UICKeyChainStore.podspec`)
@ -65,7 +65,7 @@ SPEC CHECKSUMS:
libPhoneNumber-iOS: 98fc07d70c8fdb5e6a8e3442c37e97353065c20e
MMDrawerController: c3ab7a318ddc7e2bcd133139c3161af08c6e1197
OpenSSL: 4810adf5c99b0e2cd20670a11a987c805e8a521c
PastelogKit: 32836ec27e587a8876326abeaf9a1b5e2bc484ea
PastelogKit: 8bab71b1d187617a83e7124cffe9eb1a600e6695
TwistedOakCollapsingFutures: 07aab84fd3958dc94d55ef705b12857d9fbe61d1
UICKeyChainStore: eef407137f0397e95a3df32cdf05f7e2ddd99647
UnionFind: 45777a8b6878d3a602af3654cc3a09b87389d356

2
Pods

@ -1 +1 @@
Subproject commit e77476e6f8ddec69fb20785f9ff61db0ea95035a
Subproject commit 585c9e6ca1b55e99fb5c09aa31a6d590c2be5c58

File diff suppressed because it is too large Load Diff

View File

@ -59,9 +59,9 @@
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
launchStyle = "1"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
buildConfiguration = "Ad-Hoc Distribution"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">

View File

@ -60,6 +60,7 @@
DDLogError(@"No previous version found. Possibly first launch since install.");
[Environment resetAppData]; // We clean previous keychain entries in case their are some entries remaining.
} else if ([currentVersion compare:previousVersion options:NSNumericSearch] == NSOrderedDescending){
[Environment resetAppData];
// Application was updated, let's see if we have a migration scheme for it.
if ([previousVersion isEqualToString:@"1.0.2"]) {
// Migrate from custom preferences to NSUserDefaults

View File

@ -7,6 +7,7 @@
#define NOTIFICATION_DIRECTORY_UPDATE @"NOTIFICATION_DIRECTORY_UPDATE"
#define NOTIFICATION_DIRECTORY_WAS_UPDATED @"NOTIFICATION_DIRECTORY_WAS_UPDATED"
#define NOTIFICATION_DIRECTORY_FAILED @"NOTIFICATION_DIRECTORY_FAILED"
#define NOTIFICATION_NEW_USERS_AVAILABLE @"NOTIFICATION_NEW_USERS_AVAILABLE"

View File

@ -141,7 +141,7 @@
#pragma mark - Contact Intersection
#define TIMEOUT NSLocalizedString(@"TIMEOUT",@"")
#define TIMEOUT NSLocalizedString(@"ERROR_WAS_DETECTED_TITLE",@"")
#define TIMEOUT_CONTACTS_DETAIL NSLocalizedString(@"TIMEOUT_CONTACTS_DETAIL", @"")
NSDictionary* makeCallProgressLocalizedTextDictionary(void);

View File

@ -1,13 +0,0 @@
//
// AFFutureRequest.h
// Signal
//
// Created by Frederic Jacobs on 05/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface AFFutureRequest : NSObject
@end

View File

@ -1,13 +0,0 @@
//
// AFFutureRequest.m
// Signal
//
// Created by Frederic Jacobs on 05/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "AFFutureRequest.h"
@implementation AFFutureRequest
@end

View File

@ -6,7 +6,7 @@
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <TwistedOakCollapsingFutures/CollapsingFutures.h>
#import <CollapsingFutures.h>
#import <Foundation/Foundation.h>

View File

@ -8,7 +8,7 @@
#import "PreferencesUtil.h"
#import "PushManager.h"
#import "Environment.h"
#import "CallServerRequestsManager.h"
#import "RPServerRequestsManager.h"
#import "FutureUtil.h"
@interface PushManager ()
@ -104,7 +104,7 @@
-(TOCFuture*)registerForPushFutureWithToken:(NSData*)token{
self.registerWithServerFutureSource = [TOCFutureSource new];
[CallServerRequestsManager.sharedInstance registerPushToken:token success:^(NSURLSessionDataTask *task, id responseObject) {
[RPServerRequestsManager.sharedInstance performRequest:[RPAPICall registerPushNotificationWithPushToken:token] success:^(NSURLSessionDataTask *task, id responseObject) {
if ([task.response isKindOfClass: NSHTTPURLResponse.class]){
NSInteger statusCode = [(NSHTTPURLResponse*) task.response statusCode];
if (statusCode == 200) {
@ -116,10 +116,11 @@
} else{
[self.registerWithServerFutureSource trySetFailure:@NO];
}
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[self.registerWithServerFutureSource trySetFailure:@NO];
}];
return self.registerWithServerFutureSource.future;
}

View File

@ -0,0 +1,23 @@
//
// AFHTTPSessionManager+SignalMethods.h
// Signal
//
// Created by Frederic Jacobs on 05/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "AFHTTPSessionManager.h"
@interface AFHTTPSessionManager (SignalMethods)
- (NSURLSessionDataTask *)BUSY:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
- (NSURLSessionDataTask *)RING:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
@end

View File

@ -0,0 +1,49 @@
//
// AFHTTPSessionManager+SignalMethods.m
// Signal
//
// Created by Frederic Jacobs on 05/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "AFHTTPSessionManager+SignalMethods.h"
@interface AFHTTPSessionManager ()
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
URLString:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *, id))success
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure;
@end
@implementation AFHTTPSessionManager (SignalMethods)
- (NSURLSessionDataTask *)BUSY:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"BUSY" URLString:URLString parameters:parameters success:success failure:failure];
[dataTask resume];
return dataTask;
}
- (NSURLSessionDataTask *)RING:(NSString *)URLString
parameters:(id)parameters
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"RING" URLString:URLString parameters:parameters success:success failure:failure];
[dataTask resume];
return dataTask;
}
@end

View File

@ -1,18 +0,0 @@
//
// CallServerRequests.h
// Signal
//
// Created by Frederic Jacobs on 31/07/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>
@interface CallServerRequestsManager : NSObject
MacrosSingletonInterface
- (void)registerPushToken:(NSData*)deviceToken success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
@end

View File

@ -1,62 +0,0 @@
//
// CallServerRequests.m
// Signal
//
// Created by Frederic Jacobs on 31/07/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "HttpRequest.h"
#import "CallServerRequestsManager.h"
#import "DataUtil.h"
#import "Environment.h"
#import "HostNameEndPoint.h"
#import "SGNKeychainUtil.h"
#define defaultRequestTimeout
@interface CallServerRequestsManager ()
@property (nonatomic, retain)AFHTTPSessionManager *operationManager;
@end
@implementation CallServerRequestsManager
MacrosSingletonImplemention
- (id)init{
self = [super init];
if (self) {
HostNameEndPoint *endpoint = Environment.getCurrent.masterServerSecureEndPoint.hostNameEndPoint;
NSURL *endPointURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@:%hu", endpoint.hostname, endpoint.port]];
NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration;
self.operationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:endPointURL sessionConfiguration:sessionConf];
self.operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
self.operationManager.securityPolicy.allowInvalidCertificates = YES;
NSString *certPath = [NSBundle.mainBundle pathForResource:@"whisperReal" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:certPath];
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData));
self.operationManager.securityPolicy.pinnedCertificates = @[(__bridge_transfer NSData *)SecCertificateCopyData(cert)];
self.operationManager.securityPolicy.SSLPinningMode = AFSSLPinningModeCertificate;
}
return self;
}
- (void)registerPushToken:(NSData*)deviceToken success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{
self.operationManager.requestSerializer = [self basicAuthenticationSerializer];
[self.operationManager PUT:[NSString stringWithFormat:@"/apn/%@",deviceToken.encodedAsHexString] parameters:@{} success:success failure:failure];
}
- (AFHTTPRequestSerializer*)basicAuthenticationSerializer{
AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer];
[serializer setValue:[HttpRequest computeBasicAuthorizationTokenForLocalNumber:SGNKeychainUtil.localNumber
andPassword:SGNKeychainUtil.serverAuthPassword]
forHTTPHeaderField:@"Authorization"];
return serializer;
}
@end

View File

@ -1,7 +1,6 @@
#import <Foundation/Foundation.h>
#import "NetworkEndPoint.h"
#import "Logging.h"
#import "HttpRequestOrResponse.h"
#import "Terminable.h"
#import "Queue.h"
#import "PacketHandler.h"

View File

@ -38,7 +38,7 @@
if (optionalBody != nil) {
headers[@"Content-Length"] = [@(optionalBody.length) stringValue];
}
HttpRequest* s = [HttpRequest new];
s->_method = method;
s->_location = location;
@ -145,10 +145,10 @@
}
-(bool) isEqualToHttpRequest:(HttpRequest *)other {
return [self.toHttp isEqualToString:other.toHttp]
&& [self.method isEqualToString:other.method]
&& [self.location isEqualToString:other.location]
&& (self.optionalBody == other.optionalBody || [self.optionalBody isEqualToString:[other optionalBody]])
&& [self.headers isEqualToDictionary:other.headers];
&& [self.method isEqualToString:other.method]
&& [self.location isEqualToString:other.location]
&& (self.optionalBody == other.optionalBody || [self.optionalBody isEqualToString:[other optionalBody]])
&& [self.headers isEqualToDictionary:other.headers];
}
-(NSString*) description {
@ -156,8 +156,9 @@
self.method,
self.location,
self.optionalBody == nil ? @""
: self.optionalBody.length == 0 ? @" [empty body]"
: @" [...body...]"];
: self.optionalBody.length == 0 ? @" [empty body]"
: @" [...body...]"];
}
@end

View File

@ -0,0 +1,47 @@
//
// RedPhoneAPICall.h
// Signal
//
// Created by Frederic Jacobs on 05/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <AFNetworking/AFNetworking.h>
@class PhoneNumber;
@interface RPAPICall : NSObject
typedef NS_ENUM(NSInteger, HTTPMethod) {
HTTP_GET,
HTTP_POST,
HTTP_PUT,
HTTP_DELETE,
SIGNAL_RING,
SIGNAL_BUSY
};
#pragma mark API Call Properties
@property (nonatomic, readonly) NSString *endPoint;
@property (nonatomic, readonly) HTTPMethod method;
@property (nonatomic, readonly) NSDictionary *parameters;
@property (nonatomic, readonly) AFHTTPRequestSerializer <AFURLRequestSerialization> *requestSerializer;
@property (nonatomic, readonly) AFHTTPResponseSerializer <AFURLResponseSerialization> *responseSerializer;
#pragma mark API Call Contstructors
+ (RPAPICall*)requestVerificationCode;
+ (RPAPICall*)requestVerificationCodeWithVoice;
+ (RPAPICall*)verifyVerificationCode:(NSString*)verificationCode;
+ (RPAPICall*)registerPushNotificationWithPushToken:(NSData*)pushToken;
+ (RPAPICall*)unregister;
+ (RPAPICall*)fetchBloomFilter;
//+ (RPAPICall*)requestToOpenPortWithSessionId:(int64_t)sessionId;
//+ (RPAPICall*)requestToRingWithSessionId:(int64_t)sessionId;
//+ (RPAPICall*)requestToSignalBusyWithSessionId:(int64_t)sessionId;
//+ (RPAPICall*)requestToInitiateToRemoteNumber:(PhoneNumber*)remoteNumber;
@end

View File

@ -0,0 +1,168 @@
//
// RedPhoneAPICall.m
// Signal
//
// Created by Frederic Jacobs on 05/10/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "Constraints.h"
#import "CryptoTools.h"
#import "PhoneNumber.h"
#import "RPAPICall.h"
#import "SignalUtil.h"
#import "SGNKeychainUtil.h"
#import "Util.h"
#define CLAIMED_INTEROP_VERSION_IN_INITIATE_SIGNAL 1
@interface RPAPICall ()
@property (nonatomic, readwrite) NSString *endPoint;
@property (nonatomic, readwrite) HTTPMethod method;
@property (nonatomic, readwrite) NSDictionary *parameters;
@property (nonatomic, readwrite) AFHTTPRequestSerializer <AFURLRequestSerialization> *requestSerializer;
@property (nonatomic, readwrite) AFHTTPResponseSerializer <AFURLResponseSerialization> *responseSerializer;
@end
@implementation RPAPICall
+ (RPAPICall*)defaultAPICall {
RPAPICall *apiCall = [[RPAPICall alloc] init];
apiCall.parameters = @{};
apiCall.requestSerializer = [self basicAuthenticationSerializer];
apiCall.responseSerializer = [AFHTTPResponseSerializer serializer];
return apiCall;
}
+ (RPAPICall*)requestVerificationCode {
[SGNKeychainUtil generateServerAuthPassword];
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_GET;
apiCall.endPoint = @"/users/verification";
return apiCall;
}
+ (RPAPICall*)requestVerificationCodeWithVoice {
RPAPICall *apiCall = [self requestVerificationCode];
apiCall.endPoint = [apiCall.endPoint stringByAppendingString:@"/voice"];
return apiCall;
}
+ (RPAPICall*)verifyVerificationCode:(NSString*)verificationCode {
RPAPICall *apiCall = [self defaultAPICall];
[SGNKeychainUtil generateSignaling];
apiCall.method = HTTP_PUT;
apiCall.endPoint = [NSString stringWithFormat:@"/users/verification/%@", SGNKeychainUtil.localNumber];
NSData* signalingCipherKey = SGNKeychainUtil.signalingCipherKey;
NSData* signalingMacKey = SGNKeychainUtil.signalingMacKey;
NSData* signalingExtraKeyData = SGNKeychainUtil.signalingCipherKey;
NSString* encodedSignalingKey = @[signalingCipherKey, signalingMacKey, signalingExtraKeyData].concatDatas.encodedAsBase64;
apiCall.parameters = @{@"key" : encodedSignalingKey, @"challenge" : verificationCode};
return apiCall;
}
+ (RPAPICall*)registerPushNotificationWithPushToken:(NSData*)pushToken {
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_PUT;
apiCall.endPoint = [NSString stringWithFormat:@"/apn/%@", pushToken.encodedAsHexString];
return apiCall;
}
+ (RPAPICall*)fetchBloomFilter {
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_GET;
apiCall.endPoint = @"/users/directory";
apiCall.requestSerializer = [self otpAuthenticationSerializer];
return apiCall;
}
+ (RPAPICall*)unregister {
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_GET;
apiCall.endPoint = @"/users/directory";
apiCall.requestSerializer = [self otpAuthenticationSerializer];
return apiCall;
}
+ (RPAPICall*)requestToOpenPortWithSessionId:(int64_t)sessionId {
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = HTTP_GET;
apiCall.endPoint = [NSString stringWithFormat:@"/open/%lld", sessionId];
apiCall.requestSerializer = [self unauthenticatedSerializer];
apiCall.responseSerializer = [AFHTTPResponseSerializer serializer];
return apiCall;
}
+ (RPAPICall*)requestToRingWithSessionId:(int64_t)sessionId {
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = SIGNAL_RING;
apiCall.endPoint = [NSString stringWithFormat:@"/session/%lld", sessionId];
apiCall.requestSerializer = [self otpAuthenticationSerializer];
return apiCall;
}
+ (RPAPICall*)requestToSignalBusyWithSessionId:(int64_t)sessionId {
RPAPICall *apiCall = [self defaultAPICall];
apiCall.method = SIGNAL_BUSY;
apiCall.endPoint = [NSString stringWithFormat:@"/session/%lld", sessionId];
apiCall.requestSerializer = [self otpAuthenticationSerializer];
return apiCall;
}
+ (RPAPICall*)requestToInitiateToRemoteNumber:(PhoneNumber*)remoteNumber {
RPAPICall *apiCall = [self defaultAPICall];
require(remoteNumber != nil);
NSString* formattedRemoteNumber = remoteNumber.toE164;
NSString* interopVersionInsert = (CLAIMED_INTEROP_VERSION_IN_INITIATE_SIGNAL == 0)? @"" : [NSString stringWithFormat:@"/%d", CLAIMED_INTEROP_VERSION_IN_INITIATE_SIGNAL];
apiCall.method = HTTP_GET;
apiCall.endPoint = [NSString stringWithFormat:@"/session%@/%@",
interopVersionInsert,
formattedRemoteNumber];
apiCall.requestSerializer = [self otpAuthenticationSerializer];
return apiCall;
}
#pragma mark Authorization Headers
+ (AFHTTPRequestSerializer*)basicAuthenticationSerializer {
AFHTTPRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setAuthorizationHeaderFieldWithUsername:SGNKeychainUtil.localNumber.toE164 password:SGNKeychainUtil.serverAuthPassword];
return serializer;
}
+ (AFHTTPRequestSerializer*)otpAuthenticationSerializer {
AFHTTPRequestSerializer *serializer = [AFJSONRequestSerializer serializer];
[serializer setAuthorizationHeaderFieldWithUsername:SGNKeychainUtil.localNumber.toE164 password:SGNKeychainUtil.serverAuthPassword];
return serializer;
}
+ (AFHTTPRequestSerializer*)unauthenticatedSerializer {
return [AFHTTPRequestSerializer serializer];
}
+ (NSString*) computeOtpAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber
andCounterValue:(int64_t)counterValue
andPassword:(NSString*)password {
require(localNumber != nil);
require(password != nil);
NSString* rawToken = [NSString stringWithFormat:@"%@:%@:%lld",
localNumber.toE164,
[CryptoTools computeOtpWithPassword:password andCounter:counterValue],
counterValue];
return [@"OTP " stringByAppendingString:rawToken.encodedAsUtf8.encodedAsBase64];
}
+ (NSString*) computeBasicAuthorizationTokenForLocalNumber:(PhoneNumber*)localNumber andPassword:(NSString*)password {
NSString* rawToken = [NSString stringWithFormat:@"%@:%@",
localNumber.toE164,
password];
return [@"Basic " stringByAppendingString:rawToken.encodedAsUtf8.encodedAsBase64];
}
@end

View File

@ -0,0 +1,22 @@
//
// CallServerRequests.h
// Signal
//
// Created by Frederic Jacobs on 31/07/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import <Foundation/Foundation.h>
#import "RPAPICall.h"
#import <CollapsingFutures.h>
@interface RPServerRequestsManager : NSObject
MacrosSingletonInterface
- (void)performRequest:(RPAPICall*)apiCall success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure;
- (TOCFuture*)futureForRequest:(RPAPICall*)apiCall;
@end

View File

@ -0,0 +1,96 @@
//
// CallServerRequests.m
// Signal
//
// Created by Frederic Jacobs on 31/07/14.
// Copyright (c) 2014 Open Whisper Systems. All rights reserved.
//
#import "HttpRequest.h"
#import "RPServerRequestsManager.h"
#import "Constraints.h"
#import "CryptoTools.h"
#import "DataUtil.h"
#import "Environment.h"
#import "HostNameEndPoint.h"
#import "SGNKeychainUtil.h"
#import "Util.h"
#import "AFHTTPSessionManager+SignalMethods.h"
@interface RPServerRequestsManager ()
@property (nonatomic, retain)AFHTTPSessionManager *operationManager;
@end
@implementation RPServerRequestsManager
MacrosSingletonImplemention
- (id)init{
self = [super init];
if (self) {
HostNameEndPoint *endpoint = Environment.getCurrent.masterServerSecureEndPoint.hostNameEndPoint;
NSURL *endPointURL = [NSURL URLWithString:[NSString stringWithFormat:@"https://%@:%hu", endpoint.hostname, endpoint.port]];
NSURLSessionConfiguration *sessionConf = NSURLSessionConfiguration.ephemeralSessionConfiguration;
self.operationManager = [[AFHTTPSessionManager alloc] initWithBaseURL:endPointURL sessionConfiguration:sessionConf];
self.operationManager.responseSerializer = [AFJSONResponseSerializer serializer];
self.operationManager.securityPolicy.allowInvalidCertificates = YES;
NSString *certPath = [NSBundle.mainBundle pathForResource:@"whisperReal" ofType:@"cer"];
NSData *certData = [NSData dataWithContentsOfFile:certPath];
SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData));
self.operationManager.securityPolicy.pinnedCertificates = @[(__bridge_transfer NSData *)SecCertificateCopyData(cert)];
self.operationManager.securityPolicy.SSLPinningMode = AFSSLPinningModeCertificate;
}
return self;
}
- (void)performRequest:(RPAPICall*)apiCall success:(void (^)(NSURLSessionDataTask *task, id responseObject))success failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure{
self.operationManager.requestSerializer = apiCall.requestSerializer;
self.operationManager.responseSerializer = apiCall.responseSerializer;
switch (apiCall.method) {
case HTTP_GET:
[self.operationManager GET:apiCall.endPoint parameters:apiCall.parameters success:success failure:failure];
break;
case HTTP_PUT:
[self.operationManager PUT:apiCall.endPoint parameters:apiCall.parameters success:success failure:failure];
break;
case HTTP_POST:
[self.operationManager POST:apiCall.endPoint parameters:apiCall.parameters success:success failure:failure];
break;
case HTTP_DELETE:
[self.operationManager DELETE:apiCall.endPoint parameters:apiCall.parameters success:success failure:failure];
break;
case SIGNAL_BUSY:
[self.operationManager BUSY:apiCall.endPoint parameters:apiCall.parameters success:success failure:failure];
break;
case SIGNAL_RING:
[self.operationManager RING:apiCall.endPoint parameters:apiCall.parameters success:success failure:failure];
break;
}
}
- (TOCFuture*)futureForRequest:(RPAPICall*)apiCall{
TOCFutureSource *requestFutureSource = [TOCFutureSource new];
[self performRequest:apiCall success:^(NSURLSessionDataTask *task, id responseObject) {
NSLog(@"ResponseObject: %@", responseObject);
[requestFutureSource trySetResult:task.response];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[requestFutureSource trySetFailure:error];
}];
return [requestFutureSource future];
}
@end

View File

@ -1,7 +1,6 @@
#import <Foundation/Foundation.h>
#import "BloomFilter.h"
#import "PhoneNumber.h"
#import "HttpResponse.h"
/**
*
@ -18,7 +17,7 @@
+(PhoneNumberDirectoryFilter*) phoneNumberDirectoryFilterDefault;
+(PhoneNumberDirectoryFilter*) phoneNumberDirectoryFilterWithBloomFilter:(BloomFilter*)bloomFilter
andExpirationDate:(NSDate*)expirationDate;
+(PhoneNumberDirectoryFilter*) phoneNumberDirectoryFilterFromHttpResponse:(HttpResponse*)response;
+(PhoneNumberDirectoryFilter*) phoneNumberDirectoryFilterFromURLResponse:(NSHTTPURLResponse*)response body:(NSData*)data;
-(bool) containsPhoneNumber:(PhoneNumber*)phoneNumber;
-(NSDate*) getExpirationDate;

View File

@ -32,18 +32,18 @@
return expirationDate;
}
+(PhoneNumberDirectoryFilter*) phoneNumberDirectoryFilterFromHttpResponse:(HttpResponse*)response {
+(PhoneNumberDirectoryFilter*) phoneNumberDirectoryFilterFromURLResponse:(NSHTTPURLResponse*)response body:(NSData*)data {
require(response != nil);
checkOperation(response.isOkResponse);
checkOperation(response.statusCode == 200);
NSString* hashCountHeader = response.getHeaders[HASH_COUNT_HEADER_KEY];
NSString* hashCountHeader = response.allHeaderFields[HASH_COUNT_HEADER_KEY];
checkOperation(hashCountHeader != nil);
int hashCountValue = [hashCountHeader intValue];
checkOperation(hashCountValue > 0);
NSData* responseBody = response.getOptionalBodyData;
NSData* responseBody = data;
checkOperation(responseBody.length > 0);
BloomFilter* bloomFilter = [BloomFilter bloomFilterWithHashCount:(NSUInteger)hashCountValue

View File

@ -3,6 +3,7 @@
#import "Environment.h"
#import "NotificationManifest.h"
#import "PreferencesUtil.h"
#import "RPServerRequestsManager.h"
#import "SignalUtil.h"
#import "ThreadManager.h"
#import "Util.h"
@ -47,7 +48,9 @@
}
-(void) scheduleUpdateAt:(NSDate*)date {
void(^doUpdate)(void) = ^{
[self update];
if (Environment.isRegistered) {
[self update];
}
};
[currentUpdateLifetime cancel];
@ -59,55 +62,28 @@
unlessCancelled:currentUpdateLifetime.token];
}
-(TOCFuture*) asyncQueryCurrentDirectory {
TOCUntilOperation startAwaitDirectoryOperation = ^(TOCCancelToken* untilCancelledToken) {
HttpRequest* directoryRequest = [HttpRequest httpRequestForPhoneNumberDirectoryFilter];
TOCFuture* futureDirectoryResponse = [HttpManager asyncOkResponseFromMasterServer:directoryRequest
unlessCancelled:untilCancelledToken
andErrorHandler:Environment.errorNoter];
return [futureDirectoryResponse thenTry:^(HttpResponse* response) {
return [PhoneNumberDirectoryFilter phoneNumberDirectoryFilterFromHttpResponse:response];
}];
};
return [TOCFuture futureFromUntilOperation:[TOCFuture operationTry:startAwaitDirectoryOperation]
withOperationTimeout:DIRECTORY_UPDATE_TIMEOUT_PERIOD
until:lifetimeToken];
}
-(PhoneNumberDirectoryFilter*) sameDirectoryWithRetryTimeout {
BloomFilter* filter = [phoneNumberDirectoryFilter bloomFilter];
NSDate* retryDate = [NSDate dateWithTimeInterval:DIRECTORY_UPDATE_RETRY_PERIOD
sinceDate:[NSDate date]];
return [PhoneNumberDirectoryFilter phoneNumberDirectoryFilterWithBloomFilter:filter
andExpirationDate:retryDate];
}
-(void) signalDirectoryQueryFailed:(id)failure {
NSString* desc = [NSString stringWithFormat:@"Failed to retrieve directory. Retrying in %f hours.",
DIRECTORY_UPDATE_RETRY_PERIOD/HOUR];
Environment.errorNoter(desc, failure, false);
}
-(TOCFuture*) asyncQueryCurrentDirectoryWithDefaultOnFail {
TOCFuture* futureDirectory = [self asyncQueryCurrentDirectory];
return [futureDirectory catchTry:^PhoneNumberDirectoryFilter*(id error) {
[self signalDirectoryQueryFailed:error];
return [self sameDirectoryWithRetryTimeout];
}];
}
-(void) update {
TOCFuture* eventualDirectory = [self asyncQueryCurrentDirectoryWithDefaultOnFail];
[eventualDirectory thenDo:^(PhoneNumberDirectoryFilter* directory) {
[[RPServerRequestsManager sharedInstance] performRequest:[RPAPICall fetchBloomFilter] success:^(NSURLSessionDataTask *task, NSData *responseObject) {
PhoneNumberDirectoryFilter *directory = [PhoneNumberDirectoryFilter phoneNumberDirectoryFilterFromURLResponse:(NSHTTPURLResponse*)task.response body:responseObject];
@synchronized(self) {
phoneNumberDirectoryFilter = directory;
}
[Environment.preferences setSavedPhoneNumberDirectory:directory];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_DIRECTORY_WAS_UPDATED object:nil];
[self scheduleUpdate];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSString* desc = [NSString stringWithFormat:@"Failed to retrieve directory. Retrying in %f hours.",
DIRECTORY_UPDATE_RETRY_PERIOD/HOUR];
Environment.errorNoter(desc, error, false);
BloomFilter* filter = [phoneNumberDirectoryFilter bloomFilter];
NSDate* retryDate = [NSDate dateWithTimeInterval:DIRECTORY_UPDATE_RETRY_PERIOD
sinceDate:[NSDate date]];
[PhoneNumberDirectoryFilter phoneNumberDirectoryFilterWithBloomFilter:filter
andExpirationDate:retryDate];
[[NSNotificationCenter defaultCenter] postNotificationName:NOTIFICATION_DIRECTORY_FAILED object:nil];
}];
}

View File

@ -14,7 +14,6 @@
@property (nonatomic, strong) IBOutlet SearchBarTitleView *searchBarTitleView;
@property (nonatomic, strong) IBOutlet UIView *notificationView;
@property (nonatomic, retain) UIRefreshControl *refreshControl;
@property (nonatomic) NSTimer *refreshTimer;
- (IBAction)notificationViewTapped:(id)sender;
- (void)showNotificationForNewWhisperUsers:(NSArray *)users;

View File

@ -34,6 +34,7 @@ static NSString *const CONTACT_BROWSE_TABLE_CELL_IDENTIFIER = @"ContactTableView
- (void)viewDidLoad {
[super viewDidLoad];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contactsDidRefresh) name:NOTIFICATION_DIRECTORY_WAS_UPDATED object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(contactRefreshFailed) name:NOTIFICATION_DIRECTORY_FAILED object:nil];
UIRefreshControl *refreshControl = [[UIRefreshControl alloc]
init];
[refreshControl addTarget:self action:@selector(refreshContacts) forControlEvents:UIControlEventValueChanged];
@ -252,17 +253,15 @@ static NSString *const CONTACT_BROWSE_TABLE_CELL_IDENTIFIER = @"ContactTableView
- (void)refreshContacts{
[Environment.getCurrent.phoneDirectoryManager forceUpdate];
self.refreshTimer = [NSTimer scheduledTimerWithTimeInterval:REFRESH_TIMEOUT target:self selector:@selector(contactRefreshDidTimeout) userInfo:nil repeats:NO];
}
- (void)contactRefreshDidTimeout{
- (void)contactRefreshFailed{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:TIMEOUT message:TIMEOUT_CONTACTS_DETAIL delegate:nil cancelButtonTitle:NSLocalizedString(@"OK", @"") otherButtonTitles:nil];
[alert show];
[self.refreshControl endRefreshing];
}
- (void)contactsDidRefresh{
[self.refreshTimer invalidate];
[self.refreshControl endRefreshing];
}

View File

@ -1,3 +1,4 @@
#import "RPServerRequestsManager.h"
#import "Environment.h"
#import "HttpManager.h"
#import "LocalizableText.h"
@ -8,6 +9,7 @@
#import "PreferencesUtil.h"
#import "PushManager.h"
#import "RegisterViewController.h"
#import "RPServerRequestsManager.h"
#import "SignalUtil.h"
#import "SGNKeychainUtil.h"
#import "ThreadManager.h"
@ -114,32 +116,6 @@
[self presentViewController:countryCodeController animated:YES completion:nil];
}
-(TOCFuture*) asyncRegister:(PhoneNumber*)phoneNumber untilCancelled:(TOCCancelToken*)cancelToken {
[SGNKeychainUtil generateServerAuthPassword];
[SGNKeychainUtil setLocalNumberTo:phoneNumber];
TOCUntilOperation regStarter = ^TOCFuture *(TOCCancelToken* internalUntilCancelledToken) {
HttpRequest *registerRequest = [HttpRequest httpRequestToStartRegistrationOfPhoneNumber];
return [HttpManager asyncOkResponseFromMasterServer:registerRequest
unlessCancelled:internalUntilCancelledToken
andErrorHandler:Environment.errorNoter];
};
TOCFuture *futurePhoneRegistrationStarted = [TOCFuture futureFromUntilOperation:[TOCFuture operationTry:regStarter]
withOperationTimeout:SERVER_TIMEOUT_SECONDS
until:cancelToken];
return [futurePhoneRegistrationStarted thenTry:^(id _) {
[self showViewNumber:CHALLENGE_VIEW_NUMBER];
[self.challengeNumberLabel setText:[phoneNumber description]];
[_registerCancelButton removeFromSuperview];
[self startVoiceVerificationCountdownTimer];
self->futureChallengeAcceptedSource = [TOCFutureSource new];
return futureChallengeAcceptedSource.future;
}];
}
- (void)registerPhoneNumberTapped {
NSString *phoneNumber = [NSString stringWithFormat:@"%@%@", _countryCodeLabel.text, _phoneNumberTextField.text];
PhoneNumber* localNumber = [PhoneNumber tryParsePhoneNumberFromUserSpecifiedText:phoneNumber];
@ -147,16 +123,21 @@
[_phoneNumberTextField resignFirstResponder];
TOCFuture* futureFinished = [self asyncRegister:localNumber untilCancelled:life.token];
[_registerActivityIndicator startAnimating];
_registerButton.enabled = NO;
[futureFinished catchDo:^(id error) {
NSError *err = ((NSError*)error);
[SGNKeychainUtil setLocalNumberTo:localNumber];
[[RPServerRequestsManager sharedInstance]performRequest:[RPAPICall requestVerificationCode] success:^(NSURLSessionDataTask *task, id responseObject) {
[self showViewNumber:CHALLENGE_VIEW_NUMBER];
[self.challengeNumberLabel setText:[phoneNumber description]];
[_registerCancelButton removeFromSuperview];
[self startVoiceVerificationCountdownTimer];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[_registerActivityIndicator stopAnimating];
_registerButton.enabled = YES;
DDLogError(@"Registration failed with information %@", err.description);
DDLogError(@"Registration failed with information %@", error.description);
UIAlertView *registrationErrorAV = [[UIAlertView alloc]initWithTitle:REGISTER_ERROR_ALERT_VIEW_TITLE message:REGISTER_ERROR_ALERT_VIEW_BODY delegate:nil cancelButtonTitle:REGISTER_ERROR_ALERT_VIEW_DISMISS otherButtonTitles:nil, nil];
@ -173,22 +154,30 @@
_challengeButton.enabled = NO;
[_challengeActivityIndicator startAnimating];
HttpRequest *verifyRequest = [HttpRequest httpRequestToVerifyAccessToPhoneNumberWithChallenge:_challengeTextField.text];
TOCFuture *futureDone = [HttpManager asyncOkResponseFromMasterServer:verifyRequest
unlessCancelled:nil
andErrorHandler:Environment.errorNoter];
[futureDone catchDo:^(id error) {
[[RPServerRequestsManager sharedInstance] performRequest:[RPAPICall verifyVerificationCode:_challengeTextField.text] success:^(NSURLSessionDataTask *task, id responseObject) {
[PushManager.sharedManager registrationWithSuccess:^{
[futureChallengeAcceptedSource trySetResult:@YES];
[Environment setRegistered:YES];
[registered trySetResult:@YES];
[Environment.getCurrent.phoneDirectoryManager forceUpdate];
[self dismissView];
} failure:^{
_challengeButton.enabled = YES;
[_challengeActivityIndicator stopAnimating];
}];
} failure:^(NSURLSessionDataTask *task, NSError *error) {
NSString *alertTitle = NSLocalizedString(@"REGISTRATION_ERROR", @"");
if ([error isKindOfClass:HttpResponse.class]) {
HttpResponse* badResponse = error;
if (badResponse.getStatusCode == 401) {
NSHTTPURLResponse* badResponse = (NSHTTPURLResponse*)task.response;
if (badResponse.statusCode == 401) {
SignalAlertView(alertTitle, REGISTER_CHALLENGE_ALERT_VIEW_BODY);
} else if (badResponse.getStatusCode == 401){
} else if (badResponse.statusCode == 401){
SignalAlertView(alertTitle, NSLocalizedString(@"REGISTER_RATE_LIMITING_BODY", @""));
} else {
NSString *alertBodyString = [NSString stringWithFormat:@"%@ %lu", NSLocalizedString(@"SERVER_CODE", @""),(unsigned long)badResponse.getStatusCode];
NSString *alertBodyString = [NSString stringWithFormat:@"%@ %lu", NSLocalizedString(@"SERVER_CODE", @""),(unsigned long)badResponse.statusCode];
SignalAlertView (alertTitle, alertBodyString);
}
} else{
@ -199,22 +188,6 @@
_challengeButton.enabled = YES;
[_challengeActivityIndicator stopAnimating];
}];
[futureDone thenDo:^(id result) {
[futureChallengeAcceptedSource trySetResult:@YES];
}];
[futureChallengeAcceptedSource.future thenDo:^(id value) {
[PushManager.sharedManager registrationWithSuccess:^{
[Environment setRegistered:YES];
[registered trySetResult:@YES];
[Environment.getCurrent.phoneDirectoryManager forceUpdate];
[self dismissView];
} failure:^{
_challengeButton.enabled = YES;
[_challengeActivityIndicator stopAnimating];
}];
}];
}
- (void)showViewNumber:(NSInteger)viewNumber {
@ -275,29 +248,17 @@
- (void) initiateVoiceVerification{
[self stopVoiceVerificationCountdownTimer];
TOCUntilOperation callStarter = ^TOCFuture *(TOCCancelToken* internalUntilCancelledToken) {
HttpRequest* voiceVerifyReq = [HttpRequest httpRequestToStartRegistrationOfPhoneNumberWithVoice];
[self.voiceChallengeTextLabel setText:NSLocalizedString(@"REGISTER_CALL_CALLING", @"")];
return [HttpManager asyncOkResponseFromMasterServer:voiceVerifyReq
unlessCancelled:internalUntilCancelledToken
andErrorHandler:Environment.errorNoter];
};
TOCFuture *futureVoiceVerificationStarted = [TOCFuture futureFromUntilOperation:[TOCFuture operationTry:callStarter]
withOperationTimeout:SERVER_TIMEOUT_SECONDS
until:life.token];
[futureVoiceVerificationStarted catchDo:^(id errorId) {
HttpResponse* error = (HttpResponse*)errorId;
[self.voiceChallengeTextLabel setText:error.getStatusText];
}];
[self.voiceChallengeTextLabel setText:NSLocalizedString(@"REGISTER_CALL_CALLING", @"")];
[futureVoiceVerificationStarted finallyTry:^(id _id) {
[[RPServerRequestsManager sharedInstance] performRequest:[RPAPICall requestVerificationCodeWithVoice] success:^(NSURLSessionDataTask *task, id responseObject) {
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, VOICE_VERIFICATION_COOLDOWN_SECONDS * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
[self.voiceChallengeTextLabel setText:NSLocalizedString(@"REGISTER_CALL_RECALL", @"")];
});
return _id;
} failure:^(NSURLSessionDataTask *task, NSError *error) {
[self.voiceChallengeTextLabel setText:error.description];
}];
}