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
@@ -33,6 +41,9 @@

+ @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
{{ t('auth.back_to_login') }} @@ -391,3 +394,41 @@
@endif + +@if(recaptcha_enabled) + + +@endif