diff --git a/README.md b/README.md index eec308e7a..402cd7b72 100644 --- a/README.md +++ b/README.md @@ -4,15 +4,17 @@ An iOS client library for [ably.io](https://www.ably.io), the realtime messaging service, written in Objective-C. -## Installation +## CocoaPod Installation +add pod ably to your Podfile. While ably-ios is in development, use this line instead: +* pod "ably", :git => 'https://github.com/thevixac/ably-ios.git', :commit => 'be670f5e6c3' + +## Manual Installation * git clone https://github.com/ably/ably-ios * drag the directory ably-ios/ably-ios into your project as a group * git clone https://github.com/square/SocketRocket.git * drag the directory SocketRocket/SocketRocket into your project as a group - - ## Using the Realtime API ### Connection @@ -106,14 +108,10 @@ The library works on iOS8, and uses [SocketRocket](https://github.com/square/Soc The following features are not implemented yet: * msgpack transportation -* 256 cryptography The following features are do not have sufficient test coverage: -* 128 cryptography * app stats -* capability -* token auth ## Support and feedback diff --git a/ably-ios/ARTAuth.h b/ably-ios/ARTAuth.h index b088192f5..79135b11b 100644 --- a/ably-ios/ARTAuth.h +++ b/ably-ios/ARTAuth.h @@ -13,25 +13,25 @@ @class ARTRest; -@interface ARTAuthToken : NSObject +@interface ARTTokenDetails : NSObject -@property (readonly, strong, nonatomic) NSString *id; +@property (readonly, strong, nonatomic) NSString *token; @property (readonly, assign, nonatomic) int64_t expires; -@property (readonly, assign, nonatomic) int64_t issuedAt; +@property (readonly, assign, nonatomic) int64_t issued; @property (readonly, strong, nonatomic) NSString *capability; @property (readonly, strong, nonatomic) NSString *clientId; - (instancetype)init UNAVAILABLE_ATTRIBUTE; -- (instancetype)initWithId:(NSString *)id expires:(int64_t)expires issuedAt:(int64_t)issuedAt capability:(NSString *)capability clientId:(NSString *)clientId; +- (instancetype)initWithId:(NSString *)id expires:(int64_t)expires issued:(int64_t)issued capability:(NSString *)capability clientId:(NSString *)clientId; -+ (instancetype)authTokenWithId:(NSString *)id expires:(int64_t)expires issuedAt:(int64_t)issuedAt capability:(NSString *)capability clientId:(NSString *)clientId; ++ (instancetype)authTokenWithId:(NSString *)id expires:(int64_t)expires issued:(int64_t)issued capability:(NSString *)capability clientId:(NSString *)clientId; @end @interface ARTAuthTokenParams : NSObject -@property (readonly, strong, nonatomic) NSString *id; +@property (readonly, strong, nonatomic) NSString *keyName; @property (readonly, assign, nonatomic) int64_t ttl; @property (readonly, strong, nonatomic) NSString *capability; @property (readonly, strong, nonatomic) NSString *clientId; @@ -39,16 +39,18 @@ @property (readonly, strong, nonatomic) NSString *nonce; @property (readonly, strong, nonatomic) NSString *mac; + - (instancetype)init UNAVAILABLE_ATTRIBUTE; - (instancetype)initWithId:(NSString *)id ttl:(int64_t)ttl capability:(NSString *)capability clientId:(NSString *)clientId timestamp:(int64_t)timestamp nonce:(NSString *)nonce mac:(NSString *)mac; + (instancetype)authTokenParamsWithId:(NSString *)id ttl:(int64_t)ttl capability:(NSString *)capability clientId:(NSString *)clientId timestamp:(int64_t)timestamp nonce:(NSString *)nonce mac:(NSString *)mac; +-(NSDictionary *) asDictionary; @end -typedef id(^ARTAuthCb)(void(^continuation)(ARTAuthToken *)); -typedef id(^ARTSignedTokenRequestCb)(ARTAuthTokenParams *tokenParams, void(^continuation)(NSString *)); +typedef id(^ARTAuthCb)(void(^continuation)(ARTStatus,ARTTokenDetails *)); +typedef id(^ARTSignedTokenRequestCb)(ARTAuthTokenParams *, void(^continuation)(ARTAuthTokenParams *)); typedef NS_ENUM(NSUInteger, ARTAuthMethod) { ARTAuthMethodBasic, ARTAuthMethodToken @@ -59,12 +61,15 @@ typedef NS_ENUM(NSUInteger, ARTAuthMethod) { @property (readwrite, strong, nonatomic) ARTAuthCb authCallback; @property (readwrite, strong, nonatomic) ARTSignedTokenRequestCb signedTokenRequestCallback; @property (readwrite, strong, nonatomic) NSURL *authUrl; -@property (readwrite, strong, nonatomic) NSString *keyId; -@property (readwrite, strong, nonatomic) NSString *keyValue; -@property (readwrite, strong, nonatomic) NSString *authToken; +@property (readwrite, strong, nonatomic) NSString *keyName; +@property (readwrite, strong, nonatomic) NSString *keySecret; +@property (readwrite, strong, nonatomic) NSString *token; +@property (readwrite, strong, nonatomic) NSString *capability; @property (readwrite, strong, nonatomic) NSDictionary *authHeaders; @property (readwrite, strong, nonatomic) NSString *clientId; @property (readwrite, assign, nonatomic) BOOL queryTime; +@property (readwrite, assign, nonatomic) BOOL useTokenAuth; + - (instancetype)init; - (instancetype)initWithKey:(NSString *)key; @@ -80,9 +85,12 @@ typedef NS_ENUM(NSUInteger, ARTAuthMethod) { - (instancetype)initWithRest:(ARTRest *)rest options:(ARTAuthOptions *)options; -- (id)authHeaders:(id(^)(NSDictionary *))cb; + +- (ARTAuthMethod) getAuthMethod; +- (id)authHeadersUseBasic:(BOOL)useBasic cb:(id(^)(NSDictionary *))cb; - (id)authParams:(id(^)(NSDictionary *))cb; -- (id)authToken:(id(^)(ARTAuthToken *))cb; -- (id)authTokenForceReauth:(BOOL)force cb:(id(^)(ARTAuthToken *))cb; +- (id)authToken:(id(^)(ARTTokenDetails *))cb; +- (id)authTokenForceReauth:(BOOL)force cb:(id(^)(ARTTokenDetails *))cb; + @end \ No newline at end of file diff --git a/ably-ios/ARTAuth.m b/ably-ios/ARTAuth.m index ee00dc48f..07a0567cf 100644 --- a/ably-ios/ARTAuth.m +++ b/ably-ios/ARTAuth.m @@ -12,71 +12,73 @@ #include #import "ARTRest.h" +#import "ARTPayload.h" +#import "ARTLog.h" + @interface ARTAuthTokenCancellable : NSObject @property (readwrite, assign, nonatomic) BOOL isCancelled; -@property (readwrite, strong, nonatomic) id(^cb)(ARTAuthToken *token); +@property (readwrite, strong, nonatomic) id(^cb)(ARTTokenDetails*token); @property (readwrite, strong, nonatomic) id cancellable; - (instancetype)init UNAVAILABLE_ATTRIBUTE; -- (instancetype)initWithCb:(id(^)(ARTAuthToken *token))cb; +- (instancetype)initWithCb:(id(^)(ARTTokenDetails*token))cb; -- (void)onAuthToken:(ARTAuthToken *)token; +- (void)onAuthToken:(ARTTokenDetails *)token; @end @interface ARTAuth () @property (readonly, weak, nonatomic) ARTRest *rest; -@property (readwrite, strong, nonatomic) ARTAuthToken *authToken; -@property (readonly, assign, nonatomic) ARTAuthMethod authMethod; +@property (readwrite, strong, nonatomic) ARTTokenDetails *token; +@property (assign, nonatomic) ARTAuthMethod authMethod; @property (readonly, strong, nonatomic) NSString *basicCredentials; -@property (readonly, strong, nonatomic) NSString *keyId; -@property (readonly, strong, nonatomic) NSString *keyValue; +@property (readonly, strong, nonatomic) NSString *keyName; +@property (readonly, strong, nonatomic) NSString *keySecret; @property (readonly, strong, nonatomic) ARTAuthCb authTokenCb; @property (readwrite, strong, nonatomic) NSMutableArray *tokenCbs; @property (readwrite, strong, nonatomic) id tokenRequest; - -+ (NSString *)random; -/* + (ARTSignedTokenRequestCb)defaultSignedTokenRequestCallback:(ARTAuthOptions *)authOptions rest:(ARTRest *)rest; -+ (NSString *)hmacForData:(NSData *)data key:(NSData *)key; -*/ ++ (NSString *)random; @end -@implementation ARTAuthToken +@implementation ARTTokenDetails -- (instancetype)initWithId:(NSString *)id expires:(int64_t)expires issuedAt:(int64_t)issuedAt capability:(NSString *)capability clientId:(NSString *)clientId { +- (instancetype)initWithId:(NSString *)token expires:(int64_t)expires issued:(int64_t)issued capability:(NSString *)capability clientId:(NSString *)clientId { self = [super init]; if (self) { - _id = id; + + NSData * tokenData = [token dataUsingEncoding:NSUTF8StringEncoding]; + _token = [ARTBase64PayloadEncoder toBase64:tokenData]; _expires = expires; - _issuedAt = issuedAt; + _issued = issued; _capability = capability; _clientId = clientId; } return self; } -+ (instancetype)authTokenWithId:(NSString *)id expires:(int64_t)expires issuedAt:(int64_t)issuedAt capability:(NSString *)capability clientId:(NSString *)clientId { - return [[ARTAuthToken alloc] initWithId:id expires:expires issuedAt:issuedAt capability:capability clientId:clientId]; ++ (instancetype)authTokenWithId:(NSString *)id expires:(int64_t)expires issued:(int64_t)issued capability:(NSString *)capability clientId:(NSString *)clientId { + return [[ARTTokenDetails alloc] initWithId:id expires:expires issued:issued capability:capability clientId:clientId]; } @end @implementation ARTAuthTokenParams -- (instancetype)initWithId:(NSString *)id ttl:(int64_t)ttl capability:(NSString *)capability clientId:(NSString *)clientId timestamp:(int64_t)timestamp nonce:(NSString *)nonce mac:(NSString *)mac { +- (instancetype)initWithId:(NSString *)keyName ttl:(int64_t)ttl capability:(NSString *)capability clientId:(NSString *)clientId timestamp:(int64_t)timestamp nonce:(NSString *)nonce mac:(NSString *)mac { self = [super init]; if (self) { - _id = id; + _keyName = keyName; _ttl = ttl; _capability = capability; _clientId = clientId; _timestamp = timestamp; _nonce = nonce; _mac = mac; + } return self; } @@ -85,6 +87,19 @@ + (instancetype)authTokenParamsWithId:(NSString *)id ttl:(int64_t)ttl capability return [[ARTAuthTokenParams alloc] initWithId:id ttl:ttl capability:capability clientId:clientId timestamp:timestamp nonce:nonce mac:mac]; } + +-(NSDictionary *) asDictionary { + NSMutableDictionary *reqObj = [NSMutableDictionary dictionary]; + reqObj[@"keyName"] = self.keyName ? self.keyName : @""; + reqObj[@"capability"] = self.capability ? self.capability : @""; + reqObj[@"ttl"] = [NSNumber numberWithLongLong:self.ttl]; + reqObj[@"clientId"] = self.clientId ? self.clientId : @""; + reqObj[@"nonce"] = self.nonce ? self.nonce : @""; + reqObj[@"timestamp"] = [NSNumber numberWithLongLong:self.timestamp]; + reqObj[@"mac"] = self.mac ? self.mac : @""; + return reqObj; +} + @end @implementation ARTAuthOptions @@ -94,11 +109,14 @@ - (instancetype)init { if (self) { _authCallback = nil; _authUrl = nil; - _keyId = nil; - _keyValue = nil; - _authToken = nil; + _keyName = nil; + _keySecret = nil; + _token = nil; _authHeaders = nil; _clientId = nil; + _capability = nil; + _useTokenAuth = false; + _queryTime = true; } return self; } @@ -108,9 +126,8 @@ - (instancetype)initWithKey:(NSString *)key { if (self) { NSArray *keyBits = [key componentsSeparatedByString:@":"]; NSAssert(keyBits.count == 2, @"Invalid key"); - _keyId = keyBits[0]; - _keyValue = keyBits[1]; - + _keyName = keyBits[0]; + _keySecret = keyBits[1]; } return self; } @@ -126,12 +143,16 @@ + (instancetype)optionsWithKey:(NSString *)key { - (instancetype)clone { ARTAuthOptions *clone = [[ARTAuthOptions alloc] init]; clone.authCallback = self.authCallback; + clone.signedTokenRequestCallback = self.signedTokenRequestCallback; clone.authUrl = self.authUrl; - clone.keyId = self.keyId; - clone.keyValue = self.keyValue; - clone.authToken = self.authToken; + clone.keyName = self.keyName; + clone.keySecret = self.keySecret; + clone.token = self.token; + clone.capability = self.capability; clone.authHeaders = self.authHeaders; clone.clientId = self.clientId; + clone.queryTime = self.queryTime; + clone.useTokenAuth =self.useTokenAuth; return clone; } @@ -139,7 +160,7 @@ - (instancetype)clone { @implementation ARTAuthTokenCancellable -- (instancetype)initWithCb:(id(^)(ARTAuthToken *token))cb { +- (instancetype)initWithCb:(id(^)(ARTTokenDetails *token))cb { self = [super init]; if (self) { _cb = cb; @@ -147,7 +168,7 @@ - (instancetype)initWithCb:(id(^)(ARTAuthToken *token))cb { return self; } -- (void)onAuthToken:(ARTAuthToken *)token { +- (void)onAuthToken:(ARTTokenDetails *)token { self.cancellable = self.cb(token); } @@ -162,71 +183,105 @@ - (void)cancel { @implementation ARTAuth +-(bool) shouldUseTokenAuth:(ARTAuthOptions *) options +{ + return options.useTokenAuth || + options.clientId || + options.token || + options.authUrl || + options.authCallback; +} + - (instancetype)initWithRest:(ARTRest *)rest options:(ARTAuthOptions *)options { self = [super init]; if (self) { _rest = rest; - _authToken = nil; + _token = nil; _basicCredentials = nil; _authMethod = ARTAuthMethodBasic; _tokenCbs = nil; _tokenRequest = nil; - if (nil != options.keyValue && nil == options.clientId) { - _authMethod = ARTAuthMethodBasic; - _basicCredentials = [NSString stringWithFormat:@"Basic %@", [[[NSString stringWithFormat:@"%@:%@", options.keyId, options.keyValue] dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]]; - _keyId = options.keyId; - _keyValue = options.keyValue; - } else { - _authMethod = ARTAuthMethodToken; + //create BasicAuth, which will either be used directly, + //or only used to set up TokenAuth + if (options.keyName != nil) { + [ARTLog debug:@"ARTAuth: setting up auth method Basic"]; + + _basicCredentials = [NSString stringWithFormat:@"Basic %@", + [[[NSString stringWithFormat:@"%@:%@", options.keyName, options.keySecret] dataUsingEncoding:NSUTF8StringEncoding] base64EncodedStringWithOptions:0]]; + _keyName = options.keyName; + _keySecret = options.keySecret; + } + else { + [ARTLog warn:@"ARTAuth Error: cannot set up basic auth without a valid ArtAuthOptions key. "]; + } + if([self shouldUseTokenAuth:options]) { + _authMethod= ARTAuthMethodToken; + [ARTLog debug:@"ARTAuth: setting up auth method Token"]; _tokenCbs = [NSMutableArray array]; - if (options.authToken) { - _authToken = [[ARTAuthToken alloc] initWithId:options.authToken expires:0 issuedAt:0 capability:nil clientId:nil]; + if (options.token) { + [ARTLog debug:[NSString stringWithFormat:@"ARTAuth:using provided authToken %@", options.token]]; + _token = [[ARTTokenDetails alloc] initWithId:options.token expires:0 issued:0 capability:options.capability clientId:options.clientId]; } else if (options.authCallback) { + [ARTLog debug:@"ARTAuth: using provided authCallback"]; _authTokenCb = options.authCallback; } else { - NSLog(@"TODO handle signtokenrequest callback"); - /* TODO - ARTSignedTokenRequestCb strCb = options.signedTokenRequestCallback ? options.signedTokenRequestCallback : [ARTAuth defaultSignedTokenRequestCallback]; - _authTokenCb = ^(void(^cb)(ARTAuthToken *)){ + [ARTLog debug:@"ARTAuth: signed token request."]; + ARTSignedTokenRequestCb strCb = (options.signedTokenRequestCallback ? options.signedTokenRequestCallback : [ARTAuth defaultSignedTokenRequestCallback:options rest:rest]); + __weak ARTRest * weakRest = self.rest; + _authTokenCb = ^(void(^cb)(ARTStatus,ARTTokenDetails *)) { + ARTIndirectCancellable *ic = [[ARTIndirectCancellable alloc] init]; - id c = strCb(^(NSString *str) { - NSString *url = [NSString stringWithFormat:@"%@/keys/%@/requestToken"]; + + id c = strCb(nil,^( ARTAuthTokenParams *params) { + [ARTLog debug:[NSString stringWithFormat:@"ARTAuth tokenRequest strCb got %@", [params asDictionary]]]; + ARTRest * r = weakRest; + if(r) { + [r token:params tokenCb:^(ARTStatus status, ARTTokenDetails * token) { + cb(status, token); + }]; + } + else { + [ARTLog debug:@"ARTAuth has no ARTRest"]; + } }); ic.cancellable = c; return ic; }; - */ } + } else { + [ARTLog debug:@"ARTAuth is using Basic Authentication only"]; } } return self; } +- (ARTAuthMethod) getAuthMethod { + return self.authMethod; +} +- (id)authHeadersUseBasic:(BOOL)useBasic cb:(id(^)(NSDictionary *))cb { -- (id)authHeaders:(id(^)(NSDictionary *))cb { - - switch (self.authMethod) { - case ARTAuthMethodBasic: - return cb(@{@"Authorization": self.basicCredentials}); - return nil; - case ARTAuthMethodToken: - return [self authToken:^(ARTAuthToken *token) { - return cb(@{@"Authorization": [NSString stringWithFormat:@"Bearer %@", token.id]}); - }]; - default: - NSAssert(NO, @"Invalid auth method"); - return nil; + if(useBasic || self.authMethod == ARTAuthMethodBasic) { + return cb(@{@"Authorization": self.basicCredentials}); + } + else if(self.authMethod == ARTAuthMethodToken) { + return [self authToken:^(ARTTokenDetails *token) { + return cb(@{@"Authorization": [NSString stringWithFormat:@"Bearer %@", token.token]}); + }]; + } + else { + NSAssert(NO, @"Invalid auth method"); + return nil; } } - (id)authParams:(id(^)(NSDictionary *))cb { switch (self.authMethod) { case ARTAuthMethodBasic: - return cb(@{@"key_id":self.keyId, @"key_value":self.keyValue}); + return cb(@{@"key_id":self.keyName, @"key_value":self.keySecret}); case ARTAuthMethodToken: - return [self authToken:^(ARTAuthToken *token) { - return cb(@{@"access_token": token.id}); + return [self authToken:^(ARTTokenDetails *token) { + return cb(@{@"access_token:": token.token}); }]; default: NSAssert(NO, @"Invalid auth method"); @@ -234,25 +289,28 @@ - (instancetype)initWithRest:(ARTRest *)rest options:(ARTAuthOptions *)options { } } -- (id)authToken:(id(^)(ARTAuthToken *))cb { +- (id)authToken:(id(^)(ARTTokenDetails *))cb { return [self authTokenForceReauth:NO cb:cb]; } -- (id)authTokenForceReauth:(BOOL)force cb:(id(^)(ARTAuthToken *))cb { - if (self.authToken) { - if (0 == self.authToken.expires || self.authToken.expires > [[NSDate date] timeIntervalSince1970]) { +- (id)authTokenForceReauth:(BOOL)force cb:(id(^)(ARTTokenDetails *))cb { + if (self.token) { + if (0 == self.token.expires || self.token.expires > [[NSDate date] timeIntervalSince1970]) { if (!force) { - return cb(self.authToken); + return cb(self.token); } } - self.authToken = nil; + self.token = nil; } ARTAuthTokenCancellable *c = [[ARTAuthTokenCancellable alloc] initWithCb:cb]; [self.tokenCbs addObject:c]; if (!self.tokenRequest) { - self.tokenRequest = self.authTokenCb(^(ARTAuthToken *token) { + self.tokenRequest = self.authTokenCb(^(ARTStatus status, ARTTokenDetails *token) { + if(status != ARTStatusOk) { + [ARTLog error:@"ARTAuth: error fetching token"]; + } self.tokenRequest = nil; NSMutableArray *cbs = self.tokenCbs; self.tokenCbs = [NSMutableArray array]; @@ -271,49 +329,41 @@ + (NSString *)random { NSUInteger r2 = arc4random_uniform(100000000); return [NSString stringWithFormat:@"%08lu%08lu", (long)r1, (long)r2]; } -/* TODO + + (ARTSignedTokenRequestCb)defaultSignedTokenRequestCallback:(ARTAuthOptions *)authOptions rest:(ARTRest *)rest { - NSString *keyId = authOptions.keyId; - NSString *keyValue = authOptions.keyValue; + + NSString *keyName = authOptions.keyName; + NSString *keySecret = authOptions.keySecret; BOOL queryTime = authOptions.queryTime; - + NSString * clientId = authOptions.clientId; + NSString *capability =authOptions.capability; __weak ARTRest *weakRest = rest; - NSAssert(keyId && keyValue, @"keyId and keyValue must be set when using the default token auth"); + NSAssert(keyName && keySecret, @"keyName and keySecret must be set when using the default token auth"); - return ^(ARTAuthTokenParams *params, void(^cb)(NSString *)) { - if (params.id && ![params.id isEqualToString:keyId]) { - NSLog(@"Params id is not equal to authOptions id"); - cb(nil); - return; - } + return ^id(ARTAuthTokenParams *params, void(^cb)(ARTAuthTokenParams *)) { - NSMutableDictionary *reqObj = [NSMutableDictionary dictionary]; - reqObj[@"id"] = keyId; - NSString *ttlText = @""; - if (params.ttl) { - ttlText = [NSString stringWithFormat:@"%lld", params.ttl]; - reqObj[@"ttl"] = [NSNumber numberWithLongLong:params.ttl]; + if (params.keyName && ![params.keyName isEqualToString:keyName]) { + [ARTLog error:[NSString stringWithFormat:@"ARTAuth params keyname %@ is not equal to authOptions id %@", params.keyName, keyName]]; + cb(nil); + return nil; } - NSString *capability = params.capability ? params.capability : @""; - reqObj[@"capability"] = capability; - - NSString *clientId = params.clientId ? params.clientId : @""; - reqObj[@"client_id"] = clientId; + int64_t ttl =params.ttl ? params.ttl : 3600000; + NSString *ttlText = [NSString stringWithFormat:@"%lld", ttl]; NSString *nonce = params.nonce ? params.nonce : [ARTAuth random]; - reqObj[@"nonce"] = nonce; void (^timeCb)(void(^)(int64_t)) = nil; if (!params.timestamp) { if (queryTime) { + [ARTLog debug:@"ARTAuth: query time is being used"]; timeCb = ^(void(^cb)(int64_t)) { ARTRest *strongRest = weakRest; if (strongRest) { [strongRest time:^(ARTStatus status, NSDate *time) { if (status == ARTStatusOk) { - cb((int64_t)([time timeIntervalSince1970] * 1000.0)); + cb((int64_t)([time timeIntervalSince1970] *1000.0)); } else { cb(0); } @@ -324,7 +374,8 @@ + (ARTSignedTokenRequestCb)defaultSignedTokenRequestCallback:(ARTAuthOptions *)a }; } else { timeCb = ^(void(^cb)(int64_t)) { - cb((int64_t)([[NSDate date] timeIntervalSince1970] * 1000.0)); + [ARTLog debug:@"ARTAuth: client time is being used"]; + cb((int64_t)([[NSDate date] timeIntervalSince1970] *1000.0 )); }; } } else { @@ -339,13 +390,11 @@ + (ARTSignedTokenRequestCb)defaultSignedTokenRequestCallback:(ARTAuthOptions *)a return; } - NSString *signText = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%lld\n%@\n", keyId, ttlText, capability, clientId, timestamp, nonce]; - - reqObj[@"mac"] = params.mac ? params.mac : [ARTAuth hmacForData:[signText dataUsingEncoding:NSUTF8StringEncoding] key:[keyValue dataUsingEncoding:NSUTF8StringEncoding]]; - - NSString *signedReq = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:reqObj options:0 error:nil] encoding:NSUTF8StringEncoding]; - - cb(signedReq); + NSString *signText = [NSString stringWithFormat:@"%@\n%@\n%@\n%@\n%lld\n%@\n", keyName, ttlText, capability, clientId, timestamp, nonce]; + NSString * mac =params.mac ? params.mac : [ARTAuth hmacForData:[signText dataUsingEncoding:NSUTF8StringEncoding] key:[keySecret dataUsingEncoding:NSUTF8StringEncoding]]; + + ARTAuthTokenParams * p = [[ARTAuthTokenParams alloc] initWithId:keyName ttl:ttl capability:capability clientId:clientId timestamp:timestamp nonce:nonce mac:mac]; + cb(p); }); return ic; @@ -361,11 +410,12 @@ + (NSString *)hmacForData:(NSData *)data key:(NSData *)key { unsigned char hmac[CC_SHA256_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA256, cKey, keyLen, cData, dataLen, hmac); - NSData *mac = [[NSData alloc] initWithBytes:hmac length:sizeof(hmac)]; - - return [mac ablyBase64Encode]; + NSString * str = [ARTBase64PayloadEncoder toBase64:mac]; + return str; } - */ + + + @end diff --git a/ably-ios/ARTCrypto.h b/ably-ios/ARTCrypto.h index 7d33665b3..7e063bf7c 100644 --- a/ably-ios/ARTCrypto.h +++ b/ably-ios/ARTCrypto.h @@ -48,6 +48,8 @@ - (ARTStatus)encrypt:(NSData *)plaintext output:(NSData **)output; - (ARTStatus)decrypt:(NSData *)ciphertext output:(NSData **)output; - (NSString *)cipherName; +- (size_t) keyLength; + @end diff --git a/ably-ios/ARTCrypto.m b/ably-ios/ARTCrypto.m index cc295136e..2507eebbf 100644 --- a/ably-ios/ARTCrypto.m +++ b/ably-ios/ARTCrypto.m @@ -10,6 +10,8 @@ #import +#import "ARTLog.h" + @interface ARTCipherParams () - (BOOL)ccAlgorithm:(CCAlgorithm *)algorithm; @@ -86,6 +88,7 @@ + (instancetype)cipherParamsWithAlgorithm:(NSString *)algorithm keySpec:(ARTSecr - (BOOL)ccAlgorithm:(CCAlgorithm *)algorithm { if (NSOrderedSame == [self.algorithm compare:@"AES" options:NSCaseInsensitiveSearch]) { if ([self.ivSpec.iv length] != 16) { + [ARTLog error:[NSString stringWithFormat:@"ArtCrypto Error iv length is not 16: %d", (int)[self.ivSpec.iv length]]]; return NO; } *algorithm = kCCAlgorithmAES128; @@ -123,10 +126,16 @@ - (id)initWithCipherParams:(ARTCipherParams *)cipherParams { return self; } +-(size_t) keyLength { + return [self.keySpec.key length] *8; +} + + (instancetype)cbcCipherWithParams:(ARTCipherParams *)cipherParams { return [[self alloc] initWithCipherParams:cipherParams]; } + + - (ARTStatus)encrypt:(NSData *)plaintext output:(NSData *__autoreleasing *)output { // Encryptions must be serialized as they depend on the final block of the previous iteration NSData *ciphertext = nil; @@ -136,7 +145,7 @@ - (ARTStatus)encrypt:(NSData *)plaintext output:(NSData *__autoreleasing *)outpu void *buf = malloc(outputBufLen); if (!buf) { - // TODO report error? + [ARTLog error:@"ARTCrypto error encrypting"]; return ARTStatusError; } @@ -157,13 +166,14 @@ - (ARTStatus)encrypt:(NSData *)plaintext output:(NSData *__autoreleasing *)outpu CCCryptorStatus status = CCCrypt(kCCEncrypt, self.algorithm, kCCOptionPKCS7Padding, key, keyLen, iv, dataIn, dataInLen, ciphertextBuf, ciphertextBufLen, &bytesWritten); if (status) { - // TODO report error accordingly + [ARTLog error:[NSString stringWithFormat:@"ARTCrypto error encrypting. Status is %d", status]]; free(ciphertextBuf); return ARTStatusError; } ciphertext = [NSData dataWithBytesNoCopy:buf length:(bytesWritten + self.blockLength) freeWhenDone:YES]; if (nil == ciphertext) { + [ARTLog error:@"ARTCrypto error encrypting. cipher text is nil"]; free(buf); return ARTStatusError; } @@ -174,7 +184,7 @@ - (ARTStatus)encrypt:(NSData *)plaintext output:(NSData *__autoreleasing *)outpu if (newIv) { self.iv = newIv; } else { - // TODO Log error - not much else we can do + [ARTLog warn:@"ARTCrypto error encrypting. error updating iv"]; } *output = ciphertext; @@ -205,7 +215,7 @@ - (ARTStatus)decrypt:(NSData *)ciphertext output:(NSData *__autoreleasing *)outp size_t bytesWritten = 0; if (!buf) { - // TODO report error? + [ARTLog error:@"ARTCrypto error decrypting."]; return ARTStatusError; } @@ -214,6 +224,7 @@ - (ARTStatus)decrypt:(NSData *)ciphertext output:(NSData *__autoreleasing *)outp CCCryptorStatus status = CCCrypt(kCCDecrypt, self.algorithm, options, key, keyLength, iv, dataIn, dataInLength, buf, outputLength, &bytesWritten); if (status) { + [ARTLog error:[NSString stringWithFormat:@"ARTCrypto error decrypting. Status is %d", status]]; free(buf); return ARTStatusError; } @@ -237,6 +248,7 @@ - (ARTStatus)decrypt:(NSData *)ciphertext output:(NSData *__autoreleasing *)outp NSData *plaintext = [NSData dataWithBytesNoCopy:buf length:unpaddedLength freeWhenDone:YES]; if (!plaintext) { + [ARTLog error:@"ARTCrypto error decrypting. plain text is nil"]; free(buf); } @@ -251,6 +263,7 @@ - (NSString *)cipherName { case kCCAlgorithmAES128: algo = @"aes-128"; break; + case kCCAlgorithmDES: algo = @"des"; break; @@ -333,7 +346,6 @@ + (ARTCipherParams *)defaultParamsWithKey:(NSData *)key { if (nil == ivData) { return nil; } - return [self defaultParamsWithKey:key iv:ivData]; } diff --git a/ably-ios/ARTEncoder.h b/ably-ios/ARTEncoder.h index 704a0a10b..7cf396133 100644 --- a/ably-ios/ARTEncoder.h +++ b/ably-ios/ARTEncoder.h @@ -11,11 +11,15 @@ @class ARTMessage; @class ARTPresenceMessage; @class ARTProtocolMessage; - +@class ARTTokenDetails; +@class ARTHttpError; @protocol ARTEncoder - (NSString *)mimeType; + + +- (ARTTokenDetails *) decodeAccessToken:(NSData *) data; - (ARTMessage *)decodeMessage:(NSData *)data; - (NSArray *)decodeMessages:(NSData *)data; - (NSData *)encodeMessage:(ARTMessage *)message; @@ -30,7 +34,7 @@ - (ARTProtocolMessage *)decodeProtocolMessage:(NSData *)data; - (NSDate *)decodeTime:(NSData *)data; - +- (ARTHttpError *) decodeError:(NSData *) error; - (NSArray *)decodeStats:(NSData *)data; @end diff --git a/ably-ios/ARTHttp.h b/ably-ios/ARTHttp.h index 9207b1562..5b1719507 100644 --- a/ably-ios/ARTHttp.h +++ b/ably-ios/ARTHttp.h @@ -10,6 +10,14 @@ #import "ARTTypes.h" + +@interface ARTHttpError : NSObject +@property (strong, nonatomic) NSString *message; +@property (assign, nonatomic) int statusCode; +@property (assign, nonatomic) int code; +@end + + @interface ARTHttpRequest : NSObject @property (readonly, strong, nonatomic) NSString *method; diff --git a/ably-ios/ARTHttp.m b/ably-ios/ARTHttp.m index 4d0614878..581bd9cdc 100644 --- a/ably-ios/ARTHttp.m +++ b/ably-ios/ARTHttp.m @@ -9,6 +9,12 @@ #import "ARTHttp.h" #import "ARTLog.h" + + +@implementation ARTHttpError +@end + + @interface ARTHttp () @property (readonly, strong, nonatomic) NSURL *baseUrl; @@ -164,13 +170,13 @@ - (instancetype)initWithBaseUrl:(NSURL *)baseUrl { NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:artRequest.url]; request.HTTPMethod = artRequest.method; - for (NSString *headerName in artRequest.headers) { NSString *headerValue = [artRequest.headers objectForKey:headerName]; [request setValue:headerValue forHTTPHeaderField:headerName]; } request.HTTPBody = artRequest.body; + [ARTLog debug:[NSString stringWithFormat:@"ARTHttp: makeRequest %@", [request allHTTPHeaderFields]]]; CFRunLoopRef rl = CFRunLoopGetCurrent(); CFRetain(rl); @@ -188,8 +194,10 @@ - (instancetype)initWithBaseUrl:(NSURL *)baseUrl { else { if (httpResponse) { int status = (int)httpResponse.statusCode; - [ARTLog verbose: - [NSString stringWithFormat:@"ARTHttp response status is %d", status]]; + [ARTLog debug: + [NSString stringWithFormat:@"ARTHttp response status is %d", status]]; + + [ARTLog verbose:[NSString stringWithFormat:@"ARTHTtp received response %@",[NSJSONSerialization JSONObjectWithData:data options:0 error:nil]]]; CFRunLoopPerformBlock(rl, kCFRunLoopDefaultMode, ^{ cb([ARTHttpResponse responseWithStatus:status headers:httpResponse.allHeaderFields body:data]); }); diff --git a/ably-ios/ARTHttpPaginatedResult.m b/ably-ios/ARTHttpPaginatedResult.m index b2eb60846..06b4bfa92 100644 --- a/ably-ios/ARTHttpPaginatedResult.m +++ b/ably-ios/ARTHttpPaginatedResult.m @@ -7,7 +7,7 @@ // #import "ARTHttpPaginatedResult.h" - +#import "ARTLog.h" @interface ARTHttpPaginatedResult () @property (readonly, strong, nonatomic) ARTHttp *http; @@ -68,13 +68,15 @@ - (void)getNextPage:(ARTPaginatedResultCb)cb { + (id)makePaginatedRequest:(ARTHttp *)http request:(ARTHttpRequest *)request responseProcessor:(ARTHttpResponseProcessor)responseProcessor cb:(ARTPaginatedResultCb)cb { return [http makeRequest:request cb:^(ARTHttpResponse *response) { if (!response) { + [ARTLog error:@"ARTHttpPaginatedResult got no response"]; cb(ARTStatusError, nil); return; } if (response.status < 200 || response.status >= 300) { + [ARTLog error:[NSString stringWithFormat:@"ARTHttpPaginatedResult response.status invalid: %d", response.status]]; cb(ARTStatusError, nil); -// NSLog(@"Body: %@", [[NSString alloc] initWithData:response.body encoding:NSUTF8StringEncoding]); + return; } diff --git a/ably-ios/ARTJsonEncoder.m b/ably-ios/ARTJsonEncoder.m index fe05a04f3..0063ed943 100644 --- a/ably-ios/ARTJsonEncoder.m +++ b/ably-ios/ARTJsonEncoder.m @@ -11,9 +11,12 @@ #import "ARTPresenceMessage.h" #import "ARTProtocolMessage.h" #import "ARTStats.h" -#import "NSDictionary+ARTDictionaryUtil.h" -#import "NSDate+ARTUtil.h" +#import "ARTNSDictionary+ARTDictionaryUtil.h" +#import "ARTNSDate+ARTUtil.h" #import "ARTLog.h" +#import "ARTAuth.h" +#import "ARTHttp.h" + @interface ARTJsonEncoder () - (ARTMessage *)messageFromDictionary:(NSDictionary *)input; @@ -97,6 +100,10 @@ - (ARTProtocolMessage *)decodeProtocolMessage:(NSData *)data { return [self protocolMessageFromDictionary:[self decodeDictionary:data]]; } +- (ARTTokenDetails *) decodeAccessToken:(NSData *) data { + return [self tokenFromDictionary:[self decodeDictionary:data]]; +} + - (NSDate *)decodeTime:(NSData *)data { NSArray *resp = [self decodeArray:data]; if (resp && resp.count == 1) { @@ -158,7 +165,7 @@ -(ARTPresenceMessageAction) presenceMessageActionFromInt:(int) action case 4: return ARTPresenceMessageUpdate; } - NSLog(@"error. enum is probably not up to date"); + [ARTLog error:[NSString stringWithFormat:@"ARTJsonEncoder invalid ARTPresenceMessage action %d", action]]; return ArtPresenceMessageAbsent; } @@ -185,6 +192,7 @@ - (ARTPresenceMessage *)presenceMessageFromDictionary:(NSDictionary *)input { } ARTPresenceMessage *message = [[ARTPresenceMessage alloc] init]; message.id = [input artString:@"id"]; + message.encoding = [input artString:@"encoding"]; message.clientId = [input artString:@"clientId"]; message.payload = [self payloadFromDictionary:input]; message.timestamp = [input artDate:@"timestamp"]; @@ -307,6 +315,20 @@ - (NSDictionary *)protocolMessageToDictionary:(ARTProtocolMessage *)message { return output; } +-(ARTTokenDetails *) tokenFromDictionary:(NSDictionary *) input { + if (![input isKindOfClass:[NSDictionary class]]) { + return nil; + } + ARTTokenDetails * tok = [[ARTTokenDetails alloc] + initWithId: [input artString:@"token"] + expires: [[input artNumber:@"expires"] longLongValue] + issued: [[input artNumber:@"issued"] longLongValue] + capability: [input artString:@"capability"] + clientId: [input artString:@"clientId"]]; + return tok; + +} + - (ARTProtocolMessage *)protocolMessageFromDictionary:(NSDictionary *)input { if (![input isKindOfClass:[NSDictionary class]]) { return nil; @@ -315,7 +337,6 @@ - (ARTProtocolMessage *)protocolMessageFromDictionary:(NSDictionary *)input { ARTProtocolMessage *message = [[ARTProtocolMessage alloc] init]; message.action = (ARTProtocolMessageAction)[[input artNumber:@"action"] intValue]; message.count = [[input artNumber:@"count"] intValue]; - // TODO: ERROR, what to do? message.channel = [input artString:@"channel"]; message.channelSerial = [input artString:@"channelSerial"]; message.connectionId = [input artString:@"connectionId"]; @@ -459,6 +480,16 @@ - (ARTStatsResourceCount *)statsResourceCountFromDictionary:(NSDictionary *)inpu return nil; } +- (ARTHttpError *) decodeError:(NSData *) error { + ARTHttpError * e = [[ARTHttpError alloc] init]; + NSDictionary * d = [[self decodeDictionary:error] valueForKey:@"error"]; + e.code= [[d artNumber:@"code"] intValue]; + e.message = [d artString:@"message"]; + e.statusCode = [[d artNumber:@"statusCode"] intValue]; + return e; + +} + - (ARTStatsRequestCount *)statsRequestCountFromDictionary:(NSDictionary *)input { if (![input isKindOfClass:[NSDictionary class]]) { return nil; @@ -473,7 +504,6 @@ - (ARTStatsRequestCount *)statsRequestCountFromDictionary:(NSDictionary *)input [refused isKindOfClass:[NSNumber class]]) { return [[ARTStatsRequestCount alloc] initWithSucceeded:[succeeded doubleValue] failed:[failed doubleValue] refused:[refused doubleValue]]; } - return nil; } @@ -481,18 +511,16 @@ - (ARTPayload *)payloadFromDictionary:(NSDictionary *)input { if (![input isKindOfClass:[NSDictionary class]]) { return nil; } - NSString *encoding = [input objectForKey:@"encoding"]; if (!encoding) { encoding = @""; } - id data = [input objectForKey:@"data"]; ARTPayload *payload = [ARTPayload payloadWithPayload:data encoding:encoding]; ARTPayload *decoded = nil; ARTStatus status = [[ARTBase64PayloadEncoder instance] decode:payload output:&decoded]; if (status != ARTStatusOk) { - // TODO log + [ARTLog error:[NSString stringWithFormat:@"ARTJsonEncoder failed to decode payload %@", payload]]; } return decoded; } diff --git a/ably-ios/ARTLog.h b/ably-ios/ARTLog.h index 57a4839e5..c89bdfaea 100644 --- a/ably-ios/ARTLog.h +++ b/ably-ios/ARTLog.h @@ -36,5 +36,4 @@ typedef void(^ARTLogCallback)(id); +(void) warn:(id) str; +(void) error:(id) str; - @end diff --git a/ably-ios/ARTLog.m b/ably-ios/ARTLog.m index d3457d206..11dd4ba49 100644 --- a/ably-ios/ARTLog.m +++ b/ably-ios/ARTLog.m @@ -8,19 +8,38 @@ #import "ARTLog.h" +@interface ARTLog() + +@property (nonatomic, assign) ARTLogLevel logLevel; +@property (nonatomic, copy) ARTLogCallback cb; +@end + @implementation ARTLog +-(id) init { + self = [super init]; + if(self) { + + } + return self; +} -static ARTLogLevel g_logLevel = ArtLogLevelError; -static ARTLogCallback g_cb = nil; ++(ARTLog *) instance { + static ARTLog * logger = nil; + static dispatch_once_t onceToken; + dispatch_once(&onceToken, ^{ + logger = [[ARTLog alloc] init]; + logger.logLevel = ArtLogLevelWarn; + }); + return logger; +} +(void) setLogLevel:(ARTLogLevel) level { - g_logLevel = level; + [ARTLog instance].logLevel = level; } - +(void) setLogCallback:(ARTLogCallback) cb { - g_cb= cb; + [ARTLog instance].cb = cb; } +(void) verbose:(id) str { @@ -43,14 +62,36 @@ +(void) error:(id) str { [ARTLog log:str level:ArtLogLevelError]; } ++(NSString *) logLevelStr:(ARTLogLevel) level { + switch(level) { + case ArtLogLevelNone: + return @""; + case ArtLogLevelVerbose: + return @"VERBOSE"; + case ArtLogLevelDebug: + return @"DEBUG"; + case ArtLogLevelInfo: + return @"INFO"; + case ArtLogLevelWarn: + return @"WARN"; + case ArtLogLevelError: + return @"ERROR"; + } + return @""; +} + +(void) log:(id) str level:(ARTLogLevel) level { - if(level >= g_logLevel) { - if(g_cb) { - g_cb(str); + ARTLog * logger = [ARTLog instance]; + + NSString * res = [NSString stringWithFormat:@"%@: %@",[ARTLog logLevelStr:level],str]; + if(level >= logger.logLevel) { + if(logger.cb) { + logger.cb(res); } else { - NSLog(@"%@", str); + NSLog(@"%@",res); } } } + @end diff --git a/ably-ios/ARTMessage.m b/ably-ios/ARTMessage.m index 0093096f9..397091499 100644 --- a/ably-ios/ARTMessage.m +++ b/ably-ios/ARTMessage.m @@ -7,7 +7,7 @@ // #import "ARTMessage.h" - +#import "ARTLog.h" @implementation ARTMessage - (instancetype)init { @@ -36,7 +36,7 @@ - (ARTMessage *)decode:(id)encoder { ARTPayload *payload = self.payload; ARTStatus status = [encoder decode:payload output:&payload]; if (status != ARTStatusOk) { - // TODO log + [ARTLog warn:[NSString stringWithFormat:@"ARTMessage could not decode payload, ARTStatus: %tu", status]]; } return [self messageWithPayload:payload]; } @@ -45,7 +45,7 @@ - (ARTMessage *)encode:(id)encoder { ARTPayload *payload = self.payload; ARTStatus status = [encoder encode:payload output:&payload]; if (status != ARTStatusOk) { - // TODO log + [ARTLog warn:[NSString stringWithFormat:@"ARTMessage could not encode payload, ARTStatus: %tu", status]]; } return [self messageWithPayload:payload]; } diff --git a/ably-ios/ARTMsgPackEncoder.m b/ably-ios/ARTMsgPackEncoder.m index 855b0d994..b9ff88c39 100644 --- a/ably-ios/ARTMsgPackEncoder.m +++ b/ably-ios/ARTMsgPackEncoder.m @@ -12,8 +12,8 @@ #import "ARTPresenceMessage.h" #import "ARTProtocolMessage.h" #import "ARTStats.h" -#import "NSDictionary+ARTDictionaryUtil.h" -#import "NSDate+ARTUtil.h" +#import "ARTNSDictionary+ARTDictionaryUtil.h" +#import "ARTNSDate+ARTUtil.h" /* #import @@ -70,6 +70,10 @@ - (NSString *)mimeType { return @"application/msgpack"; } + +-(ARTTokenDetails *) decodeAccessToken:(NSData *)data { + return nil; +} - (ARTMessage *)decodeMessage:(NSData *)data { return [self messageFromDictionary:[self decodeDictionary:data]]; } diff --git a/ably-ios/NSArray+ARTFunctional.h b/ably-ios/ARTNSArray+ARTFunctional.h similarity index 100% rename from ably-ios/NSArray+ARTFunctional.h rename to ably-ios/ARTNSArray+ARTFunctional.h diff --git a/ably-ios/NSArray+ARTFunctional.m b/ably-ios/ARTNSArray+ARTFunctional.m similarity index 91% rename from ably-ios/NSArray+ARTFunctional.m rename to ably-ios/ARTNSArray+ARTFunctional.m index 05e9ebba1..7e18d7083 100644 --- a/ably-ios/NSArray+ARTFunctional.m +++ b/ably-ios/ARTNSArray+ARTFunctional.m @@ -6,7 +6,7 @@ // Copyright (c) 2014 Ably. All rights reserved. // -#import "NSArray+ARTFunctional.h" +#import "ARTNSArray+ARTFunctional.h" @implementation NSArray (ARTFunctional) diff --git a/ably-ios/NSDate+ARTUtil.h b/ably-ios/ARTNSDate+ARTUtil.h similarity index 100% rename from ably-ios/NSDate+ARTUtil.h rename to ably-ios/ARTNSDate+ARTUtil.h diff --git a/ably-ios/NSDate+ARTUtil.m b/ably-ios/ARTNSDate+ARTUtil.m similarity index 98% rename from ably-ios/NSDate+ARTUtil.m rename to ably-ios/ARTNSDate+ARTUtil.m index e3c6ae2ff..f3d9b440b 100644 --- a/ably-ios/NSDate+ARTUtil.m +++ b/ably-ios/ARTNSDate+ARTUtil.m @@ -6,7 +6,7 @@ // Copyright (c) 2014 Ably. All rights reserved. // -#import "NSDate+ARTUtil.h" +#import "ARTNSDate+ARTUtil.h" @implementation NSDate (ARTUtil) diff --git a/ably-ios/NSDictionary+ARTDictionaryUtil.h b/ably-ios/ARTNSDictionary+ARTDictionaryUtil.h similarity index 100% rename from ably-ios/NSDictionary+ARTDictionaryUtil.h rename to ably-ios/ARTNSDictionary+ARTDictionaryUtil.h diff --git a/ably-ios/NSDictionary+ARTDictionaryUtil.m b/ably-ios/ARTNSDictionary+ARTDictionaryUtil.m similarity index 92% rename from ably-ios/NSDictionary+ARTDictionaryUtil.m rename to ably-ios/ARTNSDictionary+ARTDictionaryUtil.m index df11551e0..806608d72 100644 --- a/ably-ios/NSDictionary+ARTDictionaryUtil.m +++ b/ably-ios/ARTNSDictionary+ARTDictionaryUtil.m @@ -6,8 +6,8 @@ // Copyright (c) 2014 Ably. All rights reserved. // -#import "NSDictionary+ARTDictionaryUtil.h" -#import "NSDate+ARTUtil.h" +#import "ARTNSDictionary+ARTDictionaryUtil.h" +#import "ARTNSDate+ARTUtil.h" @implementation NSDictionary (ARTDictionaryUtil) diff --git a/ably-ios/ARTOptions.h b/ably-ios/ARTOptions.h index 3134b73fd..323a976b0 100644 --- a/ably-ios/ARTOptions.h +++ b/ably-ios/ARTOptions.h @@ -21,6 +21,8 @@ @property (readwrite, assign, nonatomic) BOOL queueMessages; @property (readwrite, assign, nonatomic) BOOL echoMessages; @property (readwrite, assign, nonatomic) BOOL binary; + +//TODO some of these are possibly redundant now @property (readwrite, assign, nonatomic) NSString *resume; @property (readwrite, assign, nonatomic) NSString *resumeKey; @property (readwrite, strong, nonatomic) NSString *recover; diff --git a/ably-ios/ARTOptions.m b/ably-ios/ARTOptions.m index 9d77fb13a..561cbb5b7 100644 --- a/ably-ios/ARTOptions.m +++ b/ably-ios/ARTOptions.m @@ -35,6 +35,7 @@ - (instancetype)initWithKey:(NSString *)key { self = [super init]; if (self) { _authOptions = [ARTAuthOptions optionsWithKey:key]; + if (!_authOptions) { self = nil; } @@ -70,6 +71,7 @@ - (instancetype)initDefaults { _recover = nil; _binary = false; _resumeKey = nil; + return self; } diff --git a/ably-ios/ARTPayload+Private.h b/ably-ios/ARTPayload+Private.h new file mode 100644 index 000000000..0f78fa38a --- /dev/null +++ b/ably-ios/ARTPayload+Private.h @@ -0,0 +1,19 @@ +// +// ARTPayload+Private.h +// ably +// +// Created by vic on 22/04/2015. +// Copyright (c) 2015 Ably. All rights reserved. +// + +#import + +@interface ARTPayload (Private) +{ + +} + ++(NSArray *) parseEncodingChain:(NSString *) encodingChain key:(NSData *) key iv:(NSData *) iv; + ++(id) createEncoder:(NSString *) name key:(NSData *) key iv:(NSData *) iv; +@end diff --git a/ably-ios/ARTPayload.h b/ably-ios/ARTPayload.h index c29f4e20c..095f7c800 100644 --- a/ably-ios/ARTPayload.h +++ b/ably-ios/ARTPayload.h @@ -40,13 +40,13 @@ - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output; - (ARTStatus)decode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output; - +- (NSString *)name; @end @interface ARTBase64PayloadEncoder : NSObject + (instancetype)instance; - ++(NSString *) toBase64:(NSData *) input; @end @interface ARTUtf8PayloadEncoder : NSObject diff --git a/ably-ios/ARTPayload.m b/ably-ios/ARTPayload.m index fdf19486f..45c3b5d42 100644 --- a/ably-ios/ARTPayload.m +++ b/ably-ios/ARTPayload.m @@ -7,11 +7,13 @@ // #import "ARTPayload.h" +#import "ARTPayload+Private.h" #import "ARTCrypto.h" +#import "ARTLog.h" + @interface ARTBase64PayloadEncoder () -+ (NSString *)name; + (BOOL)canEncode:(ARTPayload *)payload; + (BOOL)canDecode:(ARTPayload *)payload; @@ -63,6 +65,45 @@ + (instancetype)payloadWithPayload:(id)payload encoding:(NSString *)encoding { [[ARTCipherPayloadEncoder alloc] initWithCipherParams:cipherParams]]]; } ++(id) createEncoder:(NSString *) name key:(NSData *) key iv:(NSData *) iv { + if([name isEqualToString:@"json"]) { + return [ARTJsonPayloadEncoder instance]; + } + else if([name isEqualToString:@"base64"]) { + return [ARTBase64PayloadEncoder instance]; + } + else if([name isEqualToString:@"utf-8"]) { + return [ARTUtf8PayloadEncoder instance]; + } + //256 on iOS is handled by passing the keyLength into kCCAlgorithmAES128 + else if([name isEqualToString:@"cipher+aes-256-cbc"] || [name isEqualToString:@"cipher+aes-128-cbc"]){ + + ARTIvParameterSpec * ivSpec = [[ARTIvParameterSpec alloc] initWithIv:iv]; + ARTSecretKeySpec * keySpec = [[ARTSecretKeySpec alloc] initWithKey:key algorithm:@"aes"]; + ARTCipherParams * params =[[ARTCipherParams alloc] initWithAlgorithm:@"aes" keySpec:keySpec ivSpec:ivSpec]; + + return [[ARTCipherPayloadEncoder alloc] initWithCipherParams:params]; + } + [ARTLog error:[NSString stringWithFormat:@"ARTPayload: unknown encoder name %@", name]]; + return nil; +} + ++(NSArray *) parseEncodingChain:(NSString *) encodingChain key:(NSData *) key iv:(NSData *) iv { + NSArray * strArray = [encodingChain componentsSeparatedByString:@"/"]; + NSMutableArray * encoders= [[NSMutableArray alloc] init]; + size_t l = [strArray count]; + for(int i=0;i < l; i++) { + NSString * encoderName = [strArray objectAtIndex:i]; + id encoder = [ARTPayload createEncoder:encoderName key:key iv:iv]; + if(encoder == nil) { + [ARTLog warn:[NSString stringWithFormat:@"ARTPayload: error creating encoder %d in chain %@", i, encodingChain]]; + } + else { + [encoders addObject:encoder]; + } + } + return encoders; +} @end @implementation NSString (ARTPayload) @@ -92,23 +133,34 @@ + (instancetype)instance { return instance; } -+ (NSString *)name { ++(NSString *) toBase64:(NSData *) input { + ARTPayload * p = [[ARTPayload alloc] initWithPayload:input encoding:@"base64"]; + ARTPayload * output = nil; + ARTBase64PayloadEncoder * e = [ARTBase64PayloadEncoder instance]; + [e encode:p output:&output]; + return output.payload; +} + ++(NSString *) getName { return @"base64"; } +- (NSString *)name { + return [ARTBase64PayloadEncoder getName]; +} + (BOOL)canEncode:(ARTPayload *)payload { return [payload.payload isKindOfClass:[NSData class]]; } + (BOOL)canDecode:(ARTPayload *)payload { - return [payload.encoding isEqualToString:[ARTBase64PayloadEncoder name]]; + return [payload.encoding isEqualToString:[ARTBase64PayloadEncoder getName]]; } - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { if ([ARTBase64PayloadEncoder canEncode:payload]) { NSString *encoded = [((NSData *)payload.payload) base64EncodedStringWithOptions:0]; if (encoded) { - *output = [ARTPayload payloadWithPayload:encoded encoding:[payload.encoding artAddEncoding:[ARTBase64PayloadEncoder name]]]; + *output = [ARTPayload payloadWithPayload:encoded encoding:[payload.encoding artAddEncoding:[ARTBase64PayloadEncoder getName]]]; return ARTStatusOk; } else { // Set the output to be the original payload @@ -121,10 +173,11 @@ - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *) } - (ARTStatus)decode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { - if ([ARTBase64PayloadEncoder canDecode:payload]) { + if ([[payload.encoding artLastEncoding] isEqualToString:[ARTBase64PayloadEncoder getName]]) {//[ARTBase64PayloadEncoder canDecode:payload]) { NSData *decoded = [[NSData alloc] initWithBase64EncodedString:payload.payload options:0]; if (decoded) { *output = [ARTPayload payloadWithPayload:decoded encoding:[payload.encoding artRemoveLastEncoding]]; + [ARTLog debug:[NSString stringWithFormat:@"ARTBase64PayloadEncoder payload decoded successfully: %@", payload.encoding]]; return ARTStatusOk; } // Set the output to be the original payload @@ -148,13 +201,20 @@ + (instancetype)instance { return instance; } ++(NSString *) getName { + return @"utf-8"; +} +- (NSString *)name { + return [ARTUtf8PayloadEncoder getName]; +} - (ARTStatus)decode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { *output = payload; - if ([[payload.encoding artLastEncoding] isEqualToString:@"utf-8"]) { + if ([[payload.encoding artLastEncoding] isEqualToString:[ARTUtf8PayloadEncoder getName]]) { if ([payload.payload isKindOfClass:[NSData class]]) { NSString *decoded = [[NSString alloc] initWithData:payload.payload encoding:NSUTF8StringEncoding]; if (decoded) { *output = [ARTPayload payloadWithPayload:decoded encoding:[payload.encoding artRemoveLastEncoding]]; + [ARTLog debug:@"utf8 payload decoded successfully"]; return ARTStatusOk; } } @@ -168,7 +228,7 @@ - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *) if ([payload isKindOfClass:[NSString class]]) { NSData *encoded = [((NSString *)payload.payload) dataUsingEncoding:NSUTF8StringEncoding]; if (encoded) { - *output = [ARTPayload payloadWithPayload:encoded encoding:[payload.encoding artAddEncoding:@"utf-8"]]; + *output = [ARTPayload payloadWithPayload:encoded encoding:[payload.encoding artAddEncoding:[ARTUtf8PayloadEncoder getName]]]; return ARTStatusOk; } return ARTStatusError; @@ -189,12 +249,19 @@ + (instancetype)instance { return instance; } ++ (NSString *) getName { + return @"json"; +} +- (NSString *)name { + return [ARTJsonPayloadEncoder getName]; +} + - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { *output = payload; if ([payload.payload isKindOfClass:[NSDictionary class]] || [payload.payload isKindOfClass:[NSArray class]]) { NSData *encoded = [NSJSONSerialization dataWithJSONObject:payload.payload options:0 error:nil]; if (encoded) { - *output = [ARTPayload payloadWithPayload:encoded encoding:[payload.encoding artAddEncoding:@"json"]]; + *output = [ARTPayload payloadWithPayload:encoded encoding:[payload.encoding artAddEncoding:[ARTJsonPayloadEncoder getName]]]; return ARTStatusOk; } else { return ARTStatusError; @@ -205,10 +272,12 @@ - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *) - (ARTStatus)decode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { *output = payload; - if ([[payload.encoding artLastEncoding] isEqualToString:@"json"]) { + if ([[payload.encoding artLastEncoding] isEqualToString:[ARTJsonPayloadEncoder getName]]) { id decoded = nil; if ([payload.payload isKindOfClass:[NSString class]]) { - decoded = [NSJSONSerialization JSONObjectWithData:payload.payload options:0 error:nil]; + NSData * d = [payload.payload dataUsingEncoding:NSUTF8StringEncoding]; + decoded = [NSJSONSerialization JSONObjectWithData:d options:0 error:nil]; + if (decoded) { *output = [ARTPayload payloadWithPayload:decoded encoding:[payload.encoding artRemoveLastEncoding]]; return ARTStatusOk; @@ -235,17 +304,42 @@ - (instancetype)initWithCipherParams:(ARTCipherParams *)cipherParams { return self; } ++(NSString *) getName128 { + return @"cipher+aes-128-cbc"; +} + ++(NSString *) getName256 { + return @"cipher+aes-256-cbc"; +} + +- (NSString *)name { + size_t keyLen =[self.cipher keyLength]; + if(keyLen== 128) { + return [ARTCipherPayloadEncoder getName128]; + } + else if(keyLen == 256) { + return [ARTCipherPayloadEncoder getName256]; + } + else { + [ARTLog error:[NSString stringWithFormat:@"ARTPayload: keyLength is invalid %zu", keyLen]]; + } + return @""; +} + - (ARTStatus)decode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { *output = payload; - if ([payload.payload isKindOfClass:[NSData class]] && [[payload.encoding artLastEncoding] hasPrefix:@"cipher+"]) { - // TODO ensure the suffix of ciper+ is the same as cipher.cipherName? + + NSString * cipherName =[payload.encoding artLastEncoding]; + if ([payload.payload isKindOfClass:[NSData class]] && [cipherName isEqualToString:[self name]]) { NSData *decrypted = nil; ARTStatus status = [self.cipher decrypt:payload.payload output:&decrypted]; if (status == ARTStatusOk) { *output = [ARTPayload payloadWithPayload:decrypted encoding:[payload.encoding artRemoveLastEncoding]]; + [ARTLog debug:@"cipher payload decoded successfully"]; } return status; } + return ARTStatusOk; } @@ -255,7 +349,7 @@ - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *) NSData *encrypted = nil; ARTStatus status = [self.cipher encrypt:payload.payload output:&encrypted]; if (status == ARTStatusOk) { - NSString *cipherName = [NSString stringWithFormat:@"cipher+%@", self.cipher.cipherName]; + NSString *cipherName = [self name]; *output = [ARTPayload payloadWithPayload:encrypted encoding:[payload.encoding artAddEncoding:cipherName]]; } return status; @@ -279,6 +373,10 @@ - (instancetype)initWithEncoders:(NSArray *)encoders { return self; } +-(NSString *) name { + return @"chain"; //not used. +} + - (ARTStatus)encode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *)output { ARTStatus status = ARTStatusOk; *output = payload; @@ -297,11 +395,16 @@ - (ARTStatus)decode:(ARTPayload *)payload output:(ARTPayload *__autoreleasing *) ARTStatus status = ARTStatusOk; *output = payload; + int count=0; for (id enc in self.encoders.reverseObjectEnumerator) { + status = [enc decode:*output output:output]; if (status != ARTStatusOk) { + ARTPayload * p = *output; + [ARTLog error:[NSString stringWithFormat:@"ARTPayload: error in ARTPayloadEncoderChain decoding with encoder %d. Remaining encoding jobs are %@", count, p.encoding]]; break; } + count++; } return status; diff --git a/ably-ios/ARTPresenceMessage.h b/ably-ios/ARTPresenceMessage.h index 231c6bdaa..12f665239 100644 --- a/ably-ios/ARTPresenceMessage.h +++ b/ably-ios/ARTPresenceMessage.h @@ -22,8 +22,10 @@ typedef NS_ENUM(NSUInteger, ARTPresenceMessageAction) { @property (readwrite, strong, nonatomic) NSString *id; @property (readwrite, strong, nonatomic) NSString *clientId; +@property (readwrite, strong, nonatomic) NSString *encoding; @property (readwrite, strong, nonatomic) ARTPayload *payload; @property (readwrite, strong, nonatomic) NSDate *timestamp; + @property (readwrite, assign, nonatomic) ARTPresenceMessageAction action; @property (readwrite, strong, nonatomic) NSString *connectionId; diff --git a/ably-ios/ARTPresenceMessage.m b/ably-ios/ARTPresenceMessage.m index f2c18b6ff..7c55d075e 100644 --- a/ably-ios/ARTPresenceMessage.m +++ b/ably-ios/ARTPresenceMessage.m @@ -7,7 +7,7 @@ // #import "ARTPresenceMessage.h" - +#import "ARTLog.h" @implementation ARTPresenceMessage - (instancetype)init { @@ -19,6 +19,7 @@ - (instancetype)init { _timestamp = nil; _action = ARTPresenceMessageEnter; _connectionId = nil; + _encoding = nil; } return self; } @@ -31,6 +32,7 @@ - (ARTPresenceMessage *)messageWithPayload:(ARTPayload *)payload { m.timestamp = self.timestamp; m.action = self.action; m.connectionId = self.connectionId; + m.encoding = self.encoding; return m; } @@ -38,7 +40,7 @@ - (ARTPresenceMessage *)decode:(id)encoder { ARTPayload *payload = self.payload; ARTStatus status = [encoder decode:payload output:&payload]; if (status != ARTStatusOk) { - // TODO log + [ARTLog warn:[NSString stringWithFormat:@"ARTPresenceMessage could not decode payload, ARTStatus: %tu", status]]; } return [self messageWithPayload:payload]; } @@ -47,7 +49,7 @@ - (ARTPresenceMessage *)encode:(id)encoder { ARTPayload *payload = self.payload; ARTStatus status = [encoder encode:payload output:&payload]; if (status != ARTStatusOk) { - // TODO log + [ARTLog warn:[NSString stringWithFormat:@"ARTPresenceMessage could not encode payload, ARTStatus: %tu", status]]; } return [self messageWithPayload:payload]; } diff --git a/ably-ios/ARTRealtime.h b/ably-ios/ARTRealtime.h index cd60dfab2..e3991638c 100644 --- a/ably-ios/ARTRealtime.h +++ b/ably-ios/ARTRealtime.h @@ -67,6 +67,7 @@ typedef void (^ARTRealtimeChannelMessageCb)(ARTMessage *); - (id)subscribeToName:(NSString *)name cb:(ARTRealtimeChannelMessageCb)cb ART_WARN_UNUSED_RESULT; - (id)subscribeToNames:(NSArray *)names cb:(ARTRealtimeChannelMessageCb)cb ART_WARN_UNUSED_RESULT; + typedef void (^ARTRealtimeChannelPresenceCb)(ARTPresenceMessage *); - (id)subscribeToPresence:(ARTRealtimeChannelPresenceCb)cb; diff --git a/ably-ios/ARTRealtime.m b/ably-ios/ARTRealtime.m index e1c6b4d8f..4d2a0a730 100644 --- a/ably-ios/ARTRealtime.m +++ b/ably-ios/ARTRealtime.m @@ -12,7 +12,7 @@ #import "ARTMessage.h" #import "ARTPresenceMessage.h" #import "ARTWebSocketTransport.h" -#import "NSArray+ARTFunctional.h" +#import "ARTNSArray+ARTFunctional.h" #import "ARTRealtime+Private.h" #import "ARTLog.h" @@ -331,7 +331,8 @@ - (void)publishMessages:(NSArray *)messages cb:(ARTStatusCallback)cb { ARTPayload *encodedPayload = nil; ARTStatus status = [self.payloadEncoder encode:message.payload output:&encodedPayload]; if (status != ARTStatusOk) { - // TODO log error message + [ARTLog error:[NSString stringWithFormat:@"ARTPresenceMessage: error decoding payload, status: %tu", status]]; + } return [message messageWithPayload:encodedPayload]; }]; @@ -474,7 +475,6 @@ - (void)publishProtocolMessage:(ARTProtocolMessage *)pm cb:(ARTStatusCallback)cb ARTRealtimeChannelSubscription *subscription = [[ARTRealtimeChannelSubscription alloc] initWithChannel:self cb:cb]; - for (NSString *name in nameSet) { NSMutableArray *subscriptions = [self.subscriptions objectForKey:name]; if (!subscriptions) { @@ -552,7 +552,7 @@ - (void)onChannelMessage:(ARTProtocolMessage *)message { [self onError:message]; break; default: - // TODO log? + [ARTLog warn:[NSString stringWithFormat:@"ARTRealtime, unknown ARTProtocolMessage action: %tu", message.action]]; break; } } @@ -828,7 +828,7 @@ - (void)unsubscribeState:(ARTRealtimeChannelStateSubscription *)subscription { } - (void)transition:(ARTRealtimeConnectionState)state { - [ARTLog debug:[NSString stringWithFormat:@"Transition to %@ requested", [ARTRealtime ARTRealtimeStateToStr:state]]]; + [ARTLog verbose:[NSString stringWithFormat:@"Transition to %@ requested", [ARTRealtime ARTRealtimeStateToStr:state]]]; // On exit logic switch (self.state) { @@ -858,8 +858,7 @@ - (void)transition:(ARTRealtimeConnectionState)state { // Create transport and initiate connection if(!self.transport) { - - //TODO can this be infinite? maybe self.resume should be an int. + if(previousState == ARTRealtimeFailed || previousState == ARTRealtimeDisconnected) { self.options.resume = [NSString stringWithFormat:@"%lld",self.connectionSerial]; self.options.resumeKey = self.connectionKey; @@ -958,8 +957,7 @@ - (void)cancelRetryTimer { } - (void)onHeartbeat:(ARTProtocolMessage *)message { - [ARTLog info:@"ARTRealtime heartbeat received"]; - // Ignore + [ARTLog verbose:@"ARTRealtime heartbeat received"]; } - (void)onConnected:(ARTProtocolMessage *)message { diff --git a/ably-ios/ARTRest+Private.h b/ably-ios/ARTRest+Private.h index 3aeab3b51..cf501c8a6 100644 --- a/ably-ios/ARTRest+Private.h +++ b/ably-ios/ARTRest+Private.h @@ -11,19 +11,28 @@ #import "ARTRest.h" #import "ARTEncoder.h" + +typedef NS_ENUM(NSUInteger, ARTAuthentication) { + ARTAuthenticationOff, + ARTAuthenticationOn, + ARTAuthenticationUseBasic +}; + @interface ARTRest (Private) @property (readonly, strong, nonatomic) id defaultEncoder; - +@property (readonly, strong, nonatomic) ARTAuth *auth; - (NSString *)formatQueryParams:(NSDictionary *)queryParams; + - (NSURL *)resolveUrl:(NSString *)relUrl; - (NSURL *)resolveUrl:(NSString *)relUrl queryParams:(NSDictionary *)queryParams; - (id)get:(NSString *)relUrl authenticated:(BOOL)authenticated cb:(ARTHttpCb)cb; - (id)get:(NSString *)relUrl headers:(NSDictionary *)headers authenticated:(BOOL)authenticated cb:(ARTHttpCb)cb; -- (id)post:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(BOOL)authenticated cb:(ARTHttpCb)cb; +- (id)post:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(ARTAuthentication)authenticated cb:(ARTHttpCb)cb; +- (id)withAuthHeadersUseBasic:(BOOL) useBasic cb:(id(^)(NSDictionary *))cb; - (id)withAuthHeaders:(id(^)(NSDictionary *authHeaders))cb; - (id)withAuthParams:(id(^)(NSDictionary *authParams))cb; diff --git a/ably-ios/ARTRest.h b/ably-ios/ARTRest.h index fa4743e14..2618420c6 100644 --- a/ably-ios/ARTRest.h +++ b/ably-ios/ARTRest.h @@ -14,6 +14,8 @@ #import "ARTPaginatedResult.h" @class ARTCipherParams; +@class ARTTokenDetails; +@class ARTAuthTokenParams; @interface ARTRestChannel : NSObject @@ -38,6 +40,8 @@ - (instancetype)initWithKey:(NSString *)key; - (instancetype)initWithOptions:(ARTOptions *)options; + +- (id) token:(ARTAuthTokenParams *) keyName tokenCb:(void (^)(ARTStatus status, ARTTokenDetails *)) cb; - (id)time:(void(^)(ARTStatus status, NSDate *time))cb; - (id)stats:(ARTPaginatedResultCb)cb; - (id)statsWithParams:(NSDictionary *)queryParams cb:(ARTPaginatedResultCb)cb; diff --git a/ably-ios/ARTRest.m b/ably-ios/ARTRest.m index e3792e5fa..acf46be4f 100644 --- a/ably-ios/ARTRest.m +++ b/ably-ios/ARTRest.m @@ -19,10 +19,14 @@ #import "ARTStats.h" #import "ARTPresenceMessage.h" -#import "NSDictionary+ARTDictionaryUtil.h" -#import "NSArray+ARTFunctional.h" +#import "ARTNSDictionary+ARTDictionaryUtil.h" +#import "ARTNSArray+ARTFunctional.h" #import "ARTLog.h" +#import "ARTHttp.h" + + + // TODO base accept headers on encoders @@ -48,7 +52,7 @@ @interface ARTRest () @property (readonly, strong, nonatomic) NSDictionary *encoders; @property (readonly, strong, nonatomic) NSString *defaultEncoding; -- (id)makeRequestWithMethod:(NSString *)method relUrl:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(BOOL)authenticated cb:(ARTHttpCb)cb; +- (id)makeRequestWithMethod:(NSString *)method relUrl:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(ARTAuthentication)authenticated cb:(ARTHttpCb)cb; - (NSDictionary *)withAcceptHeader:(NSDictionary *)headers; @@ -64,7 +68,6 @@ - (instancetype)initWithRest:(ARTRest *)rest name:(NSString *)name cipherParams: _rest = rest; _name = name; _basePath = [NSString stringWithFormat:@"/channels/%@", [name stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLPathAllowedCharacterSet]]]; - // TODO cipher params! _payloadEncoder = [ARTPayload defaultPayloadEncoder:cipherParams]; } return self; @@ -85,12 +88,15 @@ + (instancetype)channelWithRest:(ARTRest *)rest name:(NSString *)name cipherPara NSData *encodedMessage = [self.rest.defaultEncoder encodeMessage:message]; NSDictionary *headers = @{@"Content-Type":self.rest.defaultEncoding}; NSString *path = [NSString stringWithFormat:@"%@/messages", self.basePath]; - return [self.rest post:path headers:headers body:encodedMessage authenticated:YES cb:^(ARTHttpResponse *response) { + return [self.rest post:path headers:headers body:encodedMessage authenticated:ARTAuthenticationOn cb:^(ARTHttpResponse *response) { ARTStatus status = response.status >= 200 && response.status < 300 ? ARTStatusOk : ARTStatusError; cb(status); }]; } + + + - (id)publish:(id)payload cb:(ARTStatusCallback)cb { return [self publish:payload withName:nil cb:cb]; } @@ -167,10 +173,10 @@ - (instancetype)initWithOptions:(ARTOptions *)options { id defaultEncoder = [[ARTJsonEncoder alloc] init]; //msgpack not supported yet. - // id msgpackEncoder = [[ARTMsgPackEncoder alloc] init]; + //id msgpackEncoder = [[ARTMsgPackEncoder alloc] init]; _encoders = @{ [defaultEncoder mimeType]: defaultEncoder, - // [msgpackEncoder mimeType] : msgpackEncoder + //[msgpackEncoder mimeType] : msgpackEncoder }; _defaultEncoding = [defaultEncoder mimeType]; @@ -178,9 +184,36 @@ - (instancetype)initWithOptions:(ARTOptions *)options { return self; } +- (id) token:(ARTAuthTokenParams *) params tokenCb:(void (^)(ARTStatus status, ARTTokenDetails *)) cb { + NSString * keyPath = [NSString stringWithFormat:@"/keys/%@/requestToken",params.keyName]; + NSDictionary * paramsDict = [params asDictionary]; + + NSData * dictData = [NSJSONSerialization dataWithJSONObject:paramsDict options:0 error:nil]; + + NSDictionary *headers = @{@"Content-Type":self.defaultEncoding}; + return [self post:keyPath headers:headers body:dictData authenticated:ARTAuthenticationUseBasic cb:^(ARTHttpResponse *response) { + + NSString * str = [[NSString alloc] initWithData:response.body encoding:NSUTF8StringEncoding]; + [ARTLog verbose:[NSString stringWithFormat:@"ARTRest token is %@", str]]; + + if(response.status == 201) { + ARTTokenDetails * token =[self.defaultEncoder decodeAccessToken:response.body]; + cb(ARTStatusOk, token); + } + else { + + ARTHttpError * e = [self.defaultEncoder decodeError:response.body]; + [ARTLog error:[NSString stringWithFormat:@"ARTRest: requestToken Error code: %d, Status %d, Message %@", e.code, e.statusCode, e.message]]; + cb(ARTStatusError, nil); + + } + }]; +} + - (id)time:(void (^)(ARTStatus, NSDate *))cb { return [self get:@"/time" authenticated:NO cb:^(ARTHttpResponse *response) { NSDate *date = nil; + if (response.status == 200) { date = [self.defaultEncoder decodeTime:response.body]; } @@ -219,19 +252,20 @@ - (ARTRestChannel *)channel:(NSString *)channelName cipherParams:(ARTCipherParam return channel; } -- (id)makeRequestWithMethod:(NSString *)method relUrl:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(BOOL)authenticated cb:(ARTHttpCb)cb { +- (id)makeRequestWithMethod:(NSString *)method relUrl:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(ARTAuthentication)authenticated cb:(ARTHttpCb)cb { NSURL *url = [self resolveUrl:relUrl]; headers = [self withAcceptHeader:headers]; - if (authenticated) { - return [self withAuthHeaders:^(NSDictionary *authHeaders) { - NSMutableDictionary *allHeaders = [NSMutableDictionary dictionary]; - [allHeaders addEntriesFromDictionary:headers]; - [allHeaders addEntriesFromDictionary:authHeaders]; - return [self.http makeRequestWithMethod:method url:url headers:allHeaders body:body cb:cb]; - }]; - } else { + if (authenticated == ARTAuthenticationOff) { return [self.http makeRequestWithMethod:method url:url headers:headers body:body cb:cb]; + } else { + return [self withAuthHeadersUseBasic:(authenticated == ARTAuthenticationUseBasic) cb:^(NSDictionary *authHeaders) { + NSMutableDictionary *allHeaders = [NSMutableDictionary dictionary]; + [allHeaders addEntriesFromDictionary:headers]; + [allHeaders addEntriesFromDictionary:authHeaders]; + return [self.http makeRequestWithMethod:method url:url headers:allHeaders body:body cb:cb]; + }]; + } } @@ -293,12 +327,17 @@ - (NSURL *)resolveUrl:(NSString *)relUrl queryParams:(NSDictionary *)queryParams return [self makeRequestWithMethod:@"GET" relUrl:relUrl headers:headers body:nil authenticated:authenticated cb:cb]; } -- (id)post:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(BOOL)authenticated cb:(ARTHttpCb)cb { +- (id)post:(NSString *)relUrl headers:(NSDictionary *)headers body:(NSData *)body authenticated:(ARTAuthentication)authenticated cb:(ARTHttpCb)cb { return [self makeRequestWithMethod:@"POST" relUrl:relUrl headers:headers body:body authenticated:authenticated cb:cb]; } -- (id)withAuthHeaders:(id(^)(NSDictionary *))cb { - return [self.auth authHeaders:cb]; +- (id)withAuthHeaders:(id(^) + (NSDictionary *))cb { + return [self withAuthHeadersUseBasic:false cb:cb]; +} + +- (id)withAuthHeadersUseBasic:(BOOL) useBasic cb:(id(^)(NSDictionary *))cb { + return [self.auth authHeadersUseBasic:useBasic cb:cb]; } - (id)withAuthParams:(id(^)(NSDictionary *))cb { diff --git a/ably-ios/ARTWebSocketTransport.m b/ably-ios/ARTWebSocketTransport.m index e55795383..0878274aa 100644 --- a/ably-ios/ARTWebSocketTransport.m +++ b/ably-ios/ARTWebSocketTransport.m @@ -196,8 +196,8 @@ - (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error { if(error) { - //TODO maybe some errors become failed, and some become disconnect? - NSLog(@"websocket did fail with error %@", error); + //TODO maybe some errors become failed, and some become disconn + [ARTLog error:[NSString stringWithFormat:@"ARTWebSocketTransport: websocket did fail with error %@", error]]; } if(s) { diff --git a/ably-ios/Info.plist b/ably-ios/Info.plist index 2d288ff56..737195590 100644 --- a/ably-ios/Info.plist +++ b/ably-ios/Info.plist @@ -2,25 +2,25 @@ - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - com.ably.ably-ios.$(PRODUCT_NAME:rfc1034identifier) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - FMWK - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - $(CURRENT_PROJECT_VERSION) - NSPrincipalClass - + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.ably.ably-ios.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + diff --git a/ably-ios/ably-ios.h b/ably-ios/ably-ios.h index 98526033d..f2114aef7 100644 --- a/ably-ios/ably-ios.h +++ b/ably-ios/ably-ios.h @@ -15,5 +15,3 @@ FOUNDATION_EXPORT double ably_iosVersionNumber; FOUNDATION_EXPORT const unsigned char ably_iosVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import - - diff --git a/ably-iosTests/ARTHttpTest.m b/ably-iosTests/ARTHttpTest.m index add316a86..41be90096 100644 --- a/ably-iosTests/ARTHttpTest.m +++ b/ably-iosTests/ARTHttpTest.m @@ -29,10 +29,20 @@ - (void)tearDown { [super tearDown]; } +-(void) testPingGoogle { + XCTestExpectation *expectation = [self expectationWithDescription:@"get"]; + + [self.http makeRequestWithMethod:@"GET" url:[NSURL URLWithString:@"http://www.google.com"] headers:nil body:nil cb:^(ARTHttpResponse *response) { + XCTAssertEqual(response.status, 200); + [expectation fulfill]; + }]; + + [self waitForExpectationsWithTimeout:10.0 handler:nil]; +} - (void)testNonExistantPath { XCTestExpectation *expectation = [self expectationWithDescription:@"get"]; - [self.http makeRequestWithMethod:@"GET" url:[NSURL URLWithString:@"http://rest.ably.io/non-existant-path"] headers:nil body:nil cb:^(ARTHttpResponse *response) { + [self.http makeRequestWithMethod:@"GET" url:[NSURL URLWithString:@"http://rest.ably.io"] headers:nil body:nil cb:^(ARTHttpResponse *response) { XCTAssertEqual(response.status, 404); [expectation fulfill]; }]; diff --git a/ably-iosTests/ARTLogTest.m b/ably-iosTests/ARTLogTest.m index 0b622ee99..d1a12b524 100644 --- a/ably-iosTests/ARTLogTest.m +++ b/ably-iosTests/ARTLogTest.m @@ -16,18 +16,16 @@ @interface ARTLogTest : XCTestCase @implementation ARTLogTest - -(void) setUp { } -(void) tearDown { [ARTLog setLogCallback:nil]; + [ARTLog setLogLevel:ArtLogLevelWarn]; } - (void)testLogLevelToError { - // This is an example of a functional test case. - __block id lastLogged =nil; __block int logCount =0; [ARTLog setLogCallback:^(id message){ @@ -44,7 +42,7 @@ - (void)testLogLevelToError { XCTAssertEqual(logCount, 0); [ARTLog error:@"e"]; XCTAssertEqual(logCount, 1); - XCTAssertEqualObjects(lastLogged, @"e"); + XCTAssertEqualObjects(lastLogged, @"ERROR: e"); } -(void) testLogLevel { @@ -57,12 +55,12 @@ -(void) testLogLevel { [ARTLog setLogLevel:ArtLogLevelDebug]; [ARTLog verbose:@"v"]; [ARTLog debug:@"d"]; - XCTAssertEqualObjects(lastLogged, @"d"); + XCTAssertEqualObjects(lastLogged, @"DEBUG: d"); [ARTLog info:@"i"]; [ARTLog warn:@"w"]; [ARTLog error:@"e"]; XCTAssertEqual(logCount, 4); - XCTAssertEqualObjects(lastLogged, @"e"); + XCTAssertEqualObjects(lastLogged, @"ERROR: e"); } -(void) testLogLevelNone { @@ -75,7 +73,6 @@ -(void) testLogLevelNone { [ARTLog setLogLevel:ArtLogLevelNone]; [ARTLog verbose:@"v"]; [ARTLog debug:@"d"]; - [ARTLog info:@"i"]; [ARTLog warn:@"w"]; [ARTLog error:@"e"]; diff --git a/ably-iosTests/ARTRealtimeChannelTest.m b/ably-iosTests/ARTRealtimeChannelTest.m index 45530ac03..5e1c24581 100644 --- a/ably-iosTests/ARTRealtimeChannelTest.m +++ b/ably-iosTests/ARTRealtimeChannelTest.m @@ -152,36 +152,46 @@ - (void) testAttachDetachAttach { [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -/* -- (void)testSubscribeUnsubscribe{ + +- (void)testSubscribeUnsubscribe { - XCTFail(@"unsubscribe doent work. Even though this test passes"); - return; XCTestExpectation *expectation = [self expectationWithDescription:@"publish"]; + NSString * lostMessage = @"lost"; [self withRealtime:^(ARTRealtime *realtime) { ARTRealtimeChannel *channel = [realtime channel:@"test"]; - id subscription = [channel subscribe:^(ARTMessage *message) { + id __block subscription = [channel subscribe:^(ARTMessage *message) { if([[message content] isEqualToString:@"testString"]) { + [subscription unsubscribe]; - [channel publish:@"This should never arrive" cb:^(ARTStatus status) { + + [channel publish:lostMessage cb:^(ARTStatus status) { XCTAssertEqual(status, ARTStatusOk); }]; - [expectation fulfill]; } - else { + else if([[message content] isEqualToString:lostMessage]) { XCTFail(@"unsubscribe failed"); } - XCTAssertEqualObjects([message content], @"testString"); }]; + [channel publish:@"testString" cb:^(ARTStatus status) { XCTAssertEqual(ARTStatusOk, status); + NSString * finalMessage = @"final"; + [channel subscribe:^(ARTMessage * message) { + if([[message content] isEqualToString:finalMessage]) { + [expectation fulfill]; + } + }]; + [channel publish:finalMessage cb:^(ARTStatus status) { + XCTAssertEqual(ARTStatusOk, status); + }]; + }]; }]; [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } - */ + //TODO switch the keys over and confirm connection doesn't work. /* diff --git a/ably-iosTests/ARTRealtimeCryptoMessageTest.m b/ably-iosTests/ARTRealtimeCryptoMessageTest.m index 3d642459d..bb0382cb4 100644 --- a/ably-iosTests/ARTRealtimeCryptoMessageTest.m +++ b/ably-iosTests/ARTRealtimeCryptoMessageTest.m @@ -7,7 +7,10 @@ // #import #import - +#import "ARTTestUtil.h" +#import "ARTPayload.h" +#import "ARTPayload+Private.h" +#import "ARTLog.h" @interface ARTRealtimeCryptoMessageTest : XCTestCase @end @@ -16,34 +19,126 @@ @implementation ARTRealtimeCryptoMessageTest - (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) testCBCParser { + + NSArray * encoders = [ARTPayload parseEncodingChain:@"utf-8/cipher+aes-128-cbc/base64" + key:[[NSData alloc] initWithBase64EncodedString:@"WUP6u0K7MXI5Zeo0VppPwg==" options:0] + iv:[[NSData alloc] initWithBase64EncodedString:@"HO4cYSP8LybPYBPZPHQOtg==" options:0]]; + XCTAssertEqual([encoders count], 3); + id utf8 = [encoders objectAtIndex:0]; + id cipher128 = [encoders objectAtIndex:1]; + id base64 = [encoders objectAtIndex:2]; + XCTAssertEqualObjects([utf8 name], @"utf-8"); + XCTAssertEqualObjects([cipher128 name], @"cipher+aes-128-cbc"); + XCTAssertEqualObjects([base64 name], @"base64"); + + +} - -//TODO only 128 is implemented -/* -- (void)testEncrypt_128 { - XCTFail(@"TODO write test"); +-(void) testCBCParser256 { + + NSArray * encoders = [ARTPayload parseEncodingChain:@"utf-8/cipher+aes-256-cbc/base64" + key:[[NSData alloc] initWithBase64EncodedString:@"o9qXZoPGDNla50VnRwH7cGqIrpyagTxGsRgimKJbY40=" options:0] + iv:[[NSData alloc] initWithBase64EncodedString:@"HO4cYSP8LybPYBPZPHQOtg==" options:0]]; + XCTAssertEqual([encoders count], 3); + id utf8 = [encoders objectAtIndex:0]; + id cipher128 = [encoders objectAtIndex:1]; + id base64 = [encoders objectAtIndex:2]; + XCTAssertEqualObjects([utf8 name], @"utf-8"); + XCTAssertEqualObjects([cipher128 name], @"cipher+aes-256-cbc"); + XCTAssertEqualObjects([base64 name], @"base64"); + + } -- (void)testEncrypt_256 { - XCTFail(@"TODO write test"); + +-(void) testCaseByFileContents:(NSString *) str { + + NSData* data = [str dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary * topLevel =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; + NSString * key = [topLevel valueForKey:@"key"]; + NSString * iv = [topLevel valueForKey:@"iv"]; + NSArray * items = [topLevel valueForKey:@"items"]; + for(int i=0;i < [items count]; i++) { + + + NSDictionary * item = [items objectAtIndex:i]; + NSString * dataStr = [[item valueForKey:@"encoded"] valueForKey:@"data"]; + NSString * simpleEncoding = [[item valueForKey:@"encoded"] valueForKey:@"encoding"]; + if(!simpleEncoding) { + simpleEncoding = @""; + } + NSString * encData = [[item valueForKey:@"encrypted"] valueForKey:@"data"]; + NSString * encoding = [[item valueForKey:@"encrypted"] valueForKey:@"encoding"]; + + NSArray * encoders = [ARTPayload parseEncodingChain:encoding + key:[[NSData alloc] initWithBase64EncodedString:key options:0] + iv:[[NSData alloc] initWithBase64EncodedString:iv options:0]]; + + NSData * encodableData = [simpleEncoding isEqualToString:@"base64"] ? + [[NSData alloc] initWithBase64EncodedString:dataStr options:0] : [dataStr dataUsingEncoding:NSUTF8StringEncoding]; + + id encoderChain =[[ARTPayloadEncoderChain alloc] initWithEncoders:encoders]; + + //check encoded result matches the encoded string in the file + { + + ARTPayload * p = [[ARTPayload alloc] initWithPayload:encodableData encoding:encoding]; + ARTPayload * outputPayload = nil; + [encoderChain encode:p output:&outputPayload]; + XCTAssertEqualObjects(outputPayload.payload, encData); + } + + //check decoded result matches the decoded string in the file + { + ARTPayload * decP = [[ARTPayload alloc] initWithPayload:encData encoding:encoding]; + ARTPayload * decOutput = nil; + [encoderChain decode:decP output:&decOutput]; + + NSString * decodedStr = decOutput.payload; + if([simpleEncoding isEqualToString:@"base64"]) { + XCTAssertEqualObjects(decOutput.payload, encodableData); + } + else if([simpleEncoding isEqualToString:@"json"]) { + //we don't want to compare json as strings, but as arrays or dictionarys, so we encode and decode the json from the file. + ARTPayload * p =[[ARTPayload alloc] initWithPayload:encodableData encoding:@"json"]; + ARTJsonPayloadEncoder * e = [ARTJsonPayloadEncoder instance]; + ARTPayload* jsonOut = nil; + [e encode:p output:&jsonOut]; + ARTPayload * decodedEncoded = nil; + [e decode:jsonOut output:&decodedEncoded]; + if([decOutput.payload isKindOfClass:[NSDictionary class]]) { + NSDictionary * dictionary = [NSJSONSerialization JSONObjectWithData:decodedEncoded.payload options:0 error:nil]; + XCTAssertEqualObjects(dictionary, decOutput.payload); + } + else if([decOutput.payload isKindOfClass:[NSArray class]]) { + NSArray * array = [NSJSONSerialization JSONObjectWithData:decodedEncoded.payload options:0 error:nil]; + XCTAssertEqualObjects(array, decOutput.payload); + } + } + else { + XCTAssertEqualObjects(decodedStr, dataStr); + } + } + } } -- (void)testDecrypt_128 { - XCTFail(@"TODO write test"); + + +- (void)testEncrypt_128 { + [self testCaseByFileContents:[ARTTestUtil getCrypto128Json]]; } -- (void)testDecrypt_256 { - XCTFail(@"TODO write test"); +- (void)testEncrypt_256 { + [self testCaseByFileContents:[ARTTestUtil getCrypto256Json]]; } - */ + @end diff --git a/ably-iosTests/ARTRealtimeInitTest.m b/ably-iosTests/ARTRealtimeInitTest.m index 4a1fbdf21..7532479e5 100644 --- a/ably-iosTests/ARTRealtimeInitTest.m +++ b/ably-iosTests/ARTRealtimeInitTest.m @@ -98,7 +98,8 @@ -(void) testInitWithKey { XCTestExpectation *expectation = [self expectationWithDescription:@"initWithOptions"]; [self getBaseOptions:^(ARTOptions * options) { - NSString * key = [[options.authOptions.keyId stringByAppendingString:@":"] stringByAppendingString:options.authOptions.keyValue]; + NSString * key = [[options.authOptions.keyName + stringByAppendingString:@":"] stringByAppendingString:options.authOptions.keySecret]; ARTRealtime * r = [[ARTRealtime alloc] initWithKey:key]; [r subscribeToStateChanges:^(ARTRealtimeConnectionState state) { if(state == ARTRealtimeFailed) { //this doesnt try to connect to sandbox so will fail. diff --git a/ably-iosTests/ARTRealtimePresenceHistoryTest.m b/ably-iosTests/ARTRealtimePresenceHistoryTest.m index ffec2b1ed..b5978df31 100644 --- a/ably-iosTests/ARTRealtimePresenceHistoryTest.m +++ b/ably-iosTests/ARTRealtimePresenceHistoryTest.m @@ -14,7 +14,7 @@ #import "ARTRealtime.h" #import "ARTTestUtil.h" #import "ARTRest.h" - +#import "ARTLog.h" @interface ARTRealtimePresenceHistoryTest : XCTestCase { ARTRealtime * _realtime; diff --git a/ably-iosTests/ARTRealtimePresenceTest.m b/ably-iosTests/ARTRealtimePresenceTest.m index 718184346..268b6a497 100644 --- a/ably-iosTests/ARTRealtimePresenceTest.m +++ b/ably-iosTests/ARTRealtimePresenceTest.m @@ -102,7 +102,6 @@ -(void) testTwoConnections //TODO this is probably too wordy. -//enter_simple - (void)testEnterSimple { NSString * channelName = @"presTest"; @@ -211,7 +210,6 @@ - (void)testEnterBeforeConnect { [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//enter_leave_simple - (void)testEnterLeaveSimple { NSString * channelName = @"testEnterLeaveSimple"; NSString * presenceEnter = @"client_has_entered"; @@ -221,15 +219,13 @@ - (void)testEnterLeaveSimple { ARTRealtimeChannel *channel = [realtime channel:channelName]; [channel subscribeToPresence:^(ARTPresenceMessage * message) { - if(message.action == ARTPresenceMessageEnter) - { + if(message.action == ARTPresenceMessageEnter) { XCTAssertEqualObjects([message content], presenceEnter); [channel publishPresenceLeave:presenceLeave cb:^(ARTStatus status) { XCTAssertEqual(ARTStatusOk, status); }]; } - if(message.action == ARTPresenceMessageLeave) - { + if(message.action == ARTPresenceMessageLeave) { XCTAssertEqualObjects([message content], presenceLeave); [expectation fulfill]; } @@ -252,7 +248,6 @@ - (void)testEnterLeaveSimple { [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//enter_enter_simple -(void) testEnterEnter { NSString * channelName = @"testEnterLeaveSimple"; @@ -289,8 +284,6 @@ -(void) testEnterEnter [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } - -//enter_update_simple -(void) testEnterUpdateSimple { NSString * channelName = @"testEnterLeaveSimple"; @@ -326,6 +319,7 @@ -(void) testEnterUpdateSimple }]; [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } + -(void) testUpdateNull { NSString * channelName = @"testEnterLeaveSimple"; @@ -361,7 +355,6 @@ -(void) testUpdateNull [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//enter_leave_nodata -(void) testEnterLeaveWithoutData { NSString * channelName = @"testEnterLeaveSimple"; NSString * presenceEnter = @"client_has_entered"; @@ -399,7 +392,6 @@ -(void) testEnterLeaveWithoutData { [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//update_noenter -(void) testUpdateNoEnter { NSString * update = @"update_message"; @@ -433,7 +425,7 @@ -(void) testUpdateNoEnter }]; [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//enter_leave_nodata + -(void) testEnterLeaveNoData { NSString * enter = @"enter"; @@ -470,7 +462,6 @@ -(void) testEnterLeaveNoData [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//realtime_get_simple -(void) testEnterAndGet { NSString * enter = @"enter"; @@ -513,7 +504,6 @@ -(void) testEnterAndGet [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } -//realtime_get_leave -(void) testEnterLeaveAndGet { NSString * enter = @"enter"; diff --git a/ably-iosTests/ARTRestAppStatsTest.m b/ably-iosTests/ARTRestAppStatsTest.m index 9abf98e6b..33c60383e 100644 --- a/ably-iosTests/ARTRestAppStatsTest.m +++ b/ably-iosTests/ARTRestAppStatsTest.m @@ -14,7 +14,7 @@ #import "ARTRest.h" #import "ARTTestUtil.h" #import "ARTStats.h" -#import "NSDate+ARTUtil.h" +#import "ARTNSDate+ARTUtil.h" @interface ARTRestAppStatsTest : XCTestCase { ARTRest *_rest; } diff --git a/ably-iosTests/ARTRestCapabilityTest.m b/ably-iosTests/ARTRestCapabilityTest.m index bf7223b03..797531d5a 100644 --- a/ably-iosTests/ARTRestCapabilityTest.m +++ b/ably-iosTests/ARTRestCapabilityTest.m @@ -15,21 +15,14 @@ #import "ARTTestUtil.h" @interface ARTRestCapabilityTest : XCTestCase { ARTRest *_rest; - ARTOptions *_options; - float _timeout; } -- (void)withRest:(void(^)(ARTRest *))cb; - - @end @implementation ARTRestCapabilityTest - (void)setUp { [super setUp]; - _options = [[ARTOptions alloc] init]; - _options.restHost = @"sandbox-rest.ably.io"; } - (void)tearDown { @@ -37,9 +30,11 @@ - (void)tearDown { [super tearDown]; } + - (void)withRest:(void (^)(ARTRest *rest))cb { if (!_rest) { - [ARTTestUtil setupApp:_options cb:^(ARTOptions *options) { + ARTOptions * theOptions = [ARTTestUtil jsonRestOptions]; + [ARTTestUtil setupApp:theOptions cb:^(ARTOptions *options) { if (options) { _rest = [[ARTRest alloc] initWithOptions:options]; } @@ -50,11 +45,42 @@ - (void)withRest:(void (^)(ARTRest *rest))cb { cb(_rest); } -/* -//TODO write tests -- (void)testAuthBlanket { - XCTFail(@"TODO write test"); +- (void)withRestRestrictCap:(void (^)(ARTRest *rest))cb { + if (!_rest) { + ARTOptions * theOptions = [ARTTestUtil jsonRestOptions]; + [ARTTestUtil setupApp:theOptions withAlteration:TestAlterationRestrictCapability cb:^(ARTOptions *options) { + if (options) { + options.authOptions.useTokenAuth = true; + options.authOptions.clientId = @"clientId"; + _rest = [[ARTRest alloc] initWithOptions:options]; + } + cb(_rest); + }]; + return; + } + cb(_rest); +} + + +- (void)testPublishRestriced { + XCTestExpectation *expectation = [self expectationWithDescription:@"testSimpleDisconnected"]; + [self withRestRestrictCap:^(ARTRest * rest) { + ARTRestChannel * channel = [rest channel:@"canpublish:test"]; + [channel publish:@"publish" cb:^(ARTStatus status) { + XCTAssertEqual(status, ARTStatusOk); + ARTRestChannel * channel2 = [rest channel:@"cannotPublishToThisChannelName"]; + [channel2 publish:@"publish" cb:^(ARTStatus status) { + XCTAssertEqual(status, ARTStatusError); + [expectation fulfill]; + + }]; + + }]; + }]; + [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; } + +/* - (void)testAuthEqual { XCTFail(@"TODO write test"); } diff --git a/ably-iosTests/ARTRestPresenceTest.m b/ably-iosTests/ARTRestPresenceTest.m index d8c2efdbf..2e9f0e7f8 100644 --- a/ably-iosTests/ARTRestPresenceTest.m +++ b/ably-iosTests/ARTRestPresenceTest.m @@ -49,8 +49,8 @@ - (void)withRest:(void (^)(ARTRest *rest))cb { } cb(_rest); } - - (void)testPresence { + XCTestExpectation *expectation = [self expectationWithDescription:@"testPresence"]; [self withRest:^(ARTRest *rest) { ARTRestChannel *channel = [rest channel:@"persisted:presence_fixtures"]; @@ -62,28 +62,38 @@ - (void)testPresence { return; } NSArray *presence = [result currentItems]; - XCTAssertEqual(4, presence.count); + + + XCTAssertEqual(6, [presence count]); ARTPresenceMessage *p0 = presence[0]; - ARTPresenceMessage *p1 = presence[1]; - ARTPresenceMessage *p2 = presence[2]; +// ARTPresenceMessage *p1 = presence[1]; +// ARTPresenceMessage *p2 = presence[2]; ARTPresenceMessage *p3 = presence[3]; + ARTPresenceMessage *p4 = presence[4]; + ARTPresenceMessage *p5 = presence[5]; - // This is assuming the results are coming back sorted by clientId - // in alphabetical order. This seems to be the case at the time of - // writing, but may change in the future - XCTAssertEqualObjects(@"client_bool", p0.clientId); XCTAssertEqualObjects(@"true", [p0 content]); - XCTAssertEqualObjects(@"client_int", p1.clientId); - XCTAssertEqualObjects(@"24", [p1 content]); - XCTAssertEqualObjects(@"client_json", p2.clientId); - XCTAssertEqualObjects(@"{\"test\":\"This is a JSONObject clientData payload\"}", [p2 content]); + //TODO use ARTTestUtil cipher and check they match up. + /* + XCTAssertEqualObjects(@"client_decoded", p1.clientId); + XCTAssertEqualObjects([p1 content], @"{\"example\":{\"json\":\"Object\"}}"); + + XCTAssertEqualObjects(@"client_encoded", p2.clientId); + XCTAssertEqualObjects([p2 content], @"HO4cYSP8LybPYBPZPHQOtuD53yrD3YV3NBoTEYBh4U0N1QXHbtkfsDfTspKeLQFt"); + */ + + XCTAssertEqualObjects(@"client_int", p3.clientId); + XCTAssertEqualObjects(@"24", [p3 content]); + + XCTAssertEqualObjects(@"client_json", p4.clientId); + XCTAssertEqualObjects(@"{ \"test\": \"This is a JSONObject clientData payload\"}", [p4 content]); - XCTAssertEqualObjects(@"client_string", p3.clientId); - XCTAssertEqualObjects(@"This is a string clientData payload", [p3 content]); + XCTAssertEqualObjects(@"client_string", p5.clientId); + XCTAssertEqualObjects(@"This is a string clientData payload", [p5 content]); [expectation fulfill]; @@ -105,7 +115,7 @@ - (void)testHistory { return; } NSArray *presence = [result currentItems]; - XCTAssertEqual(4, presence.count); + XCTAssertEqual(6, [presence count]); [expectation fulfill]; }]; diff --git a/ably-iosTests/ARTRestTimeTest.m b/ably-iosTests/ARTRestTimeTest.m index f6d788a53..7778d9672 100644 --- a/ably-iosTests/ARTRestTimeTest.m +++ b/ably-iosTests/ARTRestTimeTest.m @@ -16,7 +16,6 @@ @interface ARTRestTimeTest : XCTestCase { ARTRest *_rest; - float _timeout; } - (void)withRest:(void(^)(ARTRest *))cb; @@ -48,7 +47,6 @@ - (void)withRest:(void (^)(ARTRest *rest))cb { cb(_rest); } -/** ARTRESTTIMETEST **/ - (void)testRestTimeBadHost { __weak XCTestExpectation *expectationRestTimeBadHost = [self expectationWithDescription:@"testRestTimeBadHost"]; diff --git a/ably-iosTests/ARTRestTokenTest.m b/ably-iosTests/ARTRestTokenTest.m index 57350a5a4..50c26d5ce 100644 --- a/ably-iosTests/ARTRestTokenTest.m +++ b/ably-iosTests/ARTRestTokenTest.m @@ -13,10 +13,10 @@ #import "ARTPresenceMessage.h" #import "ARTRest.h" #import "ARTTestUtil.h" +#import "ARTRest+Private.h" +#import "ARTLog.h" @interface ARTRestTokenTest : XCTestCase { ARTRest *_rest; - ARTOptions *_options; - float _timeout; } - (void)withRest:(void(^)(ARTRest *))cb; @@ -24,22 +24,23 @@ - (void)withRest:(void(^)(ARTRest *))cb; @end + @implementation ARTRestTokenTest - (void)setUp { + [ARTLog setLogLevel:ArtLogLevelVerbose]; [super setUp]; - _options = [[ARTOptions alloc] init]; - _options.restHost = @"sandbox-rest.ably.io"; } - (void)tearDown { + [ARTLog setLogLevel:ArtLogLevelWarn]; _rest = nil; [super tearDown]; } - (void)withRest:(void (^)(ARTRest *rest))cb { if (!_rest) { - [ARTTestUtil setupApp:_options cb:^(ARTOptions *options) { + [ARTTestUtil setupApp:[ARTTestUtil jsonRestOptions] cb:^(ARTOptions *options) { if (options) { _rest = [[ARTRest alloc] initWithOptions:options]; } @@ -49,6 +50,29 @@ - (void)withRest:(void (^)(ARTRest *rest))cb { } cb(_rest); } + +- (void)testTokenSimple{ + XCTestExpectation *expectation = [self expectationWithDescription:@"testRestTimeBadHost"]; + + [ARTTestUtil setupApp:[ARTTestUtil jsonRestOptions] cb:^(ARTOptions *options) { + options.authOptions.useTokenAuth = true; + options.authOptions.clientId = @"testToken"; + ARTRest * rest = [[ARTRest alloc] initWithOptions:options]; + + ARTAuth * auth = rest.auth; + ARTAuthMethod authMethod = [auth getAuthMethod]; + XCTAssertEqual(authMethod, ARTAuthMethodToken); + ARTRestChannel * c= [rest channel:@"getChannel"]; + [c publish:@"something" cb:^(ARTStatus status) { + XCTAssertEqual(status, ARTStatusOk); + [expectation fulfill]; + + }]; + }]; + + [self waitForExpectationsWithTimeout:[ARTTestUtil timeout] handler:nil]; +} + /* //TODO implement diff --git a/ably-iosTests/ARTTestUtil.h b/ably-iosTests/ARTTestUtil.h index 725c44c2b..24b7b4ecb 100644 --- a/ably-iosTests/ARTTestUtil.h +++ b/ably-iosTests/ARTTestUtil.h @@ -12,7 +12,7 @@ @class ARTRestChannel; @class XCTestExpectation; @class ARTRealtimeChannel; - +@class ARTCipherPayloadEncoder; @interface ARTTestUtil : NSObject @@ -23,12 +23,15 @@ typedef NS_ENUM(NSUInteger, TestAlteration) { TestAlterationNone, TestAlterationBadKeyId, TestAlterationBadKeyValue, - TestAlterationBadWsHost + TestAlterationBadWsHost, + TestAlterationRestrictCapability }; ++(ARTCipherPayloadEncoder *) getTestCipherEncoder; + + (void)setupApp:(ARTOptions *)options cb:(void(^)(ARTOptions *options))cb; -+(void) setupApp:(ARTOptions *)options withAlteration:(TestAlteration) alt cb:(void (^)(ARTOptions *))cb; ++ (void) setupApp:(ARTOptions *)options withAlteration:(TestAlteration) alt cb:(void (^)(ARTOptions *))cb; + (NSString *) restHost; + (NSString *) realtimeHost; + (float) timeout; @@ -51,7 +54,10 @@ typedef NS_ENUM(NSUInteger, TestAlteration) { +(void) publishRealtimeMessages:(NSString *) prefix count:(int) count channel:(ARTRealtimeChannel *) channel expectation:(XCTestExpectation *) expectation; - ++(NSString *) getCrypto128Json; ++(NSString *) getTestAppSetupJson; ++(NSString *) getCrypto256Json; ++(NSString *) getErrorsJson; @end diff --git a/ably-iosTests/ARTTestUtil.m b/ably-iosTests/ARTTestUtil.m index da4eea34e..6566b2791 100644 --- a/ably-iosTests/ARTTestUtil.m +++ b/ably-iosTests/ARTTestUtil.m @@ -10,58 +10,52 @@ #import "ARTRest.h" #import "ARTRealtime.h" +#import "ARTLog.h" #import +#import "ARTPayload.h" + @implementation ARTTestUtil ++(ARTCipherPayloadEncoder *) getTestCipherEncoder { + ARTCipherPayloadEncoder * e = nil; + return e; +} -+(NSString *) getTestAppString { - - NSString * path = [[NSBundle mainBundle] pathForResource:@"test-app-setup" - ofType:@"json"]; - NSString* content = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding - error:NULL]; ++(NSString *) getFileByName:(NSString *) name { + NSString * path =[[[[NSBundle bundleForClass: [self class]] resourcePath] stringByAppendingString:@"/"] stringByAppendingString:name]; + return [NSString stringWithContentsOfFile:path + encoding:NSUTF8StringEncoding + error:NULL]; +} + ++(NSString *) getErrorsJson { + return [ARTTestUtil getFileByName:@"ably-common/test-resources/errors.json"]; +} + ++(NSString *) getCrypto256Json { - return content; + return [ARTTestUtil getFileByName:@"ably-common/test-resources/crypto-data-256.json"]; +} ++(NSString *) getTestAppSetupJson { + return [ARTTestUtil getFileByName:@"ably-common/test-resources/test-app-setup.json"]; } + ++(NSString *) getCrypto128Json { + return [ARTTestUtil getFileByName:@"ably-common/test-resources/crypto-data-128.json"]; +} + +(void) setupApp:(ARTOptions *)options withAlteration:(TestAlteration) alt appId:(NSString *) appId cb:(void (^)(ARTOptions *))cb { + NSString * str = [ARTTestUtil getTestAppSetupJson]; + NSData *data = [str dataUsingEncoding:NSUTF8StringEncoding]; + NSDictionary * topLevel =[NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers error:nil]; - //NSString * str = [ARTTestUtil getTestAppString]; - // NSLog(@" STRRR IS %@", str); - NSDictionary *capability = @{ - @"cansubscribe:*":@[@"subscribe"], - @"canpublish:*":@[@"publish"], - @"canpublish:andpresence":@[@"presence",@"publish"] - }; - - NSString *capabilityString = [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:capability options:0 error:nil] encoding:NSUTF8StringEncoding]; - - NSDictionary *appSpec = @{ - @"keys": @[ - @{}, - @{@"capability":capabilityString} - ], - @"namespaces": @[ - @{@"id": @"persisted", @"persisted":[NSNumber numberWithBool:YES]} - ], - @"channels": @[ - @{ - @"name": @"persisted:presence_fixtures", - @"presence": @[ - @{@"clientId": @"client_bool", @"data": @"true"}, - @{@"clientId": @"client_int", @"data":@"24"}, - @{@"clientId": @"client_string", @"data":@"This is a string clientData payload"}, - @{@"clientId": @"client_json", @"data":@"{\"test\":\"This is a JSONObject clientData payload\"}"} - ] - } - ] - }; - - NSData *appSpecData = [NSJSONSerialization dataWithJSONObject:appSpec options:0 error:nil]; - //NSLog(@" setupApp: %@", [[NSString alloc] initWithData:appSpecData encoding:NSUTF8StringEncoding]); + NSDictionary * d = [topLevel objectForKey:@"post_apps"]; + NSData *appSpecData = [NSJSONSerialization dataWithJSONObject:d options:0 error:nil]; +// NSLog(@" setupApp: %@", [[NSString alloc] initWithData:appSpecData encoding:NSUTF8StringEncoding]); if(alt ==TestAlterationBadWsHost) @@ -73,19 +67,18 @@ +(void) setupApp:(ARTOptions *)options withAlteration:(TestAlteration) alt appI NSMutableURLRequest *req = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:urlStr]]; req.HTTPMethod = @"POST"; req.HTTPBody = appSpecData; - if(false ||options.binary) { //msgpack not implemented yet + + /*if(false ||options.binary) { //msgpack not implemented yet [req setValue:@"application/x-msgpack,application/json" forHTTPHeaderField:@"Accept"]; [req setValue:@"application/x-msgpack" forHTTPHeaderField:@"Content-Type"]; - } - else { + else */ + { [req setValue:@"application/json" forHTTPHeaderField:@"Accept"]; [req setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; - - } - // NSLog(@"Creating test app. URL: %@, Method: %@, Body: %@, Headers: %@", req.URL, req.HTTPMethod, [[NSString alloc] initWithData:req.HTTPBody encoding:NSUTF8StringEncoding], req.allHTTPHeaderFields); + // NSLog(@"Creating test app. URL: %@, Method: %@, Body: %@, Headers: %@", req.URL, req.HTTPMethod, [[NSString alloc] initWithData:req.HTTPBody encoding:NSUTF8StringEncoding], req.allHTTPHeaderFields); CFRunLoopRef rl = CFRunLoopGetCurrent(); @@ -94,35 +87,36 @@ +(void) setupApp:(ARTOptions *)options withAlteration:(TestAlteration) alt appI NSURLSessionDataTask *task = [urlSession dataTaskWithRequest:req completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response; - NSString *keyId; - NSString *keyValue; + NSString *keyName; + NSString *keySecret; + NSString * capability; if (httpResponse.statusCode < 200 || httpResponse.statusCode >= 300) { - //NSLog(@"Status Code: %ld", (long)httpResponse.statusCode); - //NSLog(@"Body: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); + NSLog(@"Status Code: %ld", (long)httpResponse.statusCode); + NSLog(@"Body: %@", [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]); cb(nil); return; } else { NSDictionary *response = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil]; - if (response) { - NSDictionary *key = response[@"keys"][0]; - keyId = [NSString stringWithFormat:@"%@.%@", response[@"appId"], key[@"id"]]; - - keyValue = key[@"value"]; + NSDictionary *key = response[@"keys"][(alt == TestAlterationRestrictCapability ? 1 :0)]; + keyName = [NSString stringWithFormat:@"%@.%@", response[@"appId"], key[@"id"]]; + keySecret = key[@"value"]; + capability = key[@"capability"]; } } ARTOptions *appOptions = [options clone]; - - appOptions.authOptions.keyId = keyId; - appOptions.authOptions.keyValue = keyValue; + appOptions.authOptions.keyName = keyName; + appOptions.authOptions.keySecret = keySecret; + appOptions.authOptions.capability =capability; + if(alt == TestAlterationBadKeyId) { - appOptions.authOptions.keyId= @"badKeyId"; + appOptions.authOptions.keyName= @"badKeyName"; } else if(alt == TestAlterationBadKeyValue) { - appOptions.authOptions.keyValue = @"badKeyValue"; + appOptions.authOptions.keySecret = @"badKeySecret"; } CFRunLoopPerformBlock(rl, kCFRunLoopDefaultMode, ^{ @@ -131,12 +125,10 @@ +(void) setupApp:(ARTOptions *)options withAlteration:(TestAlteration) alt appI CFRunLoopWakeUp(rl); }]; [task resume]; - } -+(NSString *) appIdFromkeyId:(NSString *) keyId -{ - NSArray *array = [keyId componentsSeparatedByString:@"."]; ++(NSString *) appIdFromkeyName:(NSString *) keyName { + NSArray *array = [keyName componentsSeparatedByString:@"."]; return [array objectAtIndex:0]; } @@ -148,34 +140,29 @@ + (void)setupApp:(ARTOptions *)options cb:(void (^)(ARTOptions *))cb { [ARTTestUtil setupApp:options withAlteration:TestAlterationNone cb:cb]; } -+ (NSString *) realtimeHost -{ ++ (NSString *) realtimeHost { return @"sandbox-realtime.ably.io"; } -+ (NSString *) restHost -{ ++ (NSString *) restHost { return @"sandbox-rest.ably.io"; } -+(ARTOptions *) binaryRestOptions -{ ++(ARTOptions *) binaryRestOptions { ARTOptions * json = [[ARTOptions alloc] init]; json.restHost = [ARTTestUtil restHost]; json.binary =true; return json; } -+(ARTOptions *) jsonRestOptions -{ ++(ARTOptions *) jsonRestOptions { ARTOptions * json = [[ARTOptions alloc] init]; json.restHost = [ARTTestUtil restHost]; json.binary =false; return json; } -+(ARTOptions *) jsonRealtimeOptions -{ ++(ARTOptions *) jsonRealtimeOptions { ARTOptions * json = [[ARTOptions alloc] init]; [json setRealtimeHost:[ARTTestUtil realtimeHost] withRestHost:[ARTTestUtil restHost]]; @@ -184,8 +171,7 @@ +(ARTOptions *) jsonRealtimeOptions return json; } -+(ARTOptions *) binaryRealtimeOptions -{ ++(ARTOptions *) binaryRealtimeOptions { ARTOptions * json = [[ARTOptions alloc] init]; [json setRealtimeHost:[ARTTestUtil realtimeHost] withRestHost:[ARTTestUtil restHost]]; @@ -208,24 +194,20 @@ + (void)repeat:(int)count i:(int)i delay:(NSTimeInterval)delay block:(void (^)(i }); } -+(long long) nowMilli -{ ++(long long) nowMilli { NSDate * date = [NSDate date]; return [date timeIntervalSince1970]*1000; } -+(float) smallSleep -{ ++(float) smallSleep { return 0.6; } -+(float) bigSleep -{ ++(float) bigSleep { return 1.0; } -+(float) timeout -{ ++(float) timeout { return 30.0; } diff --git a/ably-iosTests/Info.plist b/ably-iosTests/Info.plist index da3f5cbf4..3145559a5 100644 --- a/ably-iosTests/Info.plist +++ b/ably-iosTests/Info.plist @@ -2,23 +2,23 @@ - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - com.ably.ably-ios.$(PRODUCT_NAME:rfc1034identifier) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + com.ably.ably-ios.$(PRODUCT_NAME:rfc1034identifier) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + BNDL + CFBundleShortVersionString + 1.0 + CFBundleSignature + ???? + CFBundleVersion + 1 diff --git a/ably.podspec b/ably.podspec new file mode 100644 index 000000000..ae3c6c217 --- /dev/null +++ b/ably.podspec @@ -0,0 +1,22 @@ +# +# Be sure to run `pod lib lint ably.podspec' to ensure this is a +# valid spec and remove all comments before submitting the spec. +# +# Any lines starting with a # are optional, but encouraged +# +# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html +# + +Pod::Spec.new do |s| + s.name = "ably" + s.version = "0.7.0" + s.summary = "iOS client for Ably: A highly scalable, superfast and secure hosted real-time messaging service" + s.homepage = "https://www.ably.io" + s.license = 'MIT' + s.author = { "Vic Zaccarelli" => "victorzaccarelli@gmail.com" } + s.source = { :git => "https://github.com/ably/ably-ios.git", :tag => s.version.to_s } + s.platform = :ios, '8.0' + s.requires_arc = true + s.source_files = 'ably-ios/*.{h,m}' + s.dependency 'SocketRocket', '~> 0.3.1-beta2' +end diff --git a/ably.xcodeproj/project.pbxproj b/ably.xcodeproj/project.pbxproj index d233acb94..b3f7e3901 100644 --- a/ably.xcodeproj/project.pbxproj +++ b/ably.xcodeproj/project.pbxproj @@ -6,23 +6,15 @@ objectVersion = 46; objects = { -/* Begin PBXAggregateTarget section */ - 1C1EC3FB1AE2737800AAADD7 /* ablyaggregate */ = { - isa = PBXAggregateTarget; - buildConfigurationList = 1C1EC3FC1AE2737800AAADD7 /* Build configuration list for PBXAggregateTarget "ablyaggregate" */; - buildPhases = ( - 1C1EC43D1AE454DC00AAADD7 /* ShellScript */, - ); - dependencies = ( - 1C1EC4001AE273FB00AAADD7 /* PBXTargetDependency */, - ); - name = ablyaggregate; - productName = ablyaggregate; - }; -/* End PBXAggregateTarget section */ - /* Begin PBXBuildFile section */ 1C05CF201AC1D7EB00687AC9 /* ARTRealtime+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C05CF1E1AC1D7EB00687AC9 /* ARTRealtime+Private.h */; }; + 1C118A5A1AE63D58006AD19E /* ably-ios.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C118A591AE63D58006AD19E /* ably-ios.h */; }; + 1C118A5C1AE63D89006AD19E /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1C118A5B1AE63D89006AD19E /* Info.plist */; }; + 1C118A5D1AE63D89006AD19E /* Info.plist in Resources */ = {isa = PBXBuildFile; fileRef = 1C118A5B1AE63D89006AD19E /* Info.plist */; }; + 1C118AB81AE6485C006AD19E /* ably-common in Resources */ = {isa = PBXBuildFile; fileRef = 1C118AB61AE6485C006AD19E /* ably-common */; }; + 1C118AB91AE6490B006AD19E /* ably-common in Copy Files */ = {isa = PBXBuildFile; fileRef = 1C118AB61AE6485C006AD19E /* ably-common */; }; + 1C118ABB1AE64923006AD19E /* ably-common in Copy Files */ = {isa = PBXBuildFile; fileRef = 1C118AB61AE6485C006AD19E /* ably-common */; }; + 1C118ABC1AE64D96006AD19E /* ably-common in Resources */ = {isa = PBXBuildFile; fileRef = 1C118AB61AE6485C006AD19E /* ably-common */; }; 1C1E52EA1AB32EA0004A690F /* ARTRestAppStatsTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C1E52E91AB32EA0004A690F /* ARTRestAppStatsTest.m */; }; 1C1E52EE1AB32EB9004A690F /* ARTRestCapabilityTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C1E52ED1AB32EB9004A690F /* ARTRestCapabilityTest.m */; }; 1C1E52F01AB32EC7004A690F /* ARTRestChannelHistoryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C1E52EF1AB32EC7004A690F /* ARTRestChannelHistoryTest.m */; }; @@ -36,12 +28,8 @@ 1C5DA0151A6E5FA400A2B7EF /* ably.framework in Copy Files */ = {isa = PBXBuildFile; fileRef = 96BF61311A35B2AB004CF2B3 /* ably.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; 1C6C18A31ADFDAB100AB79E4 /* ARTLog.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C6C18A11ADFDAB100AB79E4 /* ARTLog.h */; }; 1C6C18A41ADFDAB100AB79E4 /* ARTLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6C18A21ADFDAB100AB79E4 /* ARTLog.m */; }; - 1C6C18A51ADFDAB100AB79E4 /* ARTLog.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6C18A21ADFDAB100AB79E4 /* ARTLog.m */; }; 1C6C18A71ADFDDBA00AB79E4 /* ARTLogTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1C6C18A61ADFDDBA00AB79E4 /* ARTLogTest.m */; }; - 1C75E9F31AE0165100B2892A /* errors.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C75E9EE1AE0165100B2892A /* errors.json */; }; - 1C75E9F41AE0165100B2892A /* crypto-data-128.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C75E9F01AE0165100B2892A /* crypto-data-128.json */; }; - 1C75E9F51AE0165100B2892A /* crypto-data-256.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C75E9F11AE0165100B2892A /* crypto-data-256.json */; }; - 1C75E9F61AE0165100B2892A /* test-app-setup.json in Resources */ = {isa = PBXBuildFile; fileRef = 1C75E9F21AE0165100B2892A /* test-app-setup.json */; }; + 1C8065051AE7C8FA00D49357 /* ARTPayload+Private.h in Headers */ = {isa = PBXBuildFile; fileRef = 1C8065041AE7C8FA00D49357 /* ARTPayload+Private.h */; }; 1CA5E1C21AB72369006ADD70 /* ARTMsgPackEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 1CA5E1C01AB72369006ADD70 /* ARTMsgPackEncoder.h */; }; 1CA5E1C31AB72369006ADD70 /* ARTMsgPackEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CA5E1C11AB72369006ADD70 /* ARTMsgPackEncoder.m */; }; 1CC3D94B1AB6FBB60005BEB0 /* ARTRealtimeChannelHistoryTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 1CC3D94A1AB6FBB60005BEB0 /* ARTRealtimeChannelHistoryTest.m */; }; @@ -62,8 +50,8 @@ 961343D91A42E0B7006DC822 /* ARTOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 961343D71A42E0B7006DC822 /* ARTOptions.m */; }; 961343E81A432E7C006DC822 /* ARTPayload.h in Headers */ = {isa = PBXBuildFile; fileRef = 961343E61A432E7C006DC822 /* ARTPayload.h */; settings = {ATTRIBUTES = (Public, ); }; }; 961343E91A432E7C006DC822 /* ARTPayload.m in Sources */ = {isa = PBXBuildFile; fileRef = 961343E71A432E7C006DC822 /* ARTPayload.m */; }; - 967A43211A39AEAF00E4CE23 /* NSArray+ARTFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = 967A431F1A39AEAF00E4CE23 /* NSArray+ARTFunctional.h */; }; - 967A43221A39AEAF00E4CE23 /* NSArray+ARTFunctional.m in Sources */ = {isa = PBXBuildFile; fileRef = 967A43201A39AEAF00E4CE23 /* NSArray+ARTFunctional.m */; }; + 967A43211A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.h in Headers */ = {isa = PBXBuildFile; fileRef = 967A431F1A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.h */; }; + 967A43221A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.m in Sources */ = {isa = PBXBuildFile; fileRef = 967A43201A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.m */; }; 96A507951A370F860077CDF8 /* ARTStats.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507931A370F860077CDF8 /* ARTStats.h */; }; 96A507961A370F860077CDF8 /* ARTStats.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507941A370F860077CDF8 /* ARTStats.m */; }; 96A507991A371E910077CDF8 /* ARTPaginatedResult.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507971A371E910077CDF8 /* ARTPaginatedResult.h */; settings = {ATTRIBUTES = (Public, ); }; }; @@ -71,16 +59,15 @@ 96A5079E1A371F800077CDF8 /* ARTHttpPaginatedResult.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A5079C1A371F800077CDF8 /* ARTHttpPaginatedResult.m */; }; 96A507A11A377AA50077CDF8 /* ARTPresenceMessage.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A5079F1A377AA50077CDF8 /* ARTPresenceMessage.h */; settings = {ATTRIBUTES = (Public, ); }; }; 96A507A21A377AA50077CDF8 /* ARTPresenceMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507A01A377AA50077CDF8 /* ARTPresenceMessage.m */; }; - 96A507A51A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507A31A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.h */; }; - 96A507A61A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507A41A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.m */; }; + 96A507A51A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507A31A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.h */; }; + 96A507A61A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507A41A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.m */; }; 96A507A91A37806A0077CDF8 /* ARTEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507A71A37806A0077CDF8 /* ARTEncoder.h */; }; 96A507AD1A3780F60077CDF8 /* ARTJsonEncoder.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507AB1A3780F60077CDF8 /* ARTJsonEncoder.h */; }; 96A507AE1A3780F60077CDF8 /* ARTJsonEncoder.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507AC1A3780F60077CDF8 /* ARTJsonEncoder.m */; }; - 96A507B51A37881C0077CDF8 /* NSDate+ARTUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507B31A37881C0077CDF8 /* NSDate+ARTUtil.h */; }; - 96A507B61A37881C0077CDF8 /* NSDate+ARTUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507B41A37881C0077CDF8 /* NSDate+ARTUtil.m */; }; + 96A507B51A37881C0077CDF8 /* ARTNSDate+ARTUtil.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507B31A37881C0077CDF8 /* ARTNSDate+ARTUtil.h */; }; + 96A507B61A37881C0077CDF8 /* ARTNSDate+ARTUtil.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507B41A37881C0077CDF8 /* ARTNSDate+ARTUtil.m */; }; 96A507BD1A3791490077CDF8 /* ARTRealtime.h in Headers */ = {isa = PBXBuildFile; fileRef = 96A507BB1A3791490077CDF8 /* ARTRealtime.h */; settings = {ATTRIBUTES = (Public, ); }; }; 96A507BE1A3791490077CDF8 /* ARTRealtime.m in Sources */ = {isa = PBXBuildFile; fileRef = 96A507BC1A3791490077CDF8 /* ARTRealtime.m */; }; - 96BF61371A35B2AB004CF2B3 /* ably-ios.h in Headers */ = {isa = PBXBuildFile; fileRef = 96BF61361A35B2AB004CF2B3 /* ably-ios.h */; settings = {ATTRIBUTES = (Public, ); }; }; 96BF613D1A35B2AB004CF2B3 /* ably.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 96BF61311A35B2AB004CF2B3 /* ably.framework */; }; 96BF61531A35B39C004CF2B3 /* ARTRest.h in Headers */ = {isa = PBXBuildFile; fileRef = 96BF61511A35B39C004CF2B3 /* ARTRest.h */; settings = {ATTRIBUTES = (Public, ); }; }; 96BF61541A35B39C004CF2B3 /* ARTRest.m in Sources */ = {isa = PBXBuildFile; fileRef = 96BF61521A35B39C004CF2B3 /* ARTRest.m */; }; @@ -115,13 +102,6 @@ /* End PBXBuildRule section */ /* Begin PBXContainerItemProxy section */ - 1C1EC3FF1AE273FB00AAADD7 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 96BF61281A35B2AB004CF2B3 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 96BF61301A35B2AB004CF2B3; - remoteInfo = ably; - }; 96BF613E1A35B2AB004CF2B3 /* PBXContainerItemProxy */ = { isa = PBXContainerItemProxy; containerPortal = 96BF61281A35B2AB004CF2B3 /* Project object */; @@ -132,12 +112,24 @@ /* End PBXContainerItemProxy section */ /* Begin PBXCopyFilesBuildPhase section */ + 1C118ABA1AE64919006AD19E /* Copy Files */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 7; + files = ( + 1C118ABB1AE64923006AD19E /* ably-common in Copy Files */, + ); + name = "Copy Files"; + runOnlyForDeploymentPostprocessing = 0; + }; 1C5DA0141A6E5F8A00A2B7EF /* Copy Files */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; dstPath = ""; dstSubfolderSpec = 10; files = ( + 1C118AB91AE6490B006AD19E /* ably-common in Copy Files */, 1C5DA0151A6E5FA400A2B7EF /* ably.framework in Copy Files */, ); name = "Copy Files"; @@ -149,6 +141,9 @@ 143713CCCD056BDB4C1E070F /* Pods.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.debug.xcconfig; path = "Pods/Target Support Files/Pods/Pods.debug.xcconfig"; sourceTree = ""; }; 1BD00ABE249D4232EB2E44FA /* Pods.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = Pods.release.xcconfig; path = "Pods/Target Support Files/Pods/Pods.release.xcconfig"; sourceTree = ""; }; 1C05CF1E1AC1D7EB00687AC9 /* ARTRealtime+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTRealtime+Private.h"; sourceTree = ""; }; + 1C118A591AE63D58006AD19E /* ably-ios.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ably-ios.h"; sourceTree = ""; }; + 1C118A5B1AE63D89006AD19E /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 1C118AB61AE6485C006AD19E /* ably-common */ = {isa = PBXFileReference; lastKnownFileType = folder; name = "ably-common"; path = "../ably-common"; sourceTree = ""; }; 1C1E52E91AB32EA0004A690F /* ARTRestAppStatsTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestAppStatsTest.m; sourceTree = ""; }; 1C1E52ED1AB32EB9004A690F /* ARTRestCapabilityTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestCapabilityTest.m; sourceTree = ""; }; 1C1E52EF1AB32EC7004A690F /* ARTRestChannelHistoryTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestChannelHistoryTest.m; sourceTree = ""; }; @@ -158,17 +153,10 @@ 1C1E52F71AB32EF0004A690F /* ARTRestTokenTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestTokenTest.m; sourceTree = ""; }; 1C1E52F91AB35665004A690F /* ARTRestTimeTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRestTimeTest.m; sourceTree = ""; }; 1C1E53011AB373C5004A690F /* ARTRealtimeChannelTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRealtimeChannelTest.m; sourceTree = ""; }; - 1C1EC4091AE3BFDB00AAADD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1C1EC40A1AE3BFDB00AAADD7 /* ably-ios.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ably-ios.h"; sourceTree = ""; }; - 1C1EC4161AE3BFDB00AAADD7 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 1C1EC4171AE3BFDB00AAADD7 /* ably_iosTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ably_iosTests.m; sourceTree = ""; }; 1C6C18A11ADFDAB100AB79E4 /* ARTLog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTLog.h; sourceTree = ""; }; 1C6C18A21ADFDAB100AB79E4 /* ARTLog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTLog.m; sourceTree = ""; }; 1C6C18A61ADFDDBA00AB79E4 /* ARTLogTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTLogTest.m; sourceTree = ""; }; - 1C75E9EE1AE0165100B2892A /* errors.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = errors.json; sourceTree = ""; }; - 1C75E9F01AE0165100B2892A /* crypto-data-128.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "crypto-data-128.json"; sourceTree = ""; }; - 1C75E9F11AE0165100B2892A /* crypto-data-256.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "crypto-data-256.json"; sourceTree = ""; }; - 1C75E9F21AE0165100B2892A /* test-app-setup.json */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.json; path = "test-app-setup.json"; sourceTree = ""; }; + 1C8065041AE7C8FA00D49357 /* ARTPayload+Private.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTPayload+Private.h"; sourceTree = ""; }; 1CA5E1C01AB72369006ADD70 /* ARTMsgPackEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTMsgPackEncoder.h; sourceTree = ""; }; 1CA5E1C11AB72369006ADD70 /* ARTMsgPackEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTMsgPackEncoder.m; sourceTree = ""; }; 1CC3D94A1AB6FBB60005BEB0 /* ARTRealtimeChannelHistoryTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRealtimeChannelHistoryTest.m; sourceTree = ""; }; @@ -189,8 +177,8 @@ 961343D71A42E0B7006DC822 /* ARTOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTOptions.m; sourceTree = ""; }; 961343E61A432E7C006DC822 /* ARTPayload.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTPayload.h; sourceTree = ""; }; 961343E71A432E7C006DC822 /* ARTPayload.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTPayload.m; sourceTree = ""; }; - 967A431F1A39AEAF00E4CE23 /* NSArray+ARTFunctional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSArray+ARTFunctional.h"; sourceTree = ""; }; - 967A43201A39AEAF00E4CE23 /* NSArray+ARTFunctional.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSArray+ARTFunctional.m"; sourceTree = ""; }; + 967A431F1A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTNSArray+ARTFunctional.h"; sourceTree = ""; }; + 967A43201A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ARTNSArray+ARTFunctional.m"; sourceTree = ""; }; 96A507931A370F860077CDF8 /* ARTStats.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTStats.h; sourceTree = ""; }; 96A507941A370F860077CDF8 /* ARTStats.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTStats.m; sourceTree = ""; }; 96A507971A371E910077CDF8 /* ARTPaginatedResult.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTPaginatedResult.h; sourceTree = ""; }; @@ -198,18 +186,16 @@ 96A5079C1A371F800077CDF8 /* ARTHttpPaginatedResult.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTHttpPaginatedResult.m; sourceTree = ""; }; 96A5079F1A377AA50077CDF8 /* ARTPresenceMessage.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTPresenceMessage.h; sourceTree = ""; }; 96A507A01A377AA50077CDF8 /* ARTPresenceMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTPresenceMessage.m; sourceTree = ""; }; - 96A507A31A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDictionary+ARTDictionaryUtil.h"; sourceTree = ""; }; - 96A507A41A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDictionary+ARTDictionaryUtil.m"; sourceTree = ""; }; + 96A507A31A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTNSDictionary+ARTDictionaryUtil.h"; sourceTree = ""; }; + 96A507A41A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ARTNSDictionary+ARTDictionaryUtil.m"; sourceTree = ""; }; 96A507A71A37806A0077CDF8 /* ARTEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTEncoder.h; sourceTree = ""; }; 96A507AB1A3780F60077CDF8 /* ARTJsonEncoder.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTJsonEncoder.h; sourceTree = ""; }; 96A507AC1A3780F60077CDF8 /* ARTJsonEncoder.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTJsonEncoder.m; sourceTree = ""; }; - 96A507B31A37881C0077CDF8 /* NSDate+ARTUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSDate+ARTUtil.h"; sourceTree = ""; }; - 96A507B41A37881C0077CDF8 /* NSDate+ARTUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSDate+ARTUtil.m"; sourceTree = ""; }; + 96A507B31A37881C0077CDF8 /* ARTNSDate+ARTUtil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "ARTNSDate+ARTUtil.h"; sourceTree = ""; }; + 96A507B41A37881C0077CDF8 /* ARTNSDate+ARTUtil.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "ARTNSDate+ARTUtil.m"; sourceTree = ""; }; 96A507BB1A3791490077CDF8 /* ARTRealtime.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRealtime.h; sourceTree = ""; }; 96A507BC1A3791490077CDF8 /* ARTRealtime.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ARTRealtime.m; sourceTree = ""; }; 96BF61311A35B2AB004CF2B3 /* ably.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ably.framework; sourceTree = BUILT_PRODUCTS_DIR; }; - 96BF61351A35B2AB004CF2B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 96BF61361A35B2AB004CF2B3 /* ably-ios.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "ably-ios.h"; sourceTree = ""; }; 96BF613C1A35B2AB004CF2B3 /* ablyTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ablyTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 96BF61421A35B2AB004CF2B3 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 96BF61511A35B39C004CF2B3 /* ARTRest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARTRest.h; sourceTree = ""; }; @@ -290,74 +276,11 @@ name = realtime; sourceTree = ""; }; - 1C1EC4071AE3BFDB00AAADD7 /* ably-ios */ = { - isa = PBXGroup; - children = ( - 1C1EC40A1AE3BFDB00AAADD7 /* ably-ios.h */, - 1C1EC4081AE3BFDB00AAADD7 /* Supporting Files */, - ); - path = "ably-ios"; - sourceTree = ""; - }; - 1C1EC4081AE3BFDB00AAADD7 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 1C1EC4091AE3BFDB00AAADD7 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 1C1EC4141AE3BFDB00AAADD7 /* ably-iosTests */ = { - isa = PBXGroup; - children = ( - 1C1EC4171AE3BFDB00AAADD7 /* ably_iosTests.m */, - 1C1EC4151AE3BFDB00AAADD7 /* Supporting Files */, - ); - path = "ably-iosTests"; - sourceTree = ""; - }; - 1C1EC4151AE3BFDB00AAADD7 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 1C1EC4161AE3BFDB00AAADD7 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; - 1C75E9EC1AE0165100B2892A /* ably-common */ = { - isa = PBXGroup; - children = ( - 1C75E9ED1AE0165100B2892A /* protocol */, - 1C75E9EF1AE0165100B2892A /* test-resources */, - ); - path = "ably-common"; - sourceTree = SOURCE_ROOT; - }; - 1C75E9ED1AE0165100B2892A /* protocol */ = { - isa = PBXGroup; - children = ( - 1C75E9EE1AE0165100B2892A /* errors.json */, - ); - path = protocol; - sourceTree = ""; - }; - 1C75E9EF1AE0165100B2892A /* test-resources */ = { - isa = PBXGroup; - children = ( - 1C75E9F01AE0165100B2892A /* crypto-data-128.json */, - 1C75E9F11AE0165100B2892A /* crypto-data-256.json */, - 1C75E9F21AE0165100B2892A /* test-app-setup.json */, - ); - path = "test-resources"; - sourceTree = ""; - }; 96BF61271A35B2AB004CF2B3 = { isa = PBXGroup; children = ( 96BF61331A35B2AB004CF2B3 /* ably-ios */, 96BF61401A35B2AB004CF2B3 /* ably-iosTests */, - 1C1EC4071AE3BFDB00AAADD7 /* ably-ios */, - 1C1EC4141AE3BFDB00AAADD7 /* ably-iosTests */, 96BF61321A35B2AB004CF2B3 /* Products */, B7FA72C0B06CA0A207042965 /* Pods */, FAFEC5BB8312EB69E84C28D4 /* Frameworks */, @@ -376,7 +299,6 @@ 96BF61331A35B2AB004CF2B3 /* ably-ios */ = { isa = PBXGroup; children = ( - 96BF61361A35B2AB004CF2B3 /* ably-ios.h */, 96BF61341A35B2AB004CF2B3 /* Supporting Files */, 96BF61511A35B39C004CF2B3 /* ARTRest.h */, 96BF61521A35B39C004CF2B3 /* ARTRest.m */, @@ -396,13 +318,13 @@ 96A5079C1A371F800077CDF8 /* ARTHttpPaginatedResult.m */, 96A5079F1A377AA50077CDF8 /* ARTPresenceMessage.h */, 96A507A01A377AA50077CDF8 /* ARTPresenceMessage.m */, - 96A507A31A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.h */, - 96A507A41A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.m */, + 96A507A31A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.h */, + 96A507A41A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.m */, 96A507A71A37806A0077CDF8 /* ARTEncoder.h */, 96A507AB1A3780F60077CDF8 /* ARTJsonEncoder.h */, 96A507AC1A3780F60077CDF8 /* ARTJsonEncoder.m */, - 96A507B31A37881C0077CDF8 /* NSDate+ARTUtil.h */, - 96A507B41A37881C0077CDF8 /* NSDate+ARTUtil.m */, + 96A507B31A37881C0077CDF8 /* ARTNSDate+ARTUtil.h */, + 96A507B41A37881C0077CDF8 /* ARTNSDate+ARTUtil.m */, 96A507BB1A3791490077CDF8 /* ARTRealtime.h */, 96A507BC1A3791490077CDF8 /* ARTRealtime.m */, 96E4083D1A3892C700087F77 /* ARTRealtimeTransport.h */, @@ -410,8 +332,8 @@ 96E408421A38939E00087F77 /* ARTProtocolMessage.m */, 96E408451A3895E800087F77 /* ARTWebSocketTransport.h */, 96E408461A3895E800087F77 /* ARTWebSocketTransport.m */, - 967A431F1A39AEAF00E4CE23 /* NSArray+ARTFunctional.h */, - 967A43201A39AEAF00E4CE23 /* NSArray+ARTFunctional.m */, + 967A431F1A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.h */, + 967A43201A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.m */, 961343D61A42E0B7006DC822 /* ARTOptions.h */, 961343D71A42E0B7006DC822 /* ARTOptions.m */, 961343E61A432E7C006DC822 /* ARTPayload.h */, @@ -424,6 +346,8 @@ 1C05CF1E1AC1D7EB00687AC9 /* ARTRealtime+Private.h */, 1C6C18A11ADFDAB100AB79E4 /* ARTLog.h */, 1C6C18A21ADFDAB100AB79E4 /* ARTLog.m */, + 1C118A591AE63D58006AD19E /* ably-ios.h */, + 1C8065041AE7C8FA00D49357 /* ARTPayload+Private.h */, ); path = "ably-ios"; sourceTree = ""; @@ -431,7 +355,7 @@ 96BF61341A35B2AB004CF2B3 /* Supporting Files */ = { isa = PBXGroup; children = ( - 96BF61351A35B2AB004CF2B3 /* Info.plist */, + 1C118A5B1AE63D89006AD19E /* Info.plist */, ); name = "Supporting Files"; sourceTree = ""; @@ -439,7 +363,7 @@ 96BF61401A35B2AB004CF2B3 /* ably-iosTests */ = { isa = PBXGroup; children = ( - 1C75E9EC1AE0165100B2892A /* ably-common */, + 1C118AB61AE6485C006AD19E /* ably-common */, 1C1E52E81AB32E6E004A690F /* realtime */, 1C1E52E71AB32E69004A690F /* rest */, 96BF61411A35B2AB004CF2B3 /* Supporting Files */, @@ -485,6 +409,7 @@ files = ( 96BF61531A35B39C004CF2B3 /* ARTRest.h in Headers */, 96A507BD1A3791490077CDF8 /* ARTRealtime.h in Headers */, + 1C118A5A1AE63D58006AD19E /* ably-ios.h in Headers */, 961343D81A42E0B7006DC822 /* ARTOptions.h in Headers */, 96BF615E1A35C1C8004CF2B3 /* ARTTypes.h in Headers */, 1C1EC3FA1AE26A8B00AAADD7 /* ARTStatus.h in Headers */, @@ -495,21 +420,21 @@ 96BF61701A35FB7C004CF2B3 /* ARTAuth.h in Headers */, 96A507A11A377AA50077CDF8 /* ARTPresenceMessage.h in Headers */, 96A5079D1A371F800077CDF8 /* ARTHttpPaginatedResult.h in Headers */, + 1C8065051AE7C8FA00D49357 /* ARTPayload+Private.h in Headers */, 961343E81A432E7C006DC822 /* ARTPayload.h in Headers */, - 967A43211A39AEAF00E4CE23 /* NSArray+ARTFunctional.h in Headers */, + 967A43211A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.h in Headers */, 96E408471A3895E800087F77 /* ARTWebSocketTransport.h in Headers */, 96E4083F1A3892C700087F77 /* ARTRealtimeTransport.h in Headers */, 960D07971A46FFC300ED8C8C /* ARTRest+Private.h in Headers */, - 96A507B51A37881C0077CDF8 /* NSDate+ARTUtil.h in Headers */, + 96A507B51A37881C0077CDF8 /* ARTNSDate+ARTUtil.h in Headers */, 96A507A91A37806A0077CDF8 /* ARTEncoder.h in Headers */, 1C6C18A31ADFDAB100AB79E4 /* ARTLog.h in Headers */, 1CA5E1C21AB72369006ADD70 /* ARTMsgPackEncoder.h in Headers */, - 96A507A51A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.h in Headers */, + 96A507A51A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.h in Headers */, 96A507AD1A3780F60077CDF8 /* ARTJsonEncoder.h in Headers */, 96A507951A370F860077CDF8 /* ARTStats.h in Headers */, 1C05CF201AC1D7EB00687AC9 /* ARTRealtime+Private.h in Headers */, 960D07931A45F1D800ED8C8C /* ARTCrypto.h in Headers */, - 96BF61371A35B2AB004CF2B3 /* ably-ios.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -544,6 +469,7 @@ 96BF61391A35B2AB004CF2B3 /* Frameworks */, 96BF613A1A35B2AB004CF2B3 /* Resources */, 1C5DA0141A6E5F8A00A2B7EF /* Copy Files */, + 1C118ABA1AE64919006AD19E /* Copy Files */, ); buildRules = ( 1C5DA0131A6E5F2700A2B7EF /* PBXBuildRule */, @@ -566,9 +492,6 @@ LastUpgradeCheck = 0610; ORGANIZATIONNAME = Ably; TargetAttributes = { - 1C1EC3FB1AE2737800AAADD7 = { - CreatedOnToolsVersion = 6.1.1; - }; 96BF61301A35B2AB004CF2B3 = { CreatedOnToolsVersion = 6.1.1; }; @@ -591,7 +514,6 @@ targets = ( 96BF61301A35B2AB004CF2B3 /* ably */, 96BF613B1A35B2AB004CF2B3 /* ablyTests */, - 1C1EC3FB1AE2737800AAADD7 /* ablyaggregate */, ); }; /* End PBXProject section */ @@ -601,6 +523,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1C118ABC1AE64D96006AD19E /* ably-common in Resources */, + 1C118A5C1AE63D89006AD19E /* Info.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -608,10 +532,8 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( - 1C75E9F41AE0165100B2892A /* crypto-data-128.json in Resources */, - 1C75E9F51AE0165100B2892A /* crypto-data-256.json in Resources */, - 1C75E9F31AE0165100B2892A /* errors.json in Resources */, - 1C75E9F61AE0165100B2892A /* test-app-setup.json in Resources */, + 1C118A5D1AE63D89006AD19E /* Info.plist in Resources */, + 1C118AB81AE6485C006AD19E /* ably-common in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -633,19 +555,6 @@ shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods/Pods-resources.sh\"\n"; showEnvVarsInLog = 0; }; - 1C1EC43D1AE454DC00AAADD7 /* ShellScript */ = { - isa = PBXShellScriptBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - inputPaths = ( - ); - outputPaths = ( - ); - runOnlyForDeploymentPostprocessing = 0; - shellPath = /bin/sh; - shellScript = "# This script is based on Jacob Van Order's answer on apple dev forums https://devforums.apple.com/message/971277\n# See also http://spin.atomicobject.com/2011/12/13/building-a-universal-framework-for-ios/ for the start\n\n\n# To get this to work with a Xcode 6 Cocoa Touch Framework, create Framework\n# Then create a new Aggregate Target. Throw this script into a Build Script Phrase on the Aggregate\n\n\n######################\n# Options\n######################\n\nREVEAL_ARCHIVE_IN_FINDER=true\n\nFRAMEWORK_NAME=\"${PROJECT_NAME}\"\n\nSIMULATOR_LIBRARY_PATH=\"${BUILD_DIR}/${CONFIGURATION}-iphonesimulator/${FRAMEWORK_NAME}.framework\"\n\nDEVICE_LIBRARY_PATH=\"${BUILD_DIR}/${CONFIGURATION}-iphoneos/${FRAMEWORK_NAME}.framework\"\n\nUNIVERSAL_LIBRARY_DIR=\"${BUILD_DIR}/${CONFIGURATION}-iphoneuniversal\"\n\nFRAMEWORK=\"${UNIVERSAL_LIBRARY_DIR}/${FRAMEWORK_NAME}.framework\"\n\n\n######################\n# Build Frameworks\n######################\n\nxcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphonesimulator -target ${PROJECT_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphonesimulator | echo\n\nxcodebuild -project ${PROJECT_NAME}.xcodeproj -sdk iphoneos -target ${PROJECT_NAME} -configuration ${CONFIGURATION} clean build CONFIGURATION_BUILD_DIR=${BUILD_DIR}/${CONFIGURATION}-iphoneos | echo\n\n#xcodebuild -target ${PROJECT_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphoneos BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" | echo\n\n#xcodebuild -target ${PROJECT_NAME} ONLY_ACTIVE_ARCH=NO -configuration ${CONFIGURATION} -sdk iphonesimulator BUILD_DIR=\"${BUILD_DIR}\" BUILD_ROOT=\"${BUILD_ROOT}\" | echo\n\n\n######################\n# Create directory for universal\n######################\n\nrm -rf \"${UNIVERSAL_LIBRARY_DIR}\"\n\nmkdir \"${UNIVERSAL_LIBRARY_DIR}\"\n\nmkdir \"${FRAMEWORK}\"\n\n\n######################\n# Copy files Framework\n######################\n\ncp -r \"${DEVICE_LIBRARY_PATH}/.\" \"${FRAMEWORK}\"\n\n\n######################\n# Make fat universal binary\n######################\n\nlipo \"${SIMULATOR_LIBRARY_PATH}/${FRAMEWORK_NAME}\" \"${DEVICE_LIBRARY_PATH}/${FRAMEWORK_NAME}\" -create -output \"${FRAMEWORK}/${FRAMEWORK_NAME}\" | echo\n\n\n######################\n# On Release, copy the result to desktop folder\n######################\n\nif [ \"${CONFIGURATION}\" == \"Release\" ]; then\nmkdir \"${HOME}/Desktop/${FRAMEWORK_NAME}-${CONFIGURATION}-iphoneuniversal/\"\ncp -r \"${FRAMEWORK}\" \"${HOME}/Desktop/${FRAMEWORK_NAME}-${CONFIGURATION}-iphoneuniversal/\"\nfi\n\n\n######################\n# If needed, open the Framework folder\n######################\n\nif [ ${REVEAL_ARCHIVE_IN_FINDER} = true ]; then\nif [ \"${CONFIGURATION}\" == \"Release\" ]; then\nopen \"${HOME}/Desktop/${FRAMEWORK_NAME}-${CONFIGURATION}-iphoneuniversal/\"\nelse\nopen \"${UNIVERSAL_LIBRARY_DIR}/\"\nfi\nfi"; - }; 79FE055B54B0AB6FDAB24FCE /* Check Pods Manifest.lock */ = { isa = PBXShellScriptBuildPhase; buildActionMask = 2147483647; @@ -673,7 +582,7 @@ 961343E91A432E7C006DC822 /* ARTPayload.m in Sources */, 960D07941A45F1D800ED8C8C /* ARTCrypto.m in Sources */, 96BF61591A35B52C004CF2B3 /* ARTHttp.m in Sources */, - 96A507B61A37881C0077CDF8 /* NSDate+ARTUtil.m in Sources */, + 96A507B61A37881C0077CDF8 /* ARTNSDate+ARTUtil.m in Sources */, 961343D91A42E0B7006DC822 /* ARTOptions.m in Sources */, 96BF615F1A35C1C8004CF2B3 /* ARTTypes.m in Sources */, 96A507AE1A3780F60077CDF8 /* ARTJsonEncoder.m in Sources */, @@ -686,8 +595,8 @@ 96A5079E1A371F800077CDF8 /* ARTHttpPaginatedResult.m in Sources */, 1C6C18A41ADFDAB100AB79E4 /* ARTLog.m in Sources */, 96A507BE1A3791490077CDF8 /* ARTRealtime.m in Sources */, - 967A43221A39AEAF00E4CE23 /* NSArray+ARTFunctional.m in Sources */, - 96A507A61A377DE90077CDF8 /* NSDictionary+ARTDictionaryUtil.m in Sources */, + 967A43221A39AEAF00E4CE23 /* ARTNSArray+ARTFunctional.m in Sources */, + 96A507A61A377DE90077CDF8 /* ARTNSDictionary+ARTDictionaryUtil.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -699,7 +608,6 @@ 1C1E52EE1AB32EB9004A690F /* ARTRestCapabilityTest.m in Sources */, 1C1E52F01AB32EC7004A690F /* ARTRestChannelHistoryTest.m in Sources */, 1CC3D94F1AB6FECC0005BEB0 /* ARTRealtimeConnectFail.m in Sources */, - 1C6C18A51ADFDAB100AB79E4 /* ARTLog.m in Sources */, 1CC3D9591AB701E50005BEB0 /* ARTRealtimePresenceTest.m in Sources */, 1CC3D9511AB6FF480005BEB0 /* ARTRealtimeCryptoTest.m in Sources */, 96E408361A38595F00087F77 /* ARTRealtimeAttachTest.m in Sources */, @@ -726,11 +634,6 @@ /* End PBXSourcesBuildPhase section */ /* Begin PBXTargetDependency section */ - 1C1EC4001AE273FB00AAADD7 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 96BF61301A35B2AB004CF2B3 /* ably */; - targetProxy = 1C1EC3FF1AE273FB00AAADD7 /* PBXContainerItemProxy */; - }; 96BF613F1A35B2AB004CF2B3 /* PBXTargetDependency */ = { isa = PBXTargetDependency; target = 96BF61301A35B2AB004CF2B3 /* ably */; @@ -739,33 +642,6 @@ /* End PBXTargetDependency section */ /* Begin XCBuildConfiguration section */ - 1C1EC3FD1AE2737800AAADD7 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = ( - "$(ARCHS_STANDARD)", - i386, - x86_64, - ); - ONLY_ACTIVE_ARCH = NO; - PRODUCT_NAME = "$(TARGET_NAME)"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; - }; - name = Debug; - }; - 1C1EC3FE1AE2737800AAADD7 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - ARCHS = ( - "$(ARCHS_STANDARD)", - i386, - x86_64, - ); - PRODUCT_NAME = "$(TARGET_NAME)"; - VALID_ARCHS = "arm64 armv7 armv7s x86_64"; - }; - name = Release; - }; 96BF61451A35B2AB004CF2B3 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -935,15 +811,6 @@ /* End XCBuildConfiguration section */ /* Begin XCConfigurationList section */ - 1C1EC3FC1AE2737800AAADD7 /* Build configuration list for PBXAggregateTarget "ablyaggregate" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 1C1EC3FD1AE2737800AAADD7 /* Debug */, - 1C1EC3FE1AE2737800AAADD7 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; 96BF612B1A35B2AB004CF2B3 /* Build configuration list for PBXProject "ably" */ = { isa = XCConfigurationList; buildConfigurations = (