diff --git a/Source/ARTAuth.m b/Source/ARTAuth.m index 347b6ebb0..2cace74c2 100644 --- a/Source/ARTAuth.m +++ b/Source/ARTAuth.m @@ -158,6 +158,7 @@ - (NSURL *)buildURL:(ARTAuthOptions *)options withParams:(ARTTokenParams *)param } - (NSMutableURLRequest *)buildRequest:(ARTAuthOptions *)options withParams:(ARTTokenParams *)params { + if (!params.timestamp) params.timestamp = [self currentDate]; NSURL *url = [self buildURL:options withParams:params]; NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; request.HTTPMethod = options.authMethod; @@ -189,7 +190,7 @@ - (void)requestToken:(ARTTokenParams *)tokenParams withOptions:(ARTAuthOptions * // The values replace all corresponding. ARTAuthOptions *replacedOptions = authOptions ? authOptions : self.options; ARTTokenParams *currentTokenParams = tokenParams ? tokenParams : _tokenParams; - tokenParams.timestamp = [self currentDate]; + currentTokenParams.timestamp = [self currentDate]; if (replacedOptions.key == nil && replacedOptions.authCallback == nil && replacedOptions.authUrl == nil) { callback(nil, [ARTErrorInfo createWithCode:ARTStateRequestTokenFailed message:@"no means to renew the token is provided (either an API key, authCallback or authUrl)"]); @@ -373,6 +374,7 @@ - (void)authorise:(ARTTokenParams *)tokenParams options:(ARTAuthOptions *)authOp - (void)createTokenRequest:(ARTTokenParams *)tokenParams options:(ARTAuthOptions *)options callback:(void (^)(ARTTokenRequest *, NSError *))callback { ARTAuthOptions *replacedOptions = options ? : self.options; ARTTokenParams *currentTokenParams = tokenParams ? : _tokenParams; + currentTokenParams.timestamp = [self currentDate]; // Validate: Capability JSON text NSError *errorCapability; diff --git a/Source/ARTClientOptions.m b/Source/ARTClientOptions.m index 2c40f01b4..243136be0 100644 --- a/Source/ARTClientOptions.m +++ b/Source/ARTClientOptions.m @@ -10,6 +10,7 @@ #import "ARTAuthOptions+Private.h" #import "ARTDefault.h" +#import "ARTTokenParams.h" NSString *ARTDefaultEnvironment = nil; @@ -125,4 +126,8 @@ + (void)setDefaultEnvironment:(NSString *)environment { ARTDefaultEnvironment = environment; } +- (void)setDefaultTokenParams:(ARTTokenParams *)value { + _defaultTokenParams = [[ARTTokenParams alloc] initWithTokenParams:value]; +} + @end diff --git a/Source/ARTTokenParams.h b/Source/ARTTokenParams.h index 4bc0a78d2..b53127967 100644 --- a/Source/ARTTokenParams.h +++ b/Source/ARTTokenParams.h @@ -37,7 +37,7 @@ ART_ASSUME_NONNULL_BEGIN /** Timestamp (in millis since the epoch) of this request. Timestamps, in conjunction with the nonce, are used to prevent n requests from being replayed. */ -@property (nonatomic, strong, null_resettable, setter=setTimestamp:, getter=getTimestamp) NSDate *timestamp; +@property (art_nullable, nonatomic, copy, readwrite) NSDate *timestamp; @property (nonatomic, readonly, strong) NSString *nonce; @@ -45,6 +45,7 @@ ART_ASSUME_NONNULL_BEGIN - (instancetype)initWithClientId:(NSString *__art_nullable)clientId; - (instancetype)initWithClientId:(NSString *__art_nullable)clientId nonce:(NSString *__art_nullable)nonce; - (instancetype)initWithOptions:(ARTClientOptions *)options; +- (instancetype)initWithTokenParams:(ARTTokenParams *)tokenParams; - (__GENERIC(NSMutableArray, NSURLQueryItem *) *)toArray; - (__GENERIC(NSArray, NSURLQueryItem *) *)toArrayWithUnion:(NSArray *)items; diff --git a/Source/ARTTokenParams.m b/Source/ARTTokenParams.m index bd40f677b..de4e73019 100644 --- a/Source/ARTTokenParams.m +++ b/Source/ARTTokenParams.m @@ -15,9 +15,7 @@ #import "ARTEncoder.h" #import "ARTTokenRequest.h" -@implementation ARTTokenParams { - NSDate *_timestamp; -} +@implementation ARTTokenParams - (instancetype)init { return [self initWithClientId:nil nonce:nil]; @@ -47,22 +45,19 @@ - (instancetype)initWithOptions:(ARTClientOptions *)options { return self; } +- (instancetype)initWithTokenParams:(ARTTokenParams *)tokenParams { + self = [self initWithClientId:tokenParams.clientId]; + self.timestamp = nil; + self.ttl = tokenParams.ttl; + self.capability = tokenParams.capability; + return self; +} + - (NSString *)description { return [NSString stringWithFormat: @"ARTTokenParams: ttl=%f capability=%@ timestamp=%@", self.ttl, self.capability, self.timestamp]; } -- (void)setTimestamp:(NSDate *)timestamp { - _timestamp = timestamp; -} - -- (NSDate *)getTimestamp { - if (_timestamp == nil) { - _timestamp = [NSDate date]; - } - return _timestamp; -} - - (NSMutableArray *)toArray { NSMutableArray *params = [[NSMutableArray alloc] init]; diff --git a/Spec/Auth.swift b/Spec/Auth.swift index 5044700de..881738c41 100644 --- a/Spec/Auth.swift +++ b/Spec/Auth.swift @@ -268,7 +268,9 @@ class Auth : QuickSpec { } } - let transport = client.transport as! TestProxyTransport + guard let transport = client.transport as? TestProxyTransport else { + fail("Transport is nil"); return + } guard let connectedMessage = transport.protocolMessagesReceived.filter({ $0.action == .Connected }).last else { XCTFail("No CONNECTED protocol action received"); return } @@ -1106,7 +1108,10 @@ class Auth : QuickSpec { waitUntil(timeout: testTimeout) { done in let message = ARTMessage(name: nil, data: "message with an explicit clientId", clientId: "john") channel.publish([message]) { error in - expect(error!.message).to(contain("mismatched clientId")) + guard let error = error else { + fail("Error is nil"); done(); return + } + expect(error.message).to(contain("mismatched clientId")) done() } } @@ -2590,21 +2595,29 @@ class Auth : QuickSpec { expect(params.timestamp).to(equal(NSDate(timeIntervalSince1970: 123))) } - it("if not explicitly set, should be generated at the getter and stick") { + it("if explicitly set, the value should stick") { let params = ARTTokenParams() + params.timestamp = NSDate() waitUntil(timeout: testTimeout) { done in + let now = NSDate().artToIntegerMs() + guard let timestamp = params.timestamp else { + fail("timestamp is nil"); done(); return + } + let firstParamsTimestamp = timestamp.artToIntegerMs() + expect(firstParamsTimestamp).to(beCloseTo(now, within: 1.5)) delay(0.25) { - let now = NSDate().artToIntegerMs() - let firstParamsTimestamp = params.timestamp.artToIntegerMs() - expect(firstParamsTimestamp).to(beCloseTo(now, within: 1.5)) - delay(0.25) { - expect(params.timestamp.artToIntegerMs()).to(equal(firstParamsTimestamp)) - done() - } + expect(timestamp.artToIntegerMs()).to(equal(firstParamsTimestamp)) + done() } } } + + // https://github.com/ably/ably-ios/pull/508#discussion_r82577728 + it("object has no timestamp value unless explicitly set") { + let params = ARTTokenParams() + expect(params.timestamp).to(beNil()) + } } } @@ -2706,5 +2719,35 @@ class Auth : QuickSpec { } } } + + describe("TokenParams") { + // TK2d + it("timestamp should not be a member of any default token params") { + let rest = ARTRest(options: AblyTests.commonAppSetup()) + waitUntil(timeout: testTimeout) { done in + rest.auth.authorise(nil, options: nil) { _, error in + expect(error).to(beNil()) + guard let defaultTokenParams = rest.auth.options.defaultTokenParams else { + fail("DefaultTokenParams is nil"); done(); return + } + expect(defaultTokenParams.timestamp).to(beNil()) + + var defaultTokenParamsCallCount = 0 + let hook = rest.auth.options.testSuite_injectIntoMethodAfter(NSSelectorFromString("defaultTokenParams")) { + defaultTokenParamsCallCount += 1 + } + defer { hook.remove() } + + let newTokenParams = ARTTokenParams(options: rest.auth.options) + expect(defaultTokenParamsCallCount) > 0 + + newTokenParams.timestamp = NSDate() + expect(newTokenParams.timestamp).toNot(equal(defaultTokenParams.timestamp)) + expect(defaultTokenParams.timestamp).to(beNil()) //remain nil + done() + } + } + } + } } }