diff --git a/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml b/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml
index e0f60e14..6f9a9516 100644
--- a/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml
+++ b/.idea/.idea.ProjectLighthouse/.idea/jsLibraryMappings.xml
@@ -1,6 +1,6 @@
-
+
\ No newline at end of file
diff --git a/ProjectLighthouse/Helpers/CaptchaHelper.cs b/ProjectLighthouse/Helpers/CaptchaHelper.cs
new file mode 100644
index 00000000..3008b084
--- /dev/null
+++ b/ProjectLighthouse/Helpers/CaptchaHelper.cs
@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Net.Http;
+using System.Threading.Tasks;
+using LBPUnion.ProjectLighthouse.Types.Settings;
+using Newtonsoft.Json.Linq;
+
+namespace LBPUnion.ProjectLighthouse.Helpers;
+
+public static class CaptchaHelper
+{
+ private static readonly HttpClient client = new()
+ {
+ BaseAddress = new Uri("https://hcaptcha.com"),
+ };
+
+ public static async Task Verify(string token)
+ {
+ if (!ServerSettings.Instance.HCaptchaEnabled) return true;
+
+ List> payload = new()
+ {
+ new("secret", ServerSettings.Instance.HCaptchaSecret),
+ new("response", token),
+ };
+
+ HttpResponseMessage response = await client.PostAsync("/siteverify", new FormUrlEncodedContent(payload));
+
+ response.EnsureSuccessStatusCode();
+
+ string responseBody = await response.Content.ReadAsStringAsync();
+
+ // We only really care about the success result, nothing else that hcaptcha sends us, so lets only parse that.
+ bool success = bool.Parse(JObject.Parse(responseBody)["success"]?.ToString() ?? "false");
+ return success;
+ }
+}
\ No newline at end of file
diff --git a/ProjectLighthouse/Pages/LoginForm.cshtml b/ProjectLighthouse/Pages/LoginForm.cshtml
index 2e5494a4..f07daa9f 100644
--- a/ProjectLighthouse/Pages/LoginForm.cshtml
+++ b/ProjectLighthouse/Pages/LoginForm.cshtml
@@ -50,6 +50,11 @@
+ @if (ServerSettings.Instance.HCaptchaEnabled)
+ {
+ @await Html.PartialAsync("Partials/CaptchaPartial")
+ }
+
@if (ServerSettings.Instance.RegistrationEnabled)
{
diff --git a/ProjectLighthouse/Pages/LoginForm.cshtml.cs b/ProjectLighthouse/Pages/LoginForm.cshtml.cs
index 5e19c5a4..d10d3f7d 100644
--- a/ProjectLighthouse/Pages/LoginForm.cshtml.cs
+++ b/ProjectLighthouse/Pages/LoginForm.cshtml.cs
@@ -6,8 +6,10 @@ using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
using LBPUnion.ProjectLighthouse.Pages.Layouts;
using LBPUnion.ProjectLighthouse.Types;
+using LBPUnion.ProjectLighthouse.Types.Settings;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Primitives;
namespace LBPUnion.ProjectLighthouse.Pages;
@@ -18,8 +20,6 @@ public class LoginForm : BaseLayout
public string Error { get; private set; }
- public bool WasLoginRequest { get; private set; }
-
[UsedImplicitly]
public async Task OnPost(string username, string password)
{
@@ -35,6 +35,19 @@ public class LoginForm : BaseLayout
return this.Page();
}
+ if (ServerSettings.Instance.HCaptchaEnabled)
+ {
+ // && (!this.Request.Form.TryGetValue("h-captcha-response", out StringValues values) || !await CaptchaHelper.Verify(values[0])))
+ bool gotCaptcha = this.Request.Form.TryGetValue("h-captcha-response", out StringValues values);
+ string? token = gotCaptcha ? values[0] : null;
+
+ if (token == null || !await CaptchaHelper.Verify(token))
+ {
+ this.Error = "You must solve the captcha correctly.";
+ return this.Page();
+ }
+ }
+
User? user = await this.Database.Users.FirstOrDefaultAsync(u => u.Username == username);
if (user == null)
{
@@ -68,6 +81,8 @@ public class LoginForm : BaseLayout
this.Response.Cookies.Append("LighthouseToken", webToken.UserToken);
+ Logger.Log($"User {user.Username} (id: {user.UserId}) successfully logged in on web", LoggerLevelLogin.Instance);
+
if (user.PasswordResetRequired) return this.Redirect("~/passwordResetRequired");
return this.RedirectToPage(nameof(LandingPage));
diff --git a/ProjectLighthouse/Pages/Partials/CaptchaPartial.cshtml b/ProjectLighthouse/Pages/Partials/CaptchaPartial.cshtml
new file mode 100644
index 00000000..e1891722
--- /dev/null
+++ b/ProjectLighthouse/Pages/Partials/CaptchaPartial.cshtml
@@ -0,0 +1,6 @@
+@using LBPUnion.ProjectLighthouse.Types.Settings
+@if (ServerSettings.Instance.HCaptchaEnabled)
+{
+
+
+}
\ No newline at end of file
diff --git a/ProjectLighthouse/Types/Settings/ServerSettings.cs b/ProjectLighthouse/Types/Settings/ServerSettings.cs
index 53ce334e..fd99f22e 100644
--- a/ProjectLighthouse/Types/Settings/ServerSettings.cs
+++ b/ProjectLighthouse/Types/Settings/ServerSettings.cs
@@ -5,7 +5,6 @@ using System.Text.Json;
using System.Text.Json.Serialization;
using JetBrains.Annotations;
using Kettu;
-using LBPUnion.ProjectLighthouse.Helpers;
using LBPUnion.ProjectLighthouse.Logging;
namespace LBPUnion.ProjectLighthouse.Types.Settings;
@@ -13,7 +12,7 @@ namespace LBPUnion.ProjectLighthouse.Types.Settings;
[Serializable]
public class ServerSettings
{
- public const int CurrentConfigVersion = 18; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
+ public const int CurrentConfigVersion = 19; // MUST BE INCREMENTED FOR EVERY CONFIG CHANGE!
private static FileSystemWatcher fileWatcher;
static ServerSettings()
{
@@ -150,6 +149,12 @@ public class ServerSettings
public string MissingIconHash { get; set; } = "";
+ public bool HCaptchaEnabled { get; set; }
+
+ public string HCaptchaSiteKey { get; set; } = "";
+
+ public string HCaptchaSecret { get; set; } = "";
+
#region Meta
[NotNull]