diff --git a/API.IntegrationTests/AccountTests.cs b/API.IntegrationTests/AccountTests.cs index 0d0a9b08..99e8a47b 100644 --- a/API.IntegrationTests/AccountTests.cs +++ b/API.IntegrationTests/AccountTests.cs @@ -16,7 +16,7 @@ public async Task CreateAccount_ShouldAdd_NewUserToDatabase() username = "Bob", password = "SecurePassword123#", email = "bob@example.com", - turnstileresponse = "lmao" + turnstileresponse = "valid-token" }); diff --git a/API.IntegrationTests/HttpMessageHandlers/InterceptedHttpMessageHandler.cs b/API.IntegrationTests/HttpMessageHandlers/InterceptedHttpMessageHandler.cs new file mode 100644 index 00000000..7302613b --- /dev/null +++ b/API.IntegrationTests/HttpMessageHandlers/InterceptedHttpMessageHandler.cs @@ -0,0 +1,80 @@ +using System.Net; +using System.Text.Json; +using System.Web; + +namespace OpenShock.API.IntegrationTests.HttpMessageHandlers; + +sealed class InterceptedHttpMessageHandler : DelegatingHandler +{ + private async Task HandleCloudflareTurnstileRequest(HttpRequestMessage request, CancellationToken cancellationToken) + { + var formData = request.Content != null ? await request.Content.ReadAsStringAsync(cancellationToken) : string.Empty; + var parsedForm = HttpUtility.ParseQueryString(formData); + var responseToken = parsedForm["response"]; + + var responseDto = responseToken switch + { + "valid-token" => new CloudflareTurnstileVerifyResponseDto + { + Success = true, + ErrorCodes = [], + ChallengeTs = DateTime.UtcNow, + Hostname = "validhost", + Action = "validaction", + Cdata = "" + }, + "invalid-token" => new CloudflareTurnstileVerifyResponseDto + { + Success = false, + ErrorCodes = ["invalid-input-response"], + ChallengeTs = DateTime.UtcNow, + Hostname = "invalidhost", + Action = "invalidaction", + Cdata = "" + }, + _ => new CloudflareTurnstileVerifyResponseDto + { + Success = false, + ErrorCodes = ["bad-request"], + ChallengeTs = DateTime.UtcNow, + Hostname = "unknownhost", + Action = "unknownaction", + Cdata = "" + } + }; + + var responseJson = JsonSerializer.Serialize(responseDto); + + var responseMessage = new HttpResponseMessage(HttpStatusCode.OK) + { + Content = new StringContent(responseJson, System.Text.Encoding.UTF8, "application/json") + }; + + return responseMessage; + } + + private async Task HandleMailJetApiHost(HttpRequestMessage request, CancellationToken cancellationToken) + { + return new HttpResponseMessage(HttpStatusCode.NotFound); + } + + protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) + { + return request.RequestUri switch + { + { Host: "challenges.cloudflare.com", AbsolutePath: "/turnstile/v0/siteverify" } => await HandleCloudflareTurnstileRequest(request, cancellationToken), + { Host: "api.mailjet.com" } => await HandleMailJetApiHost(request, cancellationToken), + _ => new HttpResponseMessage(HttpStatusCode.NotFound) + }; + } + + private class CloudflareTurnstileVerifyResponseDto + { + public bool Success { get; set; } + public string[] ErrorCodes { get; set; } + public DateTime ChallengeTs { get; set; } + public string Hostname { get; set; } + public string Action { get; set; } + public string Cdata { get; set; } + } +} \ No newline at end of file diff --git a/API.IntegrationTests/HttpMessageHandlers/InterceptedHttpMessageHandlerBuilder.cs b/API.IntegrationTests/HttpMessageHandlers/InterceptedHttpMessageHandlerBuilder.cs new file mode 100644 index 00000000..f4444f8e --- /dev/null +++ b/API.IntegrationTests/HttpMessageHandlers/InterceptedHttpMessageHandlerBuilder.cs @@ -0,0 +1,16 @@ +using Microsoft.Extensions.Http; + +namespace OpenShock.API.IntegrationTests.HttpMessageHandlers; + +sealed class InterceptedHttpMessageHandlerBuilder : HttpMessageHandlerBuilder +{ + public override string? Name { get; set; } + public override HttpMessageHandler PrimaryHandler { get; set; } + public override IList AdditionalHandlers => []; + + + public override HttpMessageHandler Build() + { + return new InterceptedHttpMessageHandler(); + } +} diff --git a/API.IntegrationTests/IntegrationTestWebAppFactory.cs b/API.IntegrationTests/IntegrationTestWebAppFactory.cs index e0d4bd5c..80d3b2a9 100644 --- a/API.IntegrationTests/IntegrationTestWebAppFactory.cs +++ b/API.IntegrationTests/IntegrationTestWebAppFactory.cs @@ -1,6 +1,11 @@ using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Mvc.Testing; using Microsoft.AspNetCore.TestHost; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.DependencyInjection.Extensions; +using Microsoft.Extensions.Http; +using OpenShock.API.IntegrationTests.HttpMessageHandlers; +using OpenShock.Common.Services.Turnstile; using Testcontainers.PostgreSql; using Testcontainers.Redis; using TUnit.Core.Interfaces; @@ -78,7 +83,7 @@ protected override void ConfigureWebHost(IWebHostBuilder builder) builder.ConfigureTestServices(services => { - // We can replace services here + services.AddTransient(); }); }