Merge pull request #120 from Moonlight-Panel/AddReCaptchaToRegister
Added recaptcha. Added recaptcha to register page
This commit is contained in:
18
Moonlight/App/Helpers/MustBeTrueAttribute.cs
Normal file
18
Moonlight/App/Helpers/MustBeTrueAttribute.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -1,21 +1,31 @@
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Moonlight.App.Helpers;
|
||||
|
||||
namespace Moonlight.App.Models.Forms;
|
||||
|
||||
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; }
|
||||
|
||||
[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; }
|
||||
|
||||
[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; }
|
||||
|
||||
[Required]
|
||||
[Required(ErrorMessage = "You need to specify a password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[Required]
|
||||
[Required(ErrorMessage = "You need to specify a password")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
[MustBeTrue(ErrorMessage = "Please solve the captcha")]
|
||||
public bool Captcha { get; set; }
|
||||
}
|
||||
91
Moonlight/App/Services/Interop/ReCaptchaService.cs
Normal file
91
Moonlight/App/Services/Interop/ReCaptchaService.cs
Normal 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");
|
||||
}
|
||||
}
|
||||
@@ -117,6 +117,7 @@ namespace Moonlight
|
||||
builder.Services.AddScoped<FabricService>();
|
||||
builder.Services.AddSingleton<BucketService>();
|
||||
builder.Services.AddScoped<RatingService>();
|
||||
builder.Services.AddScoped<ReCaptchaService>();
|
||||
|
||||
builder.Services.AddScoped<GoogleOAuth2Service>();
|
||||
builder.Services.AddScoped<DiscordOAuth2Service>();
|
||||
|
||||
@@ -83,6 +83,11 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row mt-3 mb-3">
|
||||
<SmartReCaptcha @bind-Value="UserRegisterModel.Captcha">
|
||||
</SmartReCaptcha>
|
||||
</div>
|
||||
|
||||
<div class="d-grid mb-6">
|
||||
<button type="submit" class="btn btn-primary">
|
||||
<TL>Sign-up</TL>
|
||||
|
||||
49
Moonlight/Shared/Components/Forms/SmartReCaptcha.razor
Normal file
49
Moonlight/Shared/Components/Forms/SmartReCaptcha.razor
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user