diff --git a/.github/workflows/dotnetcore.yml b/.github/workflows/dotnetcore.yml index c36fc10..8711eff 100644 --- a/.github/workflows/dotnetcore.yml +++ b/.github/workflows/dotnetcore.yml @@ -12,7 +12,7 @@ jobs: - name: Setup .NET Core uses: actions/setup-dotnet@v1 with: - dotnet-version: 3.1.100 + dotnet-version: 5.0.100 - name: Build with dotnet run: dotnet build -c Release - name: Test with dotnet diff --git a/demo/reCAPTCHA.Demo/Pages/V2_Checkbox.cshtml.cs b/demo/reCAPTCHA.Demo/Pages/V2_Checkbox.cshtml.cs index 8a57dd3..538209b 100644 --- a/demo/reCAPTCHA.Demo/Pages/V2_Checkbox.cshtml.cs +++ b/demo/reCAPTCHA.Demo/Pages/V2_Checkbox.cshtml.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System.Text.Json; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.RazorPages; -using Newtonsoft.Json; using Owl.reCAPTCHA; using Owl.reCAPTCHA.v2; @@ -22,10 +22,13 @@ public async Task OnPostAsync(string token) var response = await _siteVerify.Verify(new reCAPTCHASiteVerifyRequest { Response = token, - RemoteIp = HttpContext.Connection.RemoteIpAddress.ToString() + RemoteIp = HttpContext.Connection.RemoteIpAddress?.ToString() }); - Result = JsonConvert.SerializeObject(response, Formatting.Indented); + Result = JsonSerializer.Serialize(response, new JsonSerializerOptions + { + WriteIndented = true + }); } } -} \ No newline at end of file +} diff --git a/demo/reCAPTCHA.Demo/Pages/V2_Invisible.cshtml.cs b/demo/reCAPTCHA.Demo/Pages/V2_Invisible.cshtml.cs index 32c9c7e..47d8655 100644 --- a/demo/reCAPTCHA.Demo/Pages/V2_Invisible.cshtml.cs +++ b/demo/reCAPTCHA.Demo/Pages/V2_Invisible.cshtml.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System.Text.Json; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.RazorPages; -using Newtonsoft.Json; using Owl.reCAPTCHA; using Owl.reCAPTCHA.v2; @@ -22,10 +22,13 @@ public async Task OnPostAsync(string token) var response = await _siteVerify.Verify(new reCAPTCHASiteVerifyRequest { Response = token, - RemoteIp = HttpContext.Connection.RemoteIpAddress.ToString() + RemoteIp = HttpContext.Connection.RemoteIpAddress?.ToString() }); - Result = JsonConvert.SerializeObject(response, Formatting.Indented); + Result = JsonSerializer.Serialize(response, new JsonSerializerOptions + { + WriteIndented = true + }); } } -} \ No newline at end of file +} diff --git a/demo/reCAPTCHA.Demo/Pages/V3.cshtml.cs b/demo/reCAPTCHA.Demo/Pages/V3.cshtml.cs index dc6f7a2..7c785d3 100644 --- a/demo/reCAPTCHA.Demo/Pages/V3.cshtml.cs +++ b/demo/reCAPTCHA.Demo/Pages/V3.cshtml.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System.Text.Json; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.RazorPages; -using Newtonsoft.Json; using Owl.reCAPTCHA; using Owl.reCAPTCHA.v3; @@ -22,10 +22,13 @@ public async Task OnPostAsync(string token) var response = await _siteVerify.Verify(new reCAPTCHASiteVerifyRequest { Response = token, - RemoteIp = HttpContext.Connection.RemoteIpAddress.ToString() + RemoteIp = HttpContext.Connection.RemoteIpAddress?.ToString() }); - Result = JsonConvert.SerializeObject(response, Formatting.Indented); + Result = JsonSerializer.Serialize(response, new JsonSerializerOptions + { + WriteIndented = true + }); } } -} \ No newline at end of file +} diff --git a/demo/reCAPTCHA.Demo/Pages/V3_Programmatically.cshtml.cs b/demo/reCAPTCHA.Demo/Pages/V3_Programmatically.cshtml.cs index f23d1a4..e132779 100644 --- a/demo/reCAPTCHA.Demo/Pages/V3_Programmatically.cshtml.cs +++ b/demo/reCAPTCHA.Demo/Pages/V3_Programmatically.cshtml.cs @@ -1,6 +1,6 @@ -using System.Threading.Tasks; +using System.Text.Json; +using System.Threading.Tasks; using Microsoft.AspNetCore.Mvc.RazorPages; -using Newtonsoft.Json; using Owl.reCAPTCHA; using Owl.reCAPTCHA.v3; @@ -22,10 +22,13 @@ public async Task OnPostAsync(string token) var response = await _siteVerify.Verify(new reCAPTCHASiteVerifyRequest { Response = token, - RemoteIp = HttpContext.Connection.RemoteIpAddress.ToString() + RemoteIp = HttpContext.Connection.RemoteIpAddress?.ToString() }); - Result = JsonConvert.SerializeObject(response, Formatting.Indented); + Result = JsonSerializer.Serialize(response, new JsonSerializerOptions + { + WriteIndented = true + }); } } } diff --git a/demo/reCAPTCHA.Demo/Startup.cs b/demo/reCAPTCHA.Demo/Startup.cs index f152444..6952e4a 100644 --- a/demo/reCAPTCHA.Demo/Startup.cs +++ b/demo/reCAPTCHA.Demo/Startup.cs @@ -19,7 +19,7 @@ public Startup(IConfiguration configuration) // This method gets called by the runtime. Use this method to add services to the container. public void ConfigureServices(IServiceCollection services) { - services.AddRazorPages().AddRazorRuntimeCompilation(); + services.AddRazorPages(); services.AddreCAPTCHAV3(x => { diff --git a/demo/reCAPTCHA.Demo/reCAPTCHA.Demo.csproj b/demo/reCAPTCHA.Demo/reCAPTCHA.Demo.csproj index 491fe10..caaf366 100644 --- a/demo/reCAPTCHA.Demo/reCAPTCHA.Demo.csproj +++ b/demo/reCAPTCHA.Demo/reCAPTCHA.Demo.csproj @@ -4,16 +4,6 @@ net5.0 - - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - - - - diff --git a/src/Owl.reCAPTCHA/Owl.reCAPTCHA.csproj b/src/Owl.reCAPTCHA/Owl.reCAPTCHA.csproj index d286373..8f3573e 100644 --- a/src/Owl.reCAPTCHA/Owl.reCAPTCHA.csproj +++ b/src/Owl.reCAPTCHA/Owl.reCAPTCHA.csproj @@ -5,24 +5,20 @@ Owl.reCAPTCHA Owl.reCAPTCHA maliming - reCAPTCHA for Asp Net Core 3.0 + reCAPTCHA for Asp Net Core 5.0 https://github.com/maliming/reCAPTCHA https://github.com/maliming/reCAPTCHA git - 0.3.0 + 0.4.0 true Library true true - - $(AllowedOutputExtensionsInPackageBuildOutputFolder);.pdb - 0.3.1 + 0.4.0 - - - + diff --git a/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponse.cs b/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponse.cs index 711820b..c446e3d 100644 --- a/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponse.cs +++ b/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponse.cs @@ -1,5 +1,4 @@ using System; -using Newtonsoft.Json; namespace Owl.reCAPTCHA { @@ -9,13 +8,11 @@ public class reCAPTCHASiteVerifyResponse public bool Success { get; set; } // timestamp of the challenge load (ISO format yyyy-MM-dd'T'HH:mm:ssZZ) - [JsonProperty("challenge_ts")] public DateTime ChallengeTs { get; set; } // the hostname of the site where the reCAPTCHA was solved public string HostName { get; set; } - [JsonProperty("error-codes")] public string[] ErrorCodes { get; set; } } -} \ No newline at end of file +} diff --git a/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponseJsonConverter.cs b/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponseJsonConverter.cs new file mode 100644 index 0000000..5986e45 --- /dev/null +++ b/src/Owl.reCAPTCHA/reCAPTCHASiteVerifyResponseJsonConverter.cs @@ -0,0 +1,60 @@ +using System; +using System.Linq; +using System.Text.Json; +using System.Text.Json.Serialization; +using Owl.reCAPTCHA.v3; + +namespace Owl.reCAPTCHA +{ + public class reCAPTCHASiteVerifyResponseJsonConverter : JsonConverter + { + public override bool CanConvert(Type typeToConvert) + { + return typeToConvert == typeof(reCAPTCHASiteVerifyV3Response) || + typeToConvert == typeof(reCAPTCHASiteVerifyResponse); + } + + public override reCAPTCHASiteVerifyResponse Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + var rootElement = JsonDocument.ParseValue(ref reader).RootElement; + + var success = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("success", StringComparison.InvariantCultureIgnoreCase)); + var challengeTimestamp = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("challenge_ts", StringComparison.InvariantCultureIgnoreCase)); + var hostname = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("hostname", StringComparison.InvariantCultureIgnoreCase)); + var errorCodes = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("error-codes", StringComparison.InvariantCultureIgnoreCase)); + + if (typeToConvert == typeof(reCAPTCHASiteVerifyResponse)) + { + return new reCAPTCHASiteVerifyResponse + { + Success = success.Value.ValueKind == JsonValueKind.True, + ChallengeTs = challengeTimestamp.Value.ValueKind == JsonValueKind.String ? challengeTimestamp.Value.GetDateTime() : DateTime.MinValue, + HostName = hostname.Value.ValueKind == JsonValueKind.String ? hostname.Value.GetString() : null, + ErrorCodes = errorCodes.Value.ValueKind == JsonValueKind.Array ? JsonSerializer.Deserialize(errorCodes.Value.GetRawText()) : null + }; + } + + if (typeToConvert == typeof(reCAPTCHASiteVerifyV3Response)) + { + var score = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("score", StringComparison.InvariantCultureIgnoreCase)); + var action = rootElement.EnumerateObject().FirstOrDefault(x => x.Name.Equals("action", StringComparison.InvariantCultureIgnoreCase)); + return new reCAPTCHASiteVerifyV3Response + { + Success = success.Value.ValueKind == JsonValueKind.True, + ChallengeTs = challengeTimestamp.Value.ValueKind == JsonValueKind.String ? challengeTimestamp.Value.GetDateTime() : DateTime.MinValue, + HostName = hostname.Value.ValueKind == JsonValueKind.String ? hostname.Value.GetString() : null, + ErrorCodes = errorCodes.Value.ValueKind == JsonValueKind.Array ? JsonSerializer.Deserialize(errorCodes.Value.GetRawText()) : null, + Score = score.Value.ValueKind == JsonValueKind.Number ? score.Value.GetSingle() : 0, + Action = action.Value.ValueKind == JsonValueKind.String ? action.Value.GetString() : null + }; + } + + throw new JsonException($"Incorrect type: {typeToConvert.FullName}"); + } + + public override void Write(Utf8JsonWriter writer, reCAPTCHASiteVerifyResponse value, JsonSerializerOptions options) + { + JsonSerializer.Serialize(writer, value); + } + } +} diff --git a/src/Owl.reCAPTCHA/v2/reCAPTCHASiteVerifyV2.cs b/src/Owl.reCAPTCHA/v2/reCAPTCHASiteVerifyV2.cs index b7ecd95..2df4ee5 100644 --- a/src/Owl.reCAPTCHA/v2/reCAPTCHASiteVerifyV2.cs +++ b/src/Owl.reCAPTCHA/v2/reCAPTCHASiteVerifyV2.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Options; -using Newtonsoft.Json; namespace Owl.reCAPTCHA.v2 { @@ -31,8 +31,9 @@ public async Task Verify(reCAPTCHASiteVerifyRequest var v3Response = await _client.PostAsync("recaptcha/api/siteverify", content); if (v3Response.IsSuccessStatusCode) { - return JsonConvert.DeserializeObject( - await v3Response.Content.ReadAsStringAsync()); + var options = new JsonSerializerOptions(); + options.Converters.Add(new reCAPTCHASiteVerifyResponseJsonConverter()); + return JsonSerializer.Deserialize(await v3Response.Content.ReadAsStringAsync(), options); } return new reCAPTCHASiteVerifyResponse @@ -45,4 +46,4 @@ public async Task Verify(reCAPTCHASiteVerifyRequest }; } } -} \ No newline at end of file +} diff --git a/src/Owl.reCAPTCHA/v3/reCAPTCHASiteVerifyV3.cs b/src/Owl.reCAPTCHA/v3/reCAPTCHASiteVerifyV3.cs index 934ea83..1585263 100644 --- a/src/Owl.reCAPTCHA/v3/reCAPTCHASiteVerifyV3.cs +++ b/src/Owl.reCAPTCHA/v3/reCAPTCHASiteVerifyV3.cs @@ -1,9 +1,9 @@ using System; using System.Collections.Generic; using System.Net.Http; +using System.Text.Json; using System.Threading.Tasks; using Microsoft.Extensions.Options; -using Newtonsoft.Json; namespace Owl.reCAPTCHA.v3 { @@ -31,8 +31,9 @@ public async Task Verify(reCAPTCHASiteVerifyReque var v3Response = await _client.PostAsync("recaptcha/api/siteverify", content); if (v3Response.IsSuccessStatusCode) { - return JsonConvert.DeserializeObject( - await v3Response.Content.ReadAsStringAsync()); + var options = new JsonSerializerOptions(); + options.Converters.Add(new reCAPTCHASiteVerifyResponseJsonConverter()); + return JsonSerializer.Deserialize(await v3Response.Content.ReadAsStringAsync(), options); } return new reCAPTCHASiteVerifyV3Response @@ -45,4 +46,4 @@ public async Task Verify(reCAPTCHASiteVerifyReque }; } } -} \ No newline at end of file +}