Feature/recaptcha v3 plus login (#202)

* [WIP] New GoogleReCAPTCHA code
Support for v3
v2-invisible doesn't work yet

* Add some notice about recaptchas versions

* Lets support only ReCaptcha v3

Too much mess ;)

* Fixes
This commit is contained in:
slawkens 2022-08-31 11:16:48 +02:00 committed by GitHub
parent 6d142dcbfe
commit 32cf487128
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 129 additions and 26 deletions

View File

@ -135,11 +135,13 @@ $config = array(
'smtp_secure' => '', // What kind of encryption to use on the SMTP connection. Options: '', 'ssl' (GMail) or 'tls' (Microsoft Outlook)
'smtp_debug' => false, // set true to debug (you will see more info in error.log)
// reCAPTCHA (prevent spam bots)
// Google reCAPTCHA v3 (prevent spam bots)
'recaptcha_enabled' => false, // enable recaptcha verification code
'recaptcha_site_key' => '', // get your own site and secret keys at https://www.google.com/recaptcha
'recaptcha_secret_key' => '',
'recaptcha_theme' => 'light', // light, dark
// min score for validation, between 0 - 1.0
// https://developers.google.com/recaptcha/docs/v3#interpreting_the_score
'recaptcha_min_score' => 0.5,
//
'generate_new_reckey' => true, // let player generate new recovery key, he will receive e-mail with new rec key (not display on page, hacker can't generate rec key)

View File

@ -0,0 +1,79 @@
<?php
class GoogleReCAPTCHA
{
private static $errorMessage = '';
private static $errorType;
const ERROR_MISSING_RESPONSE = 1;
const ERROR_INVALID_ACTION = 2;
const ERROR_LOW_SCORE = 3;
const ERROR_NO_SUCCESS = 4;
public static function verify($action = '')
{
if (!isset($_POST['g-recaptcha-response']) || empty($_POST['g-recaptcha-response'])) {
self::$errorType = self::ERROR_MISSING_RESPONSE;
self::$errorMessage = "Please confirm that you're not a robot.";
return false;
}
$recaptchaApiUrl = 'https://www.google.com/recaptcha/api/siteverify';
$secretKey = config('recaptcha_secret_key');
$recaptchaResponse = $_POST['g-recaptcha-response'];
$ip = $_SERVER['REMOTE_ADDR'];
$params = 'secret='.$secretKey.'&response='.$recaptchaResponse.'&remoteip='.$ip;
if (function_exists('curl_version')) {
$curl_connection = curl_init($recaptchaApiUrl);
curl_setopt($curl_connection, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($curl_connection, CURLOPT_FOLLOWLOCATION, 0);
curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $params);
$response = curl_exec($curl_connection);
curl_close($curl_connection);
} else {
$response = file_get_contents($recaptchaApiUrl . '?' . $params);
}
$json = json_decode($response);
//log_append('recaptcha.log', 'recaptcha_score: ' . $json->score . ', action:' . $json->action);
if (!isset($json->action) || $json->action !== $action) {
self::$errorType = self::ERROR_INVALID_ACTION;
self::$errorMessage = 'Google ReCaptcha returned invalid action.';
return false;
}
if (!isset($json->score) || $json->score < config('recaptcha_min_score')) {
self::$errorType = self::ERROR_LOW_SCORE;
self::$errorMessage = 'Your Google ReCaptcha score was too low.';
return false;
}
if (!isset($json->success) || !$json->success) {
self::$errorType = self::ERROR_NO_SUCCESS;
self::$errorMessage = "Please confirm that you're not a robot.";
return false;
}
return true;
}
/**
* @return string
*/
public static function getErrorMessage() {
return self::$errorMessage;
}
/**
* @return int
*/
public static function getErrorType() {
return self::$errorType;
}
}

View File

@ -84,6 +84,14 @@ else
$t = isset($tmp[$ip]) ? $tmp[$ip] : NULL;
}
if(config('recaptcha_enabled'))
{
require LIBS . 'GoogleReCAPTCHA.php';
if (!GoogleReCAPTCHA::verify('login')) {
$errors[] = GoogleReCAPTCHA::getErrorMessage();
}
}
$account_logged = new OTS_Account();
if (config('account_login_by_email')) {
$account_logged->findByEMail($login_account);

View File

@ -72,17 +72,12 @@ if($save)
$errors['country'] = 'Country is invalid.';
}
if($config['recaptcha_enabled'])
if(config('recaptcha_enabled'))
{
if(isset($_POST['g-recaptcha-response']) && !empty($_POST['g-recaptcha-response']))
{
$verifyResponse = file_get_contents('https://www.google.com/recaptcha/api/siteverify?secret='.$config['recaptcha_secret_key'].'&response='.$_POST['g-recaptcha-response']);
$responseData = json_decode($verifyResponse);
if(!$responseData->success)
$errors['verification'] = "Please confirm that you're not a robot.";
require LIBS . 'GoogleReCAPTCHA.php';
if (!GoogleReCAPTCHA::verify('register')) {
$errors['verification'] = GoogleReCAPTCHA::getErrorMessage();
}
else
$errors['verification'] = "Please confirm that you're not a robot.";
}
// password

View File

@ -109,19 +109,9 @@
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_PASSWORDS') }}
{% if config.recaptcha_enabled %}
<tr>
<td class="LabelV" style="width: 150px">
<span{% if errors.verification[0] is defined %} class="red"{% endif %}>Verification:</span>
</td>
<td>
<div class="g-recaptcha" data-sitekey="{{ config.recaptcha_site_key }}" data-theme="{{ config.recaptcha_theme }}"></div>
</td>
</tr>
{% if errors.verification is defined %}
<tr><td></td><td><span class="FormFieldError">{{ errors.verification }}</span></td></tr>
{% endif %}
{% endif %}
{% if config.recaptcha_enabled %}
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" />
{% endif %}
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_RECAPTCHA') }}
</tbody>
@ -339,6 +329,10 @@
</form>
{{ hook('HOOK_ACCOUNT_CREATE_AFTER_FORM') }}
<script type="text/javascript" src="tools/check_name.js"></script>
{% if config.recaptcha_enabled %}
{% set action = 'register' %}
{{ include('google_recaptcha.html.twig') }}
{% endif %}
<style>
#SuggestAccountNumber {
font-size: 7pt;

View File

@ -39,6 +39,9 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="?s
<td><input type="checkbox" id="remember_me" name="remember_me" value="true" />
<label for="remember_me"> Remember me</label></td>
</tr>
{% if config.recaptcha_enabled %}
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" />
{% endif %}
{% if error is not null %}
<tr><td></td><td><span class="FormFieldError">{{ error }}</span></td></tr>
{% endif %}
@ -74,3 +77,7 @@ Please enter your account {{ account|lower }} and your password.<br/><a href="?s
</td>
</tr>
</table>
{% if config.recaptcha_enabled %}
{% set action = 'login' %}
{{ include('google_recaptcha.html.twig') }}
{% endif %}

View File

@ -0,0 +1,11 @@
<script>
$(document).ready(function() {
grecaptcha.ready(function() {
grecaptcha.execute('{{ config.recaptcha_site_key }}', {action: '{{ action }}'}).then(function(token) {
if (token) {
document.getElementById('g-recaptcha-response').value = token;
}
});
});
});
</script>

View File

@ -17,5 +17,5 @@
</div>
</noscript>
{% if config.recaptcha_enabled %}
<script src="https://www.google.com/recaptcha/api.js"></script>
{% endif %}
<script src="https://www.google.com/recaptcha/api.js?render={{ config.recaptcha_site_key }}"></script>
{% endif %}

View File

@ -47,6 +47,9 @@
<td><input type="checkbox" id="remember_me" name="remember_me" value="true" />
<label for="remember_me"> Remember me</label></td>
</tr>
{% if config.recaptcha_enabled %}
<input type="hidden" name="g-recaptcha-response" id="g-recaptcha-response" />
{% endif %}
</table>
<div style="float: right; font-size: 1px;" >
<input type="hidden" name="page" value="overview" >
@ -144,3 +147,7 @@
</tr>
</table>
</div>
{% if config.recaptcha_enabled %}
{% set action = 'login' %}
{{ include('google_recaptcha.html.twig') }}
{% endif %}