Added recaptcha

This commit is contained in:
2026-01-12 11:05:01 +01:00
parent a4d386f2c5
commit 01861f08c6
6 changed files with 101 additions and 45 deletions

View File

@@ -70,12 +70,10 @@ return array(
'DB_PORT' => '3306',
'DB_CHARSET' => 'utf8',
/**
* Configuration for: Captcha size
* The currently used Captcha generator (https://github.com/Gregwar/Captcha) also runs without giving a size,
* so feel free to use ->build(); inside CaptchaModel.
* Configuration for: Google reCAPTCHA v2
*/
'CAPTCHA_WIDTH' => 359,
'CAPTCHA_HEIGHT' => 100,
'RECAPTCHA_SITE_KEY' => 'recaptcha-site-key',
'RECAPTCHA_SECRET_KEY' => 'recaptcha-secret-key',
/**
* Configuration for: Cookies
* 1209600 seconds = 2 weeks

View File

@@ -22,23 +22,25 @@ class RegisterController extends Controller
*/
public function index()
{
// only admins can access registration; reuse existing admin auth check
Auth::checkAdminAuthentication();
if (Session::userIsLoggedIn()) {
Redirect::to('index');
return;
}
$this->View->render('register/index');
}
/**
* Register page action
* POST-request after form submit
*/
public function register_action()
{
// enforce admin-only for registration
Auth::checkAdminAuthentication();
if (Session::userIsLoggedIn()) {
Redirect::to('index');
return;
}
RegistrationModel::registerNewUser();
Redirect::to('admin/index');
if (RegistrationModel::registerNewUser()) {
Redirect::to('login');
} else {
Redirect::to('register');
}
}
/**

View File

@@ -15,15 +15,13 @@ class RegistrationModel
*/
public static function registerNewUser($isAdmin = false)
{
// clean the input
$user_name = strip_tags(Request::post('user_name'));
$user_email = strip_tags(Request::post('user_email'));
// Use 'user_password' if provided (admin registration), otherwise 'user_password_new'
$user_password_new = $isAdmin ? Request::post('user_password_new') : Request::post('user_password_new');
$user_password_repeat = $user_password_new; // no repeat field
$user_password_new = Request::post('user_password_new');
$user_password_repeat = $user_password_new;
// validate using existing validators and messages
$valid = true;
if (!self::validateRecaptcha()) { $valid = false; }
if (!self::validateUserName($user_name)) { $valid = false; }
if (!self::validateUserEmail($user_email, $user_email)) { $valid = false; }
if (!self::validateUserPassword($user_password_new, $user_password_repeat)) { $valid = false; }
@@ -77,12 +75,35 @@ class RegistrationModel
return $return;
}
/**
* Validates the username
*
* @param $user_name
* @return bool
*/
public static function validateRecaptcha()
{
$recaptcha_response = Request::post('g-recaptcha-response');
if (empty($recaptcha_response)) {
Session::add('feedback_negative', 'reCAPTCHA verification failed. Please try again.');
return false;
}
$secret_key = Config::get('RECAPTCHA_SECRET_KEY');
$verify_url = 'https://www.google.com/recaptcha/api/siteverify';
$response = file_get_contents($verify_url . '?secret=' . $secret_key . '&response=' . $recaptcha_response);
$response_data = json_decode($response);
if (!$response_data->success) {
Session::add('feedback_negative', 'reCAPTCHA verification failed. Please try again.');
return false;
}
// v3 returns a score from 0.0 to 1.0 (1.0 = likely human, 0.0 = likely bot)
if (isset($response_data->score) && $response_data->score < 0.5) {
Session::add('feedback_negative', 'Registration blocked due to suspicious activity.');
return false;
}
return true;
}
public static function validateUserName($user_name)
{
if (empty($user_name)) {
@@ -90,7 +111,6 @@ class RegistrationModel
return false;
}
// if username is too short (2), too long (64) or does not fit the pattern (aZ09)
if (!preg_match('/^[a-zA-Z0-9]{2,64}$/', $user_name)) {
Session::add('feedback_negative', Text::get('FEEDBACK_USERNAME_DOES_NOT_FIT_PATTERN'));
return false;

View File

@@ -37,6 +37,9 @@
<div class="link-forgot-my-password">
<a href="<?php echo Config::get('URL'); ?>login/requestPasswordReset">I forgot my password</a>
</div>
<div class="link-register" style="margin-top: 15px;">
<a href="<?php echo Config::get('URL'); ?>register" class="button">Register new account</a>
</div>
</div>
</div>
</div>

View File

@@ -1,18 +1,30 @@
<div class="container">
<script src="https://www.google.com/recaptcha/api.js?render=<?php echo Config::get('RECAPTCHA_SITE_KEY'); ?>"></script>
<!-- echo out the system feedback (error and success messages) -->
<div class="container">
<?php $this->renderFeedbackMessages(); ?>
<!-- login box on left side -->
<div class="login-box" style="width: 50%; display: block;">
<h2>Register a new account</h2>
<!-- register form -->
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action">
<form method="post" action="<?php echo Config::get('URL'); ?>register/register_action" id="register-form">
<input type="text" pattern="[a-zA-Z0-9]{2,64}" name="user_name" placeholder="Username (letters/numbers, 2-64 chars)" required />
<input type="text" name="user_email" placeholder="email address (a real address)" required />
<input type="password" name="user_password_new" pattern=".{6,}" placeholder="Password (6+ characters)" required autocomplete="off" />
<input type="hidden" name="g-recaptcha-response" id="recaptcha-response" />
<input type="submit" value="Register" />
</form>
</div>
</div>
<script>
document.getElementById('register-form').addEventListener('submit', function(e) {
e.preventDefault();
var form = this;
grecaptcha.ready(function() {
grecaptcha.execute('<?php echo Config::get('RECAPTCHA_SITE_KEY'); ?>', {action: 'register'}).then(function(token) {
document.getElementById('recaptcha-response').value = token;
form.submit();
});
});
});
</script>