From 1125c950047607db1cb4d1675e448638f899557c Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 8 Apr 2024 21:29:25 +0530 Subject: [PATCH 01/19] Reverted deprecated methods for deprecated create token request --- src/IO.Ably.Shared/AblyAuth.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IO.Ably.Shared/AblyAuth.cs b/src/IO.Ably.Shared/AblyAuth.cs index 86de038df..91065ff53 100644 --- a/src/IO.Ably.Shared/AblyAuth.cs +++ b/src/IO.Ably.Shared/AblyAuth.cs @@ -559,6 +559,7 @@ private void SetCurrentAuthOptions(AuthOptions options) /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// signed token request. + [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObject instead")] public async Task CreateTokenRequestObjectAsync(TokenParams tokenParams, AuthOptions authOptions) { authOptions = authOptions ?? CurrentAuthOptions ?? Options; @@ -669,20 +670,19 @@ public TokenDetails Authorise(TokenParams tokenParams = null, AuthOptions option return AsyncHelper.RunSync(() => AuthorizeAsync(tokenParams, options)); } + [Obsolete("This method will be removed in a future version, please use CreateTokenRequest instead")] public TokenRequest CreateTokenRequestObject(TokenParams tokenParams = null, AuthOptions authOptions = null) { + Logger.Warning("CreateTokenRequest is deprecated and will be removed in the future, please use CreateTokenRequest instead"); return AsyncHelper.RunSync(() => CreateTokenRequestObjectAsync(tokenParams, authOptions)); } - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObjectAsync instead")] public async Task CreateTokenRequestAsync(TokenParams tokenParams, AuthOptions authOptions) { - Logger.Warning("CreateTokenRequest is deprecated and will be removed in the future, please use CreateTokenRequestObject instead"); var tokenRequest = await CreateTokenRequestObjectAsync(tokenParams, authOptions); return JsonHelper.Serialize(tokenRequest); } - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObject instead")] public string CreateTokenRequest(TokenParams tokenParams = null, AuthOptions authOptions = null) { return AsyncHelper.RunSync(() => CreateTokenRequestAsync(tokenParams, authOptions)); From 31b9fecc875ef46ba0ca8aa3aedc2673176c3cb7 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Fri, 12 Apr 2024 17:45:39 +0530 Subject: [PATCH 02/19] reverted to old ablyauth implementation for tokendetails --- src/IO.Ably.Shared/AblyAuth.cs | 67 ++++++++++++++++++++++++---------- 1 file changed, 47 insertions(+), 20 deletions(-) diff --git a/src/IO.Ably.Shared/AblyAuth.cs b/src/IO.Ably.Shared/AblyAuth.cs index 91065ff53..96fda9794 100644 --- a/src/IO.Ably.Shared/AblyAuth.cs +++ b/src/IO.Ably.Shared/AblyAuth.cs @@ -302,31 +302,33 @@ public virtual async Task RequestTokenAsync(TokenParams tokenParam TokenRequest postData = null; if (authOptions.AuthCallback != null) { - var shouldCatch = true; + bool shouldCatch = true; try { var callbackResult = await authOptions.AuthCallback(tokenParams); - switch (callbackResult) + if (callbackResult == null) { - case null: - throw new AblyException("AuthCallback returned null", ErrorCodes.ClientAuthProviderRequestFailed); - case string token: - if (string.IsNullOrEmpty(token)) - { - throw new AblyException("AuthCallback returned empty string", ErrorCodes.ClientAuthProviderRequestFailed); - } - - return new TokenDetails(token); - case TokenDetails details: - return details; - case TokenRequest tokenRequest: - postData = tokenRequest; - request.Url = $"/keys/{tokenRequest.KeyName}/requestToken"; - break; - default: - shouldCatch = false; - throw new AblyException($"AuthCallback returned an unsupported type ({callbackResult.GetType()}. Expected either TokenDetails or TokenRequest", ErrorCodes.ClientAuthProviderRequestFailed, HttpStatusCode.BadRequest); + throw new AblyException("AuthCallback returned null", ErrorCodes.ClientAuthProviderRequestFailed); + } + + if (callbackResult is TokenDetails) + { + return callbackResult as TokenDetails; + } + + if (callbackResult is TokenRequest || callbackResult is string) + { + postData = GetTokenRequest(callbackResult); + request.Url = $"/keys/{postData.KeyName}/requestToken"; + } + else + { + shouldCatch = false; + throw new AblyException( + $"AuthCallback returned an unsupported type ({callbackResult.GetType()}. Expected either TokenDetails or TokenRequest", + ErrorCodes.ClientAuthProviderRequestFailed, + HttpStatusCode.BadRequest); } } catch (Exception ex) when (shouldCatch) @@ -453,6 +455,31 @@ private void NotifyClientIdIfChanged(string oldClientId) } } +#pragma warning disable SA1204 // Static elements should appear before instance elements + private static TokenRequest GetTokenRequest(object callbackResult) +#pragma warning restore SA1204 // Static elements should appear before instance elements + { + if (callbackResult is TokenRequest) + { + return callbackResult as TokenRequest; + } + + try + { + var result = JsonHelper.Deserialize((string)callbackResult); + if (result == null) + { + throw new AblyException(new ErrorInfo($"AuthCallback returned a string which can't be converted to TokenRequest. ({callbackResult}).")); + } + + return result; + } + catch (Exception e) + { + throw new AblyException(new ErrorInfo($"AuthCallback returned a string which can't be converted to TokenRequest. ({callbackResult})."), e); + } + } + private async Task CallAuthUrl(AuthOptions mergedOptions, TokenParams @params) { var url = mergedOptions.AuthUrl; From 775b7a3fb8ed16e551b487c02e7f5e9abd13c5a4 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 15 Apr 2024 17:07:56 +0530 Subject: [PATCH 03/19] Marked old createTokenRequestObject methods as deprecated --- src/IO.Ably.Shared/AblyAuth.cs | 86 +++++++++++++++++---------------- src/IO.Ably.Shared/IAblyAuth.cs | 4 +- 2 files changed, 46 insertions(+), 44 deletions(-) diff --git a/src/IO.Ably.Shared/AblyAuth.cs b/src/IO.Ably.Shared/AblyAuth.cs index 96fda9794..67cbbc7b3 100644 --- a/src/IO.Ably.Shared/AblyAuth.cs +++ b/src/IO.Ably.Shared/AblyAuth.cs @@ -557,6 +557,11 @@ public async Task AuthorizeAsync(TokenParams tokenParams = null, A return CurrentToken; } + public TokenDetails Authorize(TokenParams tokenParams = null, AuthOptions options = null) + { + return AsyncHelper.RunSync(() => AuthorizeAsync(tokenParams, options)); + } + [Obsolete("This method will be removed in the future, please replace with a call to AuthorizeAsync")] public async Task AuthoriseAsync(TokenParams tokenParams = null, AuthOptions options = null) { @@ -564,6 +569,13 @@ public async Task AuthoriseAsync(TokenParams tokenParams = null, A return await AuthorizeAsync(tokenParams, options); } + [Obsolete("This method will be removed in the future, please replace with a call to Authorize")] + public TokenDetails Authorise(TokenParams tokenParams = null, AuthOptions options = null) + { + Logger.Warning("Authorise is deprecated and will be removed in the future, please replace with a call to Authorize."); + return AsyncHelper.RunSync(() => AuthorizeAsync(tokenParams, options)); + } + private void SetCurrentTokenParams(TokenParams authTokenParams) { CurrentTokenParams = authTokenParams.Clone(); @@ -578,31 +590,6 @@ private void SetCurrentAuthOptions(AuthOptions options) } } - /// - /// Create a signed token request based on known credentials - /// and the given token params. This would typically be used if creating - /// signed requests for submission by another client. - /// - /// . If null a token request is generated from options passed when the client was created. - /// . If null the default AuthOptions are used. - /// signed token request. - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObject instead")] - public async Task CreateTokenRequestObjectAsync(TokenParams tokenParams, AuthOptions authOptions) - { - authOptions = authOptions ?? CurrentAuthOptions ?? Options; - tokenParams = tokenParams ?? CurrentTokenParams ?? TokenParams.WithDefaultsApplied(); - - if (string.IsNullOrEmpty(authOptions.Key)) - { - throw new AblyException("No key specified", ErrorCodes.InvalidCredentials, HttpStatusCode.Unauthorized); - } - - await SetTokenParamsTimestamp(authOptions, tokenParams); - - var apiKey = authOptions.ParseKey(); - return new TokenRequest(Now).Populate(tokenParams, apiKey.KeyName, apiKey.KeySecret); - } - private TokenAuthMethod GetTokenAuthMethod() { if (Options.AuthCallback != null) @@ -685,34 +672,49 @@ public TokenDetails RequestToken(TokenParams tokenParams = null, AuthOptions opt return AsyncHelper.RunSync(() => RequestTokenAsync(tokenParams, options)); } - public TokenDetails Authorize(TokenParams tokenParams = null, AuthOptions options = null) + /// + /// Create a signed token request based on known credentials + /// and the given token params. This would typically be used if creating + /// signed requests for submission by another client. + /// + /// . If null a token request is generated from options passed when the client was created. + /// . If null the default AuthOptions are used. + /// signed token request. + public async Task CreateTokenRequestAsync(TokenParams tokenParams, AuthOptions authOptions) { - return AsyncHelper.RunSync(() => AuthorizeAsync(tokenParams, options)); - } + authOptions = authOptions ?? CurrentAuthOptions ?? Options; + tokenParams = tokenParams ?? CurrentTokenParams ?? TokenParams.WithDefaultsApplied(); - [Obsolete("This method will be removed in the future, please replace with a call to Authorize")] - public TokenDetails Authorise(TokenParams tokenParams = null, AuthOptions options = null) - { - Logger.Warning("Authorise is deprecated and will be removed in the future, please replace with a call to Authorize."); - return AsyncHelper.RunSync(() => AuthorizeAsync(tokenParams, options)); + if (string.IsNullOrEmpty(authOptions.Key)) + { + throw new AblyException("No key specified", ErrorCodes.InvalidCredentials, HttpStatusCode.Unauthorized); + } + + await SetTokenParamsTimestamp(authOptions, tokenParams); + + var apiKey = authOptions.ParseKey(); + var tokenRequest = new TokenRequest(Now).Populate(tokenParams, apiKey.KeyName, apiKey.KeySecret); + + return JsonHelper.Serialize(tokenRequest); } - [Obsolete("This method will be removed in a future version, please use CreateTokenRequest instead")] - public TokenRequest CreateTokenRequestObject(TokenParams tokenParams = null, AuthOptions authOptions = null) + public string CreateTokenRequest(TokenParams tokenParams = null, AuthOptions authOptions = null) { - Logger.Warning("CreateTokenRequest is deprecated and will be removed in the future, please use CreateTokenRequest instead"); - return AsyncHelper.RunSync(() => CreateTokenRequestObjectAsync(tokenParams, authOptions)); + return AsyncHelper.RunSync(() => CreateTokenRequestAsync(tokenParams, authOptions)); } - public async Task CreateTokenRequestAsync(TokenParams tokenParams, AuthOptions authOptions) + [Obsolete("This method will be removed in a future version, please use CreateTokenRequestAsync instead")] + public async Task CreateTokenRequestObjectAsync(TokenParams tokenParams, AuthOptions authOptions) { - var tokenRequest = await CreateTokenRequestObjectAsync(tokenParams, authOptions); - return JsonHelper.Serialize(tokenRequest); + Logger.Warning("CreateTokenRequestObject is deprecated and will be removed in the future, please use CreateTokenRequest instead"); + var tokenRequest = await CreateTokenRequestAsync(tokenParams, authOptions); + return JsonHelper.Deserialize(tokenRequest); } - public string CreateTokenRequest(TokenParams tokenParams = null, AuthOptions authOptions = null) + [Obsolete("This method will be removed in a future version, please use CreateTokenRequest instead")] + public TokenRequest CreateTokenRequestObject(TokenParams tokenParams = null, AuthOptions authOptions = null) { - return AsyncHelper.RunSync(() => CreateTokenRequestAsync(tokenParams, authOptions)); + return AsyncHelper.RunSync(() => CreateTokenRequestObjectAsync(tokenParams, authOptions)); } } } diff --git a/src/IO.Ably.Shared/IAblyAuth.cs b/src/IO.Ably.Shared/IAblyAuth.cs index cf8321ae7..a7998273e 100644 --- a/src/IO.Ably.Shared/IAblyAuth.cs +++ b/src/IO.Ably.Shared/IAblyAuth.cs @@ -57,7 +57,6 @@ public interface IAblyAuth /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// serialized signed token request. - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObjectAsync instead")] Task CreateTokenRequestAsync(TokenParams tokenParams = null, AuthOptions authOptions = null); /// @@ -68,6 +67,7 @@ public interface IAblyAuth /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// signed token request. + [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObjectAsync instead")] Task CreateTokenRequestObjectAsync(TokenParams tokenParams = null, AuthOptions authOptions = null); /// @@ -107,7 +107,6 @@ public interface IAblyAuth /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// serialized signed token request. - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObject instead")] string CreateTokenRequest(TokenParams tokenParams = null, AuthOptions authOptions = null); /// @@ -117,6 +116,7 @@ public interface IAblyAuth /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// signed token request. + [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObject instead")] TokenRequest CreateTokenRequestObject(TokenParams tokenParams = null, AuthOptions authOptions = null); } } From c7b99f3c5c054399639415ec364d0c85ca8e649d Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Mon, 15 Apr 2024 17:46:47 +0530 Subject: [PATCH 04/19] updated tests with proper auth createTokenRequest --- .../AuthTests/AuthSandboxSpecs.cs | 6 +++--- .../AuthTests/AuthorizationTests.cs | 8 ++++---- .../AuthTests/RequestTokenSpecs.cs | 4 +++- src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs | 17 ++++++++++++----- .../Samples/DocumentationSamples.cs | 8 ++++---- .../Samples/RealtimeSamples.cs | 2 +- 6 files changed, 27 insertions(+), 18 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs b/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs index eac1b64f1..1610c670b 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs @@ -283,7 +283,7 @@ public async Task RealTimeWithAuthUrl_WhenTokenExpired_And_WithServerTime_Should }); await Task.Delay(2000); // This makes sure we get server time - _ = ((AblyAuth)mainClient.Auth).CreateTokenRequestObject(); + _ = ((AblyAuth)mainClient.Auth).CreateTokenRequest(); await mainClient.StatsAsync(); ((AblyAuth)mainClient.Auth).CurrentToken.Should().NotBeSameAs(token); @@ -373,7 +373,7 @@ static void AuthCallbackOptions(ClientOptions options, TestEnvironmentSettings s static void InvalidTokenOptions(ClientOptions options, TestEnvironmentSettings settings) { options.AutoConnect = false; - options.AuthCallback = (tokenParams) => Task.FromResult(string.Empty); + options.AuthCallback = (tokenParams) => Task.FromResult("invalid:token"); } await TestConnectingBecomesDisconnected("With invalid AuthUrl connection becomes Disconnected", AuthUrlOptions); @@ -869,7 +869,7 @@ public async Task TokenAuthCallbackWithTokenRequestReturned_ShouldBeAbleToGetATo var tokenClient = await GetRestClient(protocol); var authCallbackClient = await GetRestClient(protocol, options => { - options.AuthCallback = async tokenParams => await tokenClient.Auth.CreateTokenRequestObjectAsync(new TokenParams { ClientId = "*" }); + options.AuthCallback = async tokenParams => await tokenClient.Auth.CreateTokenRequestAsync(new TokenParams { ClientId = "*" }); options.Environment = settings.Environment; options.UseBinaryProtocol = protocol == Defaults.Protocol; }); diff --git a/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs b/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs index 29a85e3af..427173ac9 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/AuthorizationTests.cs @@ -29,7 +29,7 @@ private async Task CreateTokenRequest( TokenParams @params = null, AuthOptions options = null) { - return await client.Auth.CreateTokenRequestObjectAsync(@params, options); + return JsonHelper.Deserialize(await client.Auth.CreateTokenRequestAsync(@params, options)); } public class General : AuthorizationTests @@ -54,7 +54,7 @@ public async Task WithTlsTrueAndBasicAuth_ShouldWork() private static TokenRequest CreateDefaultTokenRequest(AblyRest client) { - return client.Auth.CreateTokenRequestObjectAsync().Result; + return JsonHelper.Deserialize(client.Auth.CreateTokenRequestAsync().Result); } [Fact] @@ -289,14 +289,14 @@ public async Task WithClientIdOverridesDefault() public async Task WithOutKeyIdThrowsException() { var client = new AblyRest(new ClientOptions { UseTokenAuth = true }); - await Assert.ThrowsAsync(() => client.Auth.CreateTokenRequestObjectAsync()); + await Assert.ThrowsAsync(() => client.Auth.CreateTokenRequestAsync()); } [Fact] public async Task WithOutKeyValueThrowsException() { var client = new AblyRest(new ClientOptions { Key = "111.222" }); - await Assert.ThrowsAsync(() => client.Auth.CreateTokenRequestObjectAsync()); + await Assert.ThrowsAsync(() => client.Auth.CreateTokenRequestAsync()); } public CreateTokenRequestSpecs(ITestOutputHelper output) diff --git a/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs b/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs index 28bd47e64..08cce6cfd 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/RequestTokenSpecs.cs @@ -256,7 +256,9 @@ public async Task CreateTokenRequest_TokenParamsAndAuthOptionsReplaceConfiguredD var tokenParams = new TokenParams { Capability = cap }; var authOptions = new AuthOptions(fakeApiKey); - var tokenRequest = await rest.AblyAuth.CreateTokenRequestObjectAsync(tokenParams, authOptions); + var result = await rest.AblyAuth.CreateTokenRequestAsync(tokenParams, authOptions); + + var tokenRequest = JsonHelper.Deserialize(result); tokenRequest.Capability.Should().Be(cap); fakeApiKey.Should().StartWith(tokenRequest.KeyName); diff --git a/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs b/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs index 2eb0a54bf..beb80f61b 100644 --- a/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs @@ -815,9 +815,19 @@ await Assert.ThrowsAsync(() => } [Fact] - public async Task WhenCallbackReturnsAnObjectThatIsNotTokenRequestOrTokenDetailsOrStringToken_ThrowsAblyException() + public async Task WhenCallbackReturnsAnObjectThatIsNotTokenRequestOrTokenDetails_ThrowsAblyException() { - var objects = new[] { new object(), string.Empty, new Uri("http://test") }; + var signedTokenRequest = await new AblyRest("fake.key:fakeid").Auth.CreateTokenRequestAsync(); + // do not throw exceptions + var objects = new object[] { new TokenDetails(), new TokenRequest() }; + foreach (var obj in objects) + { + var exception = await Record.ExceptionAsync(async () => await GetClient(_ => Task.FromResult(obj)).StatsAsync()); + Assert.Null(exception); + } + + // throw exceptions + objects = new[] { new object(), string.Empty, new Uri("http://test"), "jwtToken" }; foreach (var obj in objects) { await Assert.ThrowsAsync(() => @@ -825,9 +835,6 @@ await Assert.ThrowsAsync(() => return GetClient(_ => Task.FromResult(obj)).StatsAsync(); }); } - - var exception = await Record.ExceptionAsync(async () => await GetClient(_ => Task.FromResult("jwtToken")).StatsAsync()); - Assert.Null(exception); } private static AblyRest GetClient(Func> authCallback) diff --git a/src/IO.Ably.Tests.Shared/Samples/DocumentationSamples.cs b/src/IO.Ably.Tests.Shared/Samples/DocumentationSamples.cs index 7cd82011f..d7d0ba140 100644 --- a/src/IO.Ably.Tests.Shared/Samples/DocumentationSamples.cs +++ b/src/IO.Ably.Tests.Shared/Samples/DocumentationSamples.cs @@ -16,7 +16,7 @@ public static async Task AuthSamples1() { var realtime = new AblyRealtime("{{API_KEY}}"); var tokenParams = new TokenParams { ClientId = "Bob" }; - var tokenRequest = await realtime.Auth.CreateTokenRequestObjectAsync(tokenParams); + string tokenRequest = await realtime.Auth.CreateTokenRequestAsync(tokenParams); // ... issue the TokenRequest to a client ... } @@ -41,7 +41,7 @@ public static async Task AuthSample3() try { var tokenParams = new TokenParams { ClientId = "bob" }; - var tokenRequest = await client.Auth.CreateTokenRequestObjectAsync(tokenParams); + string tokenRequest = await client.Auth.CreateTokenRequestAsync(tokenParams); Console.WriteLine("Success; token request issued"); } catch (AblyException e) @@ -311,7 +311,7 @@ public static async Task RestWithClientId() { var rest = new AblyRest(new ClientOptions { Key = "{{API_KEY}}" }); var tokenParams = new TokenParams { ClientId = "Bob" }; - var tokenRequest = await rest.Auth.CreateTokenRequestObjectAsync(tokenParams); + string tokenRequest = await rest.Auth.CreateTokenRequestAsync(tokenParams); // ... issue the TokenRequest to a client ... } @@ -338,7 +338,7 @@ public static async Task RestAuthorizeSample() try { var tokenParams = new TokenParams { ClientId = "bob" }; - var tokenRequest = await client.Auth.CreateTokenRequestObjectAsync(tokenParams); + var tokenRequest = await client.Auth.CreateTokenRequestAsync(tokenParams); Console.WriteLine("Success; token request issued"); } catch (AblyException e) diff --git a/src/IO.Ably.Tests.Shared/Samples/RealtimeSamples.cs b/src/IO.Ably.Tests.Shared/Samples/RealtimeSamples.cs index 5622db3c8..f0a6fd8b8 100644 --- a/src/IO.Ably.Tests.Shared/Samples/RealtimeSamples.cs +++ b/src/IO.Ably.Tests.Shared/Samples/RealtimeSamples.cs @@ -197,7 +197,7 @@ public async Task RestApiSamples() var tokenString = token.Token; // "xVLyHw.CLchevH3hF....MDh9ZC_Q" var tokenClient = new AblyRest(new ClientOptions { TokenDetails = token }); - var tokenRequest = await client.Auth.CreateTokenRequestObjectAsync(); + var tokenRequest = await client.Auth.CreateTokenRequestAsync(); // Stats var stats = await client.StatsAsync(); From 29bb790a8b24a6e507a129dac6353d59798dff6b Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 16 Apr 2024 16:24:22 +0530 Subject: [PATCH 05/19] Fixed failing test for authcallback returning tokenrequest or tokendetails --- src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs b/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs index beb80f61b..a1cd45dbc 100644 --- a/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Rest/RestSpecs.cs @@ -815,18 +815,18 @@ await Assert.ThrowsAsync(() => } [Fact] - public async Task WhenCallbackReturnsAnObjectThatIsNotTokenRequestOrTokenDetails_ThrowsAblyException() + public async Task WhenAuthCallbackReturnsAnObjectThatIsNotTokenRequestOrTokenDetails_ThrowsAblyException() { - var signedTokenRequest = await new AblyRest("fake.key:fakeid").Auth.CreateTokenRequestAsync(); - // do not throw exceptions - var objects = new object[] { new TokenDetails(), new TokenRequest() }; + string serializedTokenRequest = await new AblyRest("fake.key:fakeid").Auth.CreateTokenRequestAsync(); + // do not throw exceptions for valid values in authCallback + var objects = new object[] { new TokenDetails(), new TokenRequest(), serializedTokenRequest }; foreach (var obj in objects) { - var exception = await Record.ExceptionAsync(async () => await GetClient(_ => Task.FromResult(obj)).StatsAsync()); + var exception = await Record.ExceptionAsync(async () => await GetClient(_ => Task.FromResult(obj)).StatsAsync()); Assert.Null(exception); } - // throw exceptions + // throw exceptions for invalid values in authCallback objects = new[] { new object(), string.Empty, new Uri("http://test"), "jwtToken" }; foreach (var obj in objects) { @@ -846,7 +846,10 @@ private static AblyRest GetClient(Func> authCallback) }; var rest = new AblyRest(options); - rest.ExecuteHttpRequest = delegate { return "[{}]".ToAblyResponse(); }; + rest.ExecuteHttpRequest = arg => arg.Url.Contains("requestToken") ? + JsonHelper.Serialize(new TokenDetails()).ToAblyResponse() : + "[{}]".ToAblyResponse(); + return rest; } } From 958a788705865499b658498a51d6e323387393f8 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 16 Apr 2024 17:14:44 +0530 Subject: [PATCH 06/19] Fixed failing flaky test due to provided httprequesttimeout --- src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs b/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs index 78369caf8..402927e5d 100644 --- a/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Rest/RequestSandBoxSpecs.cs @@ -371,7 +371,6 @@ public async Task RequestFails_Non200StatusResponseShouldNotRaiseException(Proto { options.HttpMaxRetryCount = 1; options.HttpOpenTimeout = TimeSpan.FromSeconds(1); - options.HttpRequestTimeout = TimeSpan.FromSeconds(1); })); client.HttpClient.SetPreferredHost("echo.ably.io/respondwith?status=400"); From d733f1457667be3e83b4a821b13049afbe807835 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 16 Apr 2024 17:47:40 +0530 Subject: [PATCH 07/19] Updated authcallback documentation for ably-dotnet as per latest tokenRequest format --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 1b2b2b7cf..82acae1ca 100644 --- a/README.md +++ b/README.md @@ -386,7 +386,7 @@ foreach (var presenceMessage in nextPage.Items) ### Using the AuthCallback -A callback to obtain a signed `TokenRequest` string or a `TokenDetails` instance. +A callback to obtain a `IO.Ably.TokenDetails`/`IO.Ably.TokenRequest` instance or serialized `TokenRequest` string. To use `AuthCallback` create a `ClientOptions` instance and assign an appropriate delegate to the `AuthCallback` property and pass the `ClientOptions` to a new `AblyRealtime` instance. @@ -395,7 +395,7 @@ var options = new ClientOptions { AuthCallback = async tokenParams => { - // Return a 'TokenDetails'/'TokenRequest' object or a token string . + // Return a 'IO.Ably.TokenDetails'/'IO.Ably.TokenRequest' object or a serialized tokenRequest string . // Typically this method would wrap a request to your web server. return await GetTokenDetailsOrTokenRequestStringFromYourServer(); } @@ -408,7 +408,13 @@ var client = new AblyRealtime(options); Token requests are issued by your servers and signed using your private API key. This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably. ```csharp -TokenRequest tokenRequest = await client.Auth.CreateTokenRequestObjectAsync(); +string tokenRequest = await client.Auth.CreateTokenRequestAsync(); +``` + +While returning tokenRequest string to the client, make sure to set `contentType` as json. +e.g. +``` +return Content(tokenRequest, "application/json"); ``` ### Fetching your application's stats From b23c40476739d415afde2b3ea80208e8be3396f7 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 16 Apr 2024 17:54:49 +0530 Subject: [PATCH 08/19] Updated token based auth README for ably-dotnet --- README.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 82acae1ca..bde15e9ca 100644 --- a/README.md +++ b/README.md @@ -407,14 +407,12 @@ var client = new AblyRealtime(options); Token requests are issued by your servers and signed using your private API key. This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably. -```csharp -string tokenRequest = await client.Auth.CreateTokenRequestAsync(); -``` - -While returning tokenRequest string to the client, make sure to set `contentType` as json. e.g. -``` -return Content(tokenRequest, "application/json"); +```csharp +app.MapGet("/token", async() => { + var tokenRequest = await rest.Auth.CreateTokenRequestAsync(); + return Content(tokenRequest, "application/json"); // make sure to set `contentType` as json. +}); ``` ### Fetching your application's stats From e6371e989af2e8fbe5e1eea3cfd1e6718f6e3cf0 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Tue, 16 Apr 2024 23:30:55 +0530 Subject: [PATCH 09/19] updated auth documentation for dotnet --- README.md | 52 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index bde15e9ca..5cd220831 100644 --- a/README.md +++ b/README.md @@ -384,36 +384,56 @@ foreach (var presenceMessage in nextPage.Items) } ``` -### Using the AuthCallback +### Authentication +- It is recommended to use `ABLY_KEY` at server side. Check [official ably auth documentation](https://ably.com/docs/auth) for more info. +- `ABLY_KEY` should not be exposed at client side where it can be used for unintentional purposes. +- Server can use `ABLY_KEY` for initializing the `AblyRest` instance. -A callback to obtain a `IO.Ably.TokenDetails`/`IO.Ably.TokenRequest` instance or serialized `TokenRequest` string. +```csharp +var rest = new AblyRest("API_KEY"); +``` +- Token requests are issued by your servers and signed using your private API key. +- This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably. +- Tokens issued using `tokenRequest` can only be used once by the client. +e.g. ASP.Net server app +```csharp +app.MapGet("/token", async() => { + string tokenRequest = await rest.Auth.CreateTokenRequestAsync(); + return Content(tokenRequest, "application/json"); // make sure to set `contentType` as json. +}); +``` +- You can also return JWT string token signed using `ABLY_KEY` as per [official ably JWT doc](https://ably.com/tutorials/jwt-authentication). +- Unline tokenrequests, JWT token can be used by the client multiple times till it's 'expiry. + +### Using the Token auth at client side -To use `AuthCallback` create a `ClientOptions` instance and assign an appropriate delegate to the `AuthCallback` property and pass the `ClientOptions` to a new `AblyRealtime` instance. +- To use `AuthCallback` create a `ClientOptions` instance and assign an appropriate delegate to the `AuthCallback` property and pass the `ClientOptions` to a new `AblyRealtime` instance. ```csharp var options = new ClientOptions { AuthCallback = async tokenParams => { - // Return a 'IO.Ably.TokenDetails'/'IO.Ably.TokenRequest' object or a serialized tokenRequest string . - // Typically this method would wrap a request to your web server. - return await GetTokenDetailsOrTokenRequestStringFromYourServer(); + // Return serialized tokenRequest string or 'IO.Ably.TokenRequest' object + return await TokenRequestStringFromYourServer(tokenParams); // tokenRequest will be used to obtain token from ably server. } }; var client = new AblyRealtime(options); ``` - -### Generate a TokenRequest - -Token requests are issued by your servers and signed using your private API key. This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably. - -e.g. +- If JWT token is returned by server ```csharp -app.MapGet("/token", async() => { - var tokenRequest = await rest.Auth.CreateTokenRequestAsync(); - return Content(tokenRequest, "application/json"); // make sure to set `contentType` as json. -}); +var options = new ClientOptions +{ + AuthCallback = async tokenParams => + { + // Return serialized jwttokenstring returned from server + string jwtToken = await getJwtTokenFromServer(tokenParams); + return await new TokenDetails(jwtToken); // jwt token will directly be used to authenticate with server. + } +}; ``` +- Please note that there is no intermediate step to obtain token from server, jwt will directly be used to authenticate with ably. +- Do check [official token auth documentation](https://ably.com/docs/auth/token?lang=csharp) for more information. ### Fetching your application's stats From dd8c53da228b49c3dcb1b49fbb572e67253ba23e Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Wed, 17 Apr 2024 13:44:53 +0530 Subject: [PATCH 10/19] Updated ably-dotnet auth documentation for README --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5cd220831..5dc334c0f 100644 --- a/README.md +++ b/README.md @@ -394,7 +394,6 @@ var rest = new AblyRest("API_KEY"); ``` - Token requests are issued by your servers and signed using your private API key. - This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably. -- Tokens issued using `tokenRequest` can only be used once by the client. e.g. ASP.Net server app ```csharp app.MapGet("/token", async() => { @@ -403,7 +402,6 @@ app.MapGet("/token", async() => { }); ``` - You can also return JWT string token signed using `ABLY_KEY` as per [official ably JWT doc](https://ably.com/tutorials/jwt-authentication). -- Unline tokenrequests, JWT token can be used by the client multiple times till it's 'expiry. ### Using the Token auth at client side From 1197d1b3621aa49725e9ad155aadc6804d4a33b1 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 14:04:00 +0530 Subject: [PATCH 11/19] Fixed failing flaky tests --- src/IO.Ably.Tests.Shared/Realtime/ChannelSpecs.cs | 1 + src/IO.Ably.Tests.Shared/StatsParsingTests.cs | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/Realtime/ChannelSpecs.cs b/src/IO.Ably.Tests.Shared/Realtime/ChannelSpecs.cs index 8b1ace3af..863ba6628 100644 --- a/src/IO.Ably.Tests.Shared/Realtime/ChannelSpecs.cs +++ b/src/IO.Ably.Tests.Shared/Realtime/ChannelSpecs.cs @@ -931,6 +931,7 @@ public async Task WithNameAndData_ShouldSendASingleProtocolMessageWithASingleEnc await channel.PublishAsync("byte", bytes); + await new ConditionalAwaiter(() => LastCreatedTransport.LastMessageSend.Messages.Length > 0); var sentMessage = LastCreatedTransport.LastMessageSend.Messages.First(); LastCreatedTransport.SentMessages.Should().HaveCount(1); sentMessage.Encoding.Should().Be("base64"); diff --git a/src/IO.Ably.Tests.Shared/StatsParsingTests.cs b/src/IO.Ably.Tests.Shared/StatsParsingTests.cs index eb9d793a1..893641d74 100644 --- a/src/IO.Ably.Tests.Shared/StatsParsingTests.cs +++ b/src/IO.Ably.Tests.Shared/StatsParsingTests.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Linq; using FluentAssertions; @@ -148,9 +149,9 @@ public void TokenRequestsHasCorrectValues() } [Fact] - public void IntervalIDHasCorrectValue() + public void IntervalIdHasCorrectValue() { - _stats.Interval.Should().Be(DateHelper.CreateDate(2014, 01, 01, 16, 24)); + _stats.Interval.Should().Be(new DateTime(2014, 01, 01, 16, 24, 0)); } } } From 856ebd33b5180d877ba42953255919c7fb7fb9ae Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 15:56:50 +0530 Subject: [PATCH 12/19] Fixed flaky failing test for authsandboxspec --- src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs b/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs index 1610c670b..d4e9219f5 100644 --- a/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs +++ b/src/IO.Ably.Tests.Shared/AuthTests/AuthSandboxSpecs.cs @@ -321,7 +321,7 @@ public async Task RealTimeWithAuthUrl_WhenTokenExpired_And_WithServerTime_And_No }; await Task.Delay(2000); // This makes sure we get server time - ((AblyAuth)mainClient.Auth).SetServerTime(); + await ((AblyAuth)mainClient.Auth).SetServerTime(); var ex = await Assert.ThrowsAsync(() => mainClient.StatsAsync()); ex.ErrorInfo.Should().BeSameAs(ErrorInfo.NonRenewableToken); @@ -338,7 +338,7 @@ public async Task Auth_WithRealtimeClient_WhenAuthFails_ShouldTransitionToOrRema { async Task TestConnectingBecomesDisconnected(string context, Action optionsAction) { - TaskCompletionAwaiter tca = new TaskCompletionAwaiter(5000); + TaskCompletionAwaiter tca = new TaskCompletionAwaiter(); var realtimeClient = await GetRealtimeClient(protocol, optionsAction); realtimeClient.Connection.On(ConnectionEvent.Disconnected, change => { @@ -387,7 +387,7 @@ async Task GetToken() var authRestClient = await GetRestClient(protocol); var token = await authRestClient.Auth.RequestTokenAsync(new TokenParams { - Ttl = TimeSpan.FromMilliseconds(2000) + Ttl = TimeSpan.FromMilliseconds(10000) }); return token; } From 1bf02188a7bbb2d77568f3e8e75e63dca54ebba6 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 16:58:12 +0530 Subject: [PATCH 13/19] Added timeout to conditionerWaiter test helper --- .../Infrastructure/ConditionalAwaiter.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/Infrastructure/ConditionalAwaiter.cs b/src/IO.Ably.Tests.Shared/Infrastructure/ConditionalAwaiter.cs index 6bc7f9568..83a543dae 100644 --- a/src/IO.Ably.Tests.Shared/Infrastructure/ConditionalAwaiter.cs +++ b/src/IO.Ably.Tests.Shared/Infrastructure/ConditionalAwaiter.cs @@ -14,8 +14,9 @@ public sealed class ConditionalAwaiter : IDisposable private readonly Timer _timer; private readonly TaskCompletionSource _completionSource; private int _tickCount; + private readonly int _timeout; - public ConditionalAwaiter(Func condition, Func getError = null) + public ConditionalAwaiter(Func condition, Func getError = null, int timeout = 10) { _condition = condition; _getError = getError; @@ -26,6 +27,7 @@ public ConditionalAwaiter(Func condition, Func getError = null) }; _timer.Elapsed += TimerOnElapsed; _completionSource = new TaskCompletionSource(); + _timeout = timeout; } public TaskAwaiter GetAwaiter() @@ -36,9 +38,9 @@ public TaskAwaiter GetAwaiter() private void TimerOnElapsed(object sender, ElapsedEventArgs e) { Interlocked.Increment(ref _tickCount); - if (_tickCount > 100) + if (_tickCount > _timeout * 10) { - string message = "10 seconds elapsed. Giving up."; + string message = $"{_timeout} seconds elapsed. Giving up."; if (_getError != null) { message += " Error: " + _getError(); From e53459e533482780c02d78e62c3c4845be18874e Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 17:12:45 +0530 Subject: [PATCH 14/19] updated README for jwt auth --- README.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 5dc334c0f..45bb9f8e9 100644 --- a/README.md +++ b/README.md @@ -426,11 +426,13 @@ var options = new ClientOptions { // Return serialized jwttokenstring returned from server string jwtToken = await getJwtTokenFromServer(tokenParams); - return await new TokenDetails(jwtToken); // jwt token will directly be used to authenticate with server. + int expiresIn = 3600; // assuming jwtToken has 1 hr expiry + return new TokenDetails(jwtToken) { + Expires = DateTimeOffset.UtcNow.AddSeconds(expiresIn) + }; // jwt token will directly be used to authenticate with server. } }; ``` -- Please note that there is no intermediate step to obtain token from server, jwt will directly be used to authenticate with ably. - Do check [official token auth documentation](https://ably.com/docs/auth/token?lang=csharp) for more information. ### Fetching your application's stats From 7e95ae094b6c7988e0eea303323d2c62a445cfab Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 17:20:34 +0530 Subject: [PATCH 15/19] Fixed flaky taskCompletionAwaiterTest --- .../Infrastructure/TaskCompleterAwaiterTests.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs b/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs index 8fb8ff278..d0e634554 100644 --- a/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs +++ b/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs @@ -16,8 +16,8 @@ public void TimeoutElapsedIsInitiallyFalse() [Fact] public async void TimeoutElapsedSignalsOnTimeout() { - var sut = new TaskCompletionAwaiter(10); - await Task.Delay(1000); + var sut = new TaskCompletionAwaiter(500); + await Task.Delay(2000); sut.TimeoutExpired.Should().BeTrue(); } } From 7c10489163d9f3cd54c2358bd87a0db1f54b2250 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 17:23:43 +0530 Subject: [PATCH 16/19] updated project to use dotnet v7 for build purpose --- .github/workflows/package.yml | 4 ++-- .github/workflows/run-tests-linux.yml | 2 +- .github/workflows/run-tests-macos.yml | 2 +- .github/workflows/run-tests-windows.yml | 2 +- global.json | 4 ++-- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/package.yml b/.github/workflows/package.yml index 370d130aa..b8236e0af 100644 --- a/.github/workflows/package.yml +++ b/.github/workflows/package.yml @@ -19,7 +19,7 @@ jobs: dotnet-version: | 3.1.x 6.0.403 - 7.0.100 + 7.0.408 - name: Download fake-cli run: dotnet tool restore - name: Package @@ -46,7 +46,7 @@ jobs: dotnet-version: | 3.1.x 6.0.403 - 7.0.100 + 7.0.408 - name: Download fake-cli run: dotnet tool install fake-cli --version 5.20.4 --tool-path . - name: Restore packages diff --git a/.github/workflows/run-tests-linux.yml b/.github/workflows/run-tests-linux.yml index a73ea8cb7..06ff9df90 100644 --- a/.github/workflows/run-tests-linux.yml +++ b/.github/workflows/run-tests-linux.yml @@ -25,7 +25,7 @@ jobs: with: dotnet-version: | 6.0.403 - 7.0.100 + 7.0.408 - name: Download dotnet build-script tools run: dotnet tool restore diff --git a/.github/workflows/run-tests-macos.yml b/.github/workflows/run-tests-macos.yml index 4170caffc..bb0e51648 100644 --- a/.github/workflows/run-tests-macos.yml +++ b/.github/workflows/run-tests-macos.yml @@ -25,7 +25,7 @@ jobs: with: dotnet-version: | 6.0.403 - 7.0.100 + 7.0.408 - name: Download dotnet build-script tools run: dotnet tool restore diff --git a/.github/workflows/run-tests-windows.yml b/.github/workflows/run-tests-windows.yml index 161ede25e..f65002c97 100644 --- a/.github/workflows/run-tests-windows.yml +++ b/.github/workflows/run-tests-windows.yml @@ -25,7 +25,7 @@ jobs: with: dotnet-version: | 6.0.403 - 7.0.100 + 7.0.408 - name: Download dotnet build-script tools run: dotnet tool restore diff --git a/global.json b/global.json index 0f050ba53..9f0243760 100644 --- a/global.json +++ b/global.json @@ -1,6 +1,6 @@ { "sdk": { - "version": "6.0.300", - "rollForward": "latestMajor" + "version": "7.0.408", + "rollForward": "disable" } } From 438f09ec7bd1cacb8a6acdba0ed493ccbc8bacc3 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 17:31:42 +0530 Subject: [PATCH 17/19] Ignore flaky test helper test for calculating timeout elapsed --- .../Infrastructure/TaskCompleterAwaiterTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs b/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs index d0e634554..00faf1b6c 100644 --- a/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs +++ b/src/IO.Ably.Tests.Shared/Infrastructure/TaskCompleterAwaiterTests.cs @@ -13,11 +13,11 @@ public void TimeoutElapsedIsInitiallyFalse() sut.TimeoutExpired.Should().BeFalse(); } - [Fact] + [Fact(Skip = "Flaky test, keeps failing on CI. Since this is a test helper, no need to test on CI")] public async void TimeoutElapsedSignalsOnTimeout() { - var sut = new TaskCompletionAwaiter(500); - await Task.Delay(2000); + var sut = new TaskCompletionAwaiter(2000); + await Task.Delay(5000); sut.TimeoutExpired.Should().BeTrue(); } } From 2f2b195acaee4996a13710462849e95616b5d9e3 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 23:06:52 +0530 Subject: [PATCH 18/19] Refactored README with better readability --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 45bb9f8e9..06e0a190b 100644 --- a/README.md +++ b/README.md @@ -386,7 +386,7 @@ foreach (var presenceMessage in nextPage.Items) ### Authentication - It is recommended to use `ABLY_KEY` at server side. Check [official ably auth documentation](https://ably.com/docs/auth) for more info. -- `ABLY_KEY` should not be exposed at client side where it can be used for unintentional purposes. +- `ABLY_KEY` should not be exposed at client side where it can be used for malicious purposes. - Server can use `ABLY_KEY` for initializing the `AblyRest` instance. ```csharp @@ -394,8 +394,8 @@ var rest = new AblyRest("API_KEY"); ``` - Token requests are issued by your servers and signed using your private API key. - This is the preferred method of authentication as no secrets are ever shared, and the token request can be issued to trusted clients without communicating with Ably. -e.g. ASP.Net server app ```csharp +// e.g. ASP.Net server endpoint app.MapGet("/token", async() => { string tokenRequest = await rest.Auth.CreateTokenRequestAsync(); return Content(tokenRequest, "application/json"); // make sure to set `contentType` as json. @@ -405,7 +405,7 @@ app.MapGet("/token", async() => { ### Using the Token auth at client side -- To use `AuthCallback` create a `ClientOptions` instance and assign an appropriate delegate to the `AuthCallback` property and pass the `ClientOptions` to a new `AblyRealtime` instance. +- Create `ClientOptions` instance with `AuthCallback` property ```csharp var options = new ClientOptions @@ -429,11 +429,11 @@ var options = new ClientOptions int expiresIn = 3600; // assuming jwtToken has 1 hr expiry return new TokenDetails(jwtToken) { Expires = DateTimeOffset.UtcNow.AddSeconds(expiresIn) - }; // jwt token will directly be used to authenticate with server. + }; // jwt token will directly be used to authenticate with ably server. } }; ``` -- Do check [official token auth documentation](https://ably.com/docs/auth/token?lang=csharp) for more information. +- Check [official token auth documentation](https://ably.com/docs/auth/token?lang=csharp) for more information. ### Fetching your application's stats From dcfc3f063165762c3487eb55d8b29d4b4a48bea5 Mon Sep 17 00:00:00 2001 From: sacOO7 Date: Thu, 18 Apr 2024 23:17:14 +0530 Subject: [PATCH 19/19] updated deprecation warnings for createTokenRequestObject --- src/IO.Ably.Shared/IAblyAuth.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/IO.Ably.Shared/IAblyAuth.cs b/src/IO.Ably.Shared/IAblyAuth.cs index a7998273e..903f9cd20 100644 --- a/src/IO.Ably.Shared/IAblyAuth.cs +++ b/src/IO.Ably.Shared/IAblyAuth.cs @@ -67,7 +67,7 @@ public interface IAblyAuth /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// signed token request. - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObjectAsync instead")] + [Obsolete("This method will be removed in a future version, please use CreateTokenRequestAsync instead")] Task CreateTokenRequestObjectAsync(TokenParams tokenParams = null, AuthOptions authOptions = null); /// @@ -116,7 +116,7 @@ public interface IAblyAuth /// . If null a token request is generated from options passed when the client was created. /// . If null the default AuthOptions are used. /// signed token request. - [Obsolete("This method will be removed in a future version, please use CreateTokenRequestObject instead")] + [Obsolete("This method will be removed in a future version, please use CreateTokenRequest instead")] TokenRequest CreateTokenRequestObject(TokenParams tokenParams = null, AuthOptions authOptions = null); } }