Skip to content

Commit

Permalink
Established RecaptchaValidator
Browse files Browse the repository at this point in the history
The `RecaptchaValidator` class is a concrete implementation of the new `IRequestValidator` (0272136). This accepts a token and an action, and validates them against reCAPTCHA's API. This takes advantage of the recently introduced `RecaptchaResponse` class to model the response from the reCAPTCHA API (3c0ad10).
  • Loading branch information
JeremyCaney committed May 25, 2021
1 parent 3c0ad10 commit 87d0f21
Showing 1 changed file with 91 additions and 0 deletions.
91 changes: 91 additions & 0 deletions Services/RecaptchaValidator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*==============================================================================================================================
| Author Ignia, LLC
| Client GoldSim
| Project Website
\=============================================================================================================================*/
using System;
using System.Net;
using System.Net.Http;
using System.Text.Json;
using System.Threading.Tasks;
using GoldSim.Web.Models.Recaptcha;
using OnTopic.Internal.Diagnostics;

namespace GoldSim.Web.Services {

/*============================================================================================================================
| CLASS: RECAPTCHA (REQUEST VALIDATOR)
\---------------------------------------------------------------------------------------------------------------------------*/
/// <summary>
/// Validates that a given request is from a human.
/// </summary>
public class RecaptchaValidator: IRequestValidator {

/*==========================================================================================================================
| PRIVATE VARIABLES
\-------------------------------------------------------------------------------------------------------------------------*/
private readonly string _secret;
private readonly string _serviceUrl;
private static readonly HttpClient _client = new();

/*==========================================================================================================================
| CONSTRUCTOR
\-------------------------------------------------------------------------------------------------------------------------*/
/// <summary>
/// Initializes a new instance of the <see cref="RecaptchaValidator"/> with necessary dependencies.
/// </summary>
/// <returns>A new instance of the <see cref="RecaptchaValidator"/>.</returns>
public RecaptchaValidator(string secret) {
_secret = secret?? throw new ArgumentNullException(nameof(secret));
_serviceUrl = "https://www.google.com/recaptcha/api/siteverify";
}

/*==========================================================================================================================
| IS VALID?
\-------------------------------------------------------------------------------------------------------------------------*/
/// <summary>
/// Determines that the request is valid, given a <paramref name="requestToken"/>.
/// </summary>
public async Task<bool> IsValid(string requestType, string requestToken) {

/*------------------------------------------------------------------------------------------------------------------------
| Validate input
\-----------------------------------------------------------------------------------------------------------------------*/
Contract.Requires(requestToken, nameof(requestToken));

/*------------------------------------------------------------------------------------------------------------------------
| Retrieve value
\-----------------------------------------------------------------------------------------------------------------------*/
var uri = new Uri($"{_serviceUrl}?secret={_secret}&response={requestToken}");
var httpResponse = await _client.GetAsync(uri).ConfigureAwait(false);

/*------------------------------------------------------------------------------------------------------------------------
| Validate response
\-----------------------------------------------------------------------------------------------------------------------*/
if (httpResponse.StatusCode != HttpStatusCode.OK) {
return false;
}

/*------------------------------------------------------------------------------------------------------------------------
| Validate score
\-----------------------------------------------------------------------------------------------------------------------*/
var jsonResponse = await httpResponse.Content.ReadAsStringAsync().ConfigureAwait(false);
var recaptchaResponse = JsonSerializer.Deserialize<RecaptchaResponse>(
jsonResponse,
new() {
PropertyNameCaseInsensitive = true
}
);

/*------------------------------------------------------------------------------------------------------------------------
| Validate response
\-----------------------------------------------------------------------------------------------------------------------*/
return
recaptchaResponse.Success &&
recaptchaResponse.Score >= 0.5 &&
recaptchaResponse.Action.Equals(requestType, StringComparison.Ordinal);

}

} // Class
} // Namespace

0 comments on commit 87d0f21

Please sign in to comment.