add recaptcha option
This commit is contained in:
@@ -206,5 +206,10 @@
|
|||||||
"password": "smtp_password",
|
"password": "smtp_password",
|
||||||
"from": "admin@example.com",
|
"from": "admin@example.com",
|
||||||
"mail_reset_password": false
|
"mail_reset_password": false
|
||||||
|
},
|
||||||
|
"recaptcha": {
|
||||||
|
"enabled": false,
|
||||||
|
"site_key": "YOUR_RECAPTCHA_V2_SITE_KEY",
|
||||||
|
"secret_key": "YOUR_RECAPTCHA_V2_SECRET_KEY"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,23 @@ export default (router, tpl) => {
|
|||||||
return renderError("Passwords do not match.");
|
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 activated = true;
|
||||||
let activationToken = null;
|
let activationToken = null;
|
||||||
|
|
||||||
|
|||||||
@@ -1092,6 +1092,8 @@ process.on('uncaughtException', err => {
|
|||||||
enable_userhall_image_upload: cfg.websrv.enable_userhall_image_upload !== false,
|
enable_userhall_image_upload: cfg.websrv.enable_userhall_image_upload !== false,
|
||||||
abyss_enabled: cfg.websrv.abyss_enabled !== false,
|
abyss_enabled: cfg.websrv.abyss_enabled !== false,
|
||||||
smtp_enabled: !!(cfg.smtp && cfg.smtp.enabled && cfg.smtp.mail_reset_password),
|
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,
|
show_background_cfg: cfg.websrv.background !== false,
|
||||||
allowed_mimes: Object.keys(cfg.mimes).concat([...new Set(Object.values(cfg.mimes))].map(ext => `.${ext}`)).join(','),
|
allowed_mimes: Object.keys(cfg.mimes).concat([...new Set(Object.values(cfg.mimes))].map(ext => `.${ext}`)).join(','),
|
||||||
mimes_json: JSON.stringify(cfg.mimes),
|
mimes_json: JSON.stringify(cfg.mimes),
|
||||||
|
|||||||
@@ -6,6 +6,14 @@
|
|||||||
<title>register</title>
|
<title>register</title>
|
||||||
<link rel="icon" @if(custom_favicon && custom_favicon.length > 0)href="{{ custom_favicon }}"@else type="image/gif" href="/s/img/favicon.gif"@endif />
|
<link rel="icon" @if(custom_favicon && custom_favicon.length > 0)href="{{ custom_favicon }}"@else type="image/gif" href="/s/img/favicon.gif"@endif />
|
||||||
<link href="/s/css/f0ckm.css" rel="stylesheet" />
|
<link href="/s/css/f0ckm.css" rel="stylesheet" />
|
||||||
|
@if(recaptcha_enabled)
|
||||||
|
<script>
|
||||||
|
function onRecaptchaPageReady() {
|
||||||
|
grecaptcha.render('page-register-recaptcha', { sitekey: '{{ recaptcha_site_key }}', theme: 'dark' });
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<script src="https://www.google.com/recaptcha/api.js?onload=onRecaptchaPageReady&render=explicit" async defer></script>
|
||||||
|
@endif
|
||||||
</head>
|
</head>
|
||||||
<body type="login">
|
<body type="login">
|
||||||
<form class="login-form" method="post" action="/register" novalidate>
|
<form class="login-form" method="post" action="/register" novalidate>
|
||||||
@@ -33,6 +41,9 @@
|
|||||||
<input type="checkbox" id="tos-page" name="tos" required />
|
<input type="checkbox" id="tos-page" name="tos" required />
|
||||||
<label for="tos-page">@if(private_society){{ t('auth.tos_private_simple') }}@else{{ t('auth.tos_public') }} <a href="/terms" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_terms') }}</a>, <a href="/rules" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_rules') }}</a> {{ t('auth.tos_age') }}@endif</label>
|
<label for="tos-page">@if(private_society){{ t('auth.tos_private_simple') }}@else{{ t('auth.tos_public') }} <a href="/terms" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_terms') }}</a>, <a href="/rules" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_rules') }}</a> {{ t('auth.tos_age') }}@endif</label>
|
||||||
</p>
|
</p>
|
||||||
|
@if(recaptcha_enabled)
|
||||||
|
<div id="page-register-recaptcha" style="margin: 10px 0;"></div>
|
||||||
|
@endif
|
||||||
<input type="submit" value="{{ t('auth.register_title') }}" />
|
<input type="submit" value="{{ t('auth.register_title') }}" />
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
|||||||
@@ -348,6 +348,9 @@
|
|||||||
<input type="checkbox" id="tos-modal" name="tos" required />
|
<input type="checkbox" id="tos-modal" name="tos" required />
|
||||||
<label for="tos-modal">@if(private_society){{ t('auth.tos_private') }}@else{{ t('auth.tos_public') }} <a href="/terms" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_terms') }}</a>, <a href="/rules" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_rules') }}</a> {{ t('auth.tos_age') }}@endif</label>
|
<label for="tos-modal">@if(private_society){{ t('auth.tos_private') }}@else{{ t('auth.tos_public') }} <a href="/terms" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_terms') }}</a>, <a href="/rules" target="_blank" style="color: var(--accent); text-decoration: underline;">{{ t('auth.tos_rules') }}</a> {{ t('auth.tos_age') }}@endif</label>
|
||||||
</p>
|
</p>
|
||||||
|
@if(recaptcha_enabled)
|
||||||
|
<div id="modal-register-recaptcha" style="margin: 10px 0;"></div>
|
||||||
|
@endif
|
||||||
<button type="submit">{{ t('auth.create_account') }}</button>
|
<button type="submit">{{ t('auth.create_account') }}</button>
|
||||||
<div style="text-align: center; margin-top: 20px;">
|
<div style="text-align: center; margin-top: 20px;">
|
||||||
<a href="#" id="register-to-login" style="font-size: 0.9em; color: var(--accent); text-decoration: underline;">{{ t('auth.back_to_login') }}</a>
|
<a href="#" id="register-to-login" style="font-size: 0.9em; color: var(--accent); text-decoration: underline;">{{ t('auth.back_to_login') }}</a>
|
||||||
@@ -391,3 +394,41 @@
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
@endif
|
@endif
|
||||||
|
|
||||||
|
@if(recaptcha_enabled)
|
||||||
|
<script>
|
||||||
|
(function() {
|
||||||
|
var _rcModalWidgetId = null;
|
||||||
|
var _rcLoaded = false;
|
||||||
|
|
||||||
|
function renderModalRecaptcha() {
|
||||||
|
var el = document.getElementById('modal-register-recaptcha');
|
||||||
|
if (!el || !window.grecaptcha) return;
|
||||||
|
if (_rcModalWidgetId !== null) {
|
||||||
|
try { grecaptcha.reset(_rcModalWidgetId); } catch(e) {}
|
||||||
|
} else {
|
||||||
|
_rcModalWidgetId = grecaptcha.render(el, { sitekey: '{{ recaptcha_site_key }}', theme: 'dark' });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onRecaptchaModalReady = function() {
|
||||||
|
_rcLoaded = true;
|
||||||
|
renderModalRecaptcha();
|
||||||
|
};
|
||||||
|
|
||||||
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
|
var modal = document.getElementById('register-modal');
|
||||||
|
if (!modal) return;
|
||||||
|
var obs = new MutationObserver(function(mutations) {
|
||||||
|
mutations.forEach(function(m) {
|
||||||
|
if (m.attributeName === 'style') {
|
||||||
|
if (modal.style.display !== 'none' && _rcLoaded) renderModalRecaptcha();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
obs.observe(modal, { attributes: true });
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<script src="https://www.google.com/recaptcha/api.js?onload=onRecaptchaModalReady&render=explicit" async defer></script>
|
||||||
|
@endif
|
||||||
|
|||||||
Reference in New Issue
Block a user