Added recaptcha. Added recaptcha to register page

This commit is contained in:
Marcel Baumgartner
2023-05-19 14:36:51 +02:00
parent ee11d29d2c
commit 306ad51a51
6 changed files with 192 additions and 18 deletions

View File

@@ -0,0 +1,18 @@
using System.ComponentModel.DataAnnotations;
using Logging.Net;
namespace Moonlight.App.Helpers;
[AttributeUsage(AttributeTargets.Property)]
public class MustBeTrueAttribute : ValidationAttribute
{
public override bool IsValid(object value)
{
if (value is bool boolValue)
{
return boolValue;
}
return false;
}
}

View File

@@ -1,21 +1,31 @@
using System.ComponentModel.DataAnnotations; using System.ComponentModel.DataAnnotations;
using Moonlight.App.Helpers;
namespace Moonlight.App.Models.Forms; namespace Moonlight.App.Models.Forms;
public class UserRegisterModel public class UserRegisterModel
{ {
[Required, EmailAddress] [Required(ErrorMessage = "You need to specify a email address")]
[EmailAddress(ErrorMessage = "You need to specify a valid email address")]
public string Email { get; set; } public string Email { get; set; }
[Required, MinLength(3)] [Required(ErrorMessage = "You need to specify a first name")]
[MinLength(3, ErrorMessage = "You need to specify a valid first name")]
[MaxLength(30, ErrorMessage = "You need to specify a valid first name")]
public string FirstName { get; set; } public string FirstName { get; set; }
[Required, MinLength(3)]
[Required(ErrorMessage = "You need to specify a last name")]
[MinLength(3, ErrorMessage = "You need to specify a valid last name")]
[MaxLength(30, ErrorMessage = "You need to specify a valid last name")]
public string LastName { get; set; } public string LastName { get; set; }
[Required] [Required(ErrorMessage = "You need to specify a password")]
public string Password { get; set; } public string Password { get; set; }
[Required] [Required(ErrorMessage = "You need to specify a password")]
public string ConfirmPassword { get; set; } public string ConfirmPassword { get; set; }
[MustBeTrue(ErrorMessage = "Please solve the captcha")]
public bool Captcha { get; set; }
} }

View File

@@ -0,0 +1,91 @@
using System.ComponentModel;
using System.Text;
using Microsoft.JSInterop;
using RestSharp;
namespace Moonlight.App.Services.Interop;
public class ReCaptchaService
{
private readonly IJSRuntime JsRuntime;
private readonly ConfigService ConfigService;
private readonly string SiteKey;
private readonly string SecretKey;
private readonly bool Enable = false;
public Func<string, Task>? OnResponse { get; set; }
public Func<Task>? OnValidResponse { get; set; }
public ReCaptchaService(
IJSRuntime jsRuntime,
ConfigService configService)
{
JsRuntime = jsRuntime;
ConfigService = configService;
var recaptchaConfig = ConfigService
.GetSection("Moonlight")
.GetSection("Security")
.GetSection("ReCaptcha");
Enable = recaptchaConfig.GetValue<bool>("Enable");
if (Enable)
{
SiteKey = recaptchaConfig.GetValue<string>("SiteKey");
SecretKey = recaptchaConfig.GetValue<string>("SecretKey");
}
}
public Task<bool> IsEnabled()
{
return Task.FromResult(Enable);
}
public async Task<string> Create(string elementId)
{
var page = DotNetObjectReference.Create(this);
var res = await JsRuntime.InvokeAsync<object>("moonlight.recaptcha.render", elementId, SiteKey, page);
return res.ToString() ?? "";
}
[JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
public async void CallbackOnSuccess(string res)
{
if(OnResponse != null)
await OnResponse.Invoke(res);
var b = await Validate(res);
if (b)
{
if(OnValidResponse != null)
await OnValidResponse.Invoke();
}
}
[JSInvokable, EditorBrowsable(EditorBrowsableState.Never)]
public void CallbackOnExpired()
{
}
private async Task<bool> Validate(string res)
{
var url = "https://www.google.com/recaptcha/api/siteverify";
var client = new RestClient();
var request = new RestRequest(url);
request.AddParameter("secret", SecretKey);
request.AddParameter("response", res);
var resp = await client.PostAsync(request);
var data = new ConfigurationBuilder().AddJsonStream(
new MemoryStream(Encoding.ASCII.GetBytes(resp.Content))
).Build();
return data.GetValue<bool>("success");
}
}

View File

@@ -117,6 +117,7 @@ namespace Moonlight
builder.Services.AddScoped<FabricService>(); builder.Services.AddScoped<FabricService>();
builder.Services.AddSingleton<BucketService>(); builder.Services.AddSingleton<BucketService>();
builder.Services.AddScoped<RatingService>(); builder.Services.AddScoped<RatingService>();
builder.Services.AddScoped<ReCaptchaService>();
builder.Services.AddScoped<GoogleOAuth2Service>(); builder.Services.AddScoped<GoogleOAuth2Service>();
builder.Services.AddScoped<DiscordOAuth2Service>(); builder.Services.AddScoped<DiscordOAuth2Service>();

View File

@@ -83,6 +83,11 @@
</div> </div>
</div> </div>
<div class="row mt-3 mb-3">
<SmartReCaptcha @bind-Value="UserRegisterModel.Captcha">
</SmartReCaptcha>
</div>
<div class="d-grid mb-6"> <div class="d-grid mb-6">
<button type="submit" class="btn btn-primary"> <button type="submit" class="btn btn-primary">
<TL>Sign-up</TL> <TL>Sign-up</TL>

View File

@@ -0,0 +1,49 @@
@using Moonlight.App.Services.Interop
@using Logging.Net
@inject ReCaptchaService ReCaptchaService
@inherits InputBase<bool>
<div class="d-flex flex-center" id="@UniqueId"></div>
@code
{
private string UniqueId = Guid.NewGuid().ToString();
private string Id;
private async Task OnValid()
{
CurrentValue = true;
await ValueChanged.InvokeAsync(CurrentValue);
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
if (firstRender)
{
ReCaptchaService.OnValidResponse += OnValid;
if(await ReCaptchaService.IsEnabled())
Id = await ReCaptchaService.Create(UniqueId);
else
{
await OnValid();
}
}
}
protected override bool TryParseValueFromString(string? value, out bool result, out string? validationErrorMessage)
{
if (bool.TryParse(value, out result))
{
validationErrorMessage = null;
return true;
}
else
{
validationErrorMessage = "Invalid value.";
return false;
}
}
}