From 4a155bc5f4ab269b36c12eb6724764501d759a79 Mon Sep 17 00:00:00 2001
From: Kibi Kelburton
Date: Sun, 24 May 2026 16:44:20 +0200
Subject: [PATCH] add recaptcha option
---
config_example.json | 5 +++++
src/inc/routes/register.mjs | 18 +++++++++++++++-
src/index.mjs | 2 ++
views/register.html | 11 ++++++++++
views/snippets/navbar.html | 41 +++++++++++++++++++++++++++++++++++++
5 files changed, 76 insertions(+), 1 deletion(-)
diff --git a/config_example.json b/config_example.json
index 4eea3ba..cd6032b 100644
--- a/config_example.json
+++ b/config_example.json
@@ -206,5 +206,10 @@
"password": "smtp_password",
"from": "admin@example.com",
"mail_reset_password": false
+ },
+ "recaptcha": {
+ "enabled": false,
+ "site_key": "YOUR_RECAPTCHA_V2_SITE_KEY",
+ "secret_key": "YOUR_RECAPTCHA_V2_SECRET_KEY"
}
}
\ No newline at end of file
diff --git a/src/inc/routes/register.mjs b/src/inc/routes/register.mjs
index 476d539..7ae1044 100644
--- a/src/inc/routes/register.mjs
+++ b/src/inc/routes/register.mjs
@@ -88,7 +88,23 @@ export default (router, tpl) => {
return renderError("Passwords do not match.");
}
- // Registration Logic
+ // reCAPTCHA verification
+ if (cfg.recaptcha?.enabled && cfg.recaptcha?.secret_key) {
+ const rcToken = req.post['g-recaptcha-response'];
+ if (!rcToken) return renderError("Please complete the reCAPTCHA.");
+ try {
+ const verifyRes = await fetch('https://www.google.com/recaptcha/api/siteverify', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+ body: new URLSearchParams({ secret: cfg.recaptcha.secret_key, response: rcToken, remoteip: ip })
+ });
+ const { success } = await verifyRes.json();
+ if (!success) return renderError("reCAPTCHA verification failed. Please try again.");
+ } catch (e) {
+ console.error('[REGISTER] reCAPTCHA error:', e.message);
+ return renderError("reCAPTCHA check failed. Please try again.");
+ }
+ }
let activated = true;
let activationToken = null;
diff --git a/src/index.mjs b/src/index.mjs
index 15121f0..a23742e 100644
--- a/src/index.mjs
+++ b/src/index.mjs
@@ -1092,6 +1092,8 @@ process.on('uncaughtException', err => {
enable_userhall_image_upload: cfg.websrv.enable_userhall_image_upload !== false,
abyss_enabled: cfg.websrv.abyss_enabled !== false,
smtp_enabled: !!(cfg.smtp && cfg.smtp.enabled && cfg.smtp.mail_reset_password),
+ recaptcha_enabled: !!(cfg.recaptcha && cfg.recaptcha.enabled && cfg.recaptcha.site_key),
+ recaptcha_site_key: (cfg.recaptcha && cfg.recaptcha.site_key) || '',
show_background_cfg: cfg.websrv.background !== false,
allowed_mimes: Object.keys(cfg.mimes).concat([...new Set(Object.values(cfg.mimes))].map(ext => `.${ext}`)).join(','),
mimes_json: JSON.stringify(cfg.mimes),
diff --git a/views/register.html b/views/register.html
index c9b3dfb..d6fb894 100644
--- a/views/register.html
+++ b/views/register.html
@@ -6,6 +6,14 @@
register
0)href="{{ custom_favicon }}"@else type="image/gif" href="/s/img/favicon.gif"@endif />
+ @if(recaptcha_enabled)
+
+
+ @endif
+ @if(recaptcha_enabled)
+
+ @endif
@endif
diff --git a/views/snippets/navbar.html b/views/snippets/navbar.html
index 6f5d2eb..f75d489 100644
--- a/views/snippets/navbar.html
+++ b/views/snippets/navbar.html
@@ -348,6 +348,9 @@
+ @if(recaptcha_enabled)
+
+ @endif
@endif
+
+@if(recaptcha_enabled)
+
+
+@endif